by flowing-abyss
Provides AI assistants with instant, citation‑rich access to the contents of an Obsidian vault by building a local SQLite index that combines BM25 full‑text, trigram fuzzy matching, and vector similarity.
Enables any MCP‑compatible AI assistant to query a personal Obsidian vault without leaving the local machine. Notes are indexed into SQLite with FTS5 and sqlite-vec; queries are answered using a hybrid of traditional BM25, fuzzy title/alias matching, and semantic embeddings, finally merged with Reciprocal Rank Fusion (RRF) and normalized to a 0‑1 relevance score.
npm install -g obsidian-hybrid-search # or
npx obsidian-hybrid-search
export OBSIDIAN_VAULT_PATH="/path/to/your/vault"
The CLI can also auto‑detect the vault when run inside the vault directory.obsidian-hybrid-search reindex # builds .obsidian-hybrid-search.db
obsidian-hybrid-search "knowledge graph" # hybrid (default)
obsidian-hybrid-search "knowledge graph" --mode semantic
obsidian-hybrid-search "knowledge graph" --mode title
obsidian-hybrid-search "knowledge graph" --mode fulltext
Use --path to find notes similar to a given file, and add --related to traverse the wikilink graph..mcp.json (or equivalent) to expose the four tools (search, read, reindex, status):
{
"mcpServers": {
"obsidian-hybrid-search": {
"command": "npx",
"args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
"env": { "OBSIDIAN_VAULT_PATH": "/path/to/your/vault" }
}
}
}
aliases: are indexed and boosted.--related explores outgoing, backlinks, or both at configurable depth.bge-reranker-v2-m3 for higher precision.@huggingface/transformers (no API key) or remote OpenAI‑compatible APIs.Q: Do I need an internet connection?
A: No. The default embedding model (Xenova/multilingual-e5-small) runs locally. Remote APIs are optional.
Q: How large is the model download? A: Approximately 117 MB on first run; the reranker adds ~570 MB if used.
Q: Can I limit which notes are indexed?
A: Yes. Use the OBSIDIAN_IGNORE_PATTERNS environment variable or configure ignore patterns in the database (e.g., .obsidian/**, templates/**, *.canvas).
Q: What languages are supported? A: The default multilingual model covers 100+ languages, including English, Russian, Chinese, Japanese, etc.
Q: How does the server handle multiple concurrent queries? A: The MCP server is stateless; each tool call runs a fresh search against the SQLite index, which is fast (≈500 ms for typical vaults).
Q: Is the index updated automatically?
A: A file watcher (chokidar) increments the index in real‑time; you can also trigger a full reindex with obsidian-hybrid-search reindex --force.
An MCP server and CLI tool that makes your Obsidian vault queryable by AI assistants. Indexes notes into SQLite with FTS5 full-text search, trigram fuzzy matching, and sqlite-vec vector similarity — results are merged with Reciprocal Rank Fusion (RRF) and scored 0–1.
Once connected, any MCP-compatible AI assistant can answer questions grounded in your actual notes: finding knowledge by meaning, exact phrase, or title; traversing the wikilink graph; filtering by tag or folder; always citing the source note. No guessing from training data, no manual copy-paste.
No external services required. A bundled @huggingface/transformers model handles embeddings locally by default. Any OpenAI-compatible API (OpenRouter, Ollama, LM Studio) works as a drop-in replacement.
Evaluated on the Obsidian Help vault (171 notes, 58 queries, local model):
| obsidian-hybrid-search | qmd | |
|---|---|---|
| nDCG@5 | 0.736 | 0.659 |
| MRR | 0.771 | 0.665 |
| Hit@1 | 0.690 | 0.500 |
| Avg query time | 571 ms | 754 ms |
| Model download | ~117 MB | ~2.2 GB |
obsidian-hybrid-search uses Xenova/multilingual-e5-small (no rerank). qmd uses LLM query expansion + reranking. Full benchmark →
aliases: in frontmatter are indexed and searchable by any alias; alias matches are boosted in BM25 (weight 5×) and fuzzy title scoringhybrid, semantic, fulltext, title (for text queries)--path to find semantically related notes (always semantic, uses title + content)--path --related shows linked notes at configurable depth; filter by --direction outgoing|backlinks|both-notes/dev/)-category/cs)--snippet-length sets the context window; empty snippets always fall back to note content--extended adds a TAGS/ALIASES column to the CLI table showing frontmatter tags (#tag) and aliasesohs "q1" "q2" or queries[] in MCP); results are merged via RRF — a note that ranks well in any one query floats to the top; useful when the note may use different vocabulary than the query--rerank re-scores results with bge-reranker-v2-m3 (ONNX int8, ~570 MB download once); improves precision for conceptual and multilingual queries; applied after multi-query merge@huggingface/transformers (no API key required); default model: Xenova/multilingual-e5-small, 100+ languagesread fetches one or more notes by vault-relative path; returns full content with title, aliases, tags, links, and backlinks; on path miss returns top-3 fuzzy suggestionsnpm install -g obsidian-hybrid-search
# or run directly without installing:
npx obsidian-hybrid-search
Option A — recommended: set OBSIDIAN_VAULT_PATH once in your shell profile.
This lets you run the tool from any directory. Add to ~/.zshrc or ~/.bashrc:
export OBSIDIAN_VAULT_PATH="/path/to/your/vault"
Then reload (source ~/.zshrc) and index your vault once:
obsidian-hybrid-search reindex
After that you can search from any directory:
obsidian-hybrid-search "zettelkasten"
Option B — no env var: run from inside your vault.
The tool detects the vault root by looking for the .obsidian/ folder, walking up from the current directory. cd into your vault (or any subfolder) and run:
cd /path/to/your/vault
obsidian-hybrid-search reindex # detects vault root, creates DB, indexes everything
obsidian-hybrid-search "zettelkasten"
Commands work from any directory inside the vault tree. From outside the vault (e.g. via shell aliases called from ~), use Option A or pass --db /path/to/vault/.obsidian-hybrid-search.db explicitly.
Optional: remote embedding API instead of local model.
By default the local Xenova/multilingual-e5-small model is used — works offline, no API key needed. Downloads ~117 MB on first run. Supports 100+ languages including Russian, Chinese, Japanese, and more.
To use a remote API instead, add to your shell profile:
export OPENAI_API_KEY="sk-..."
# Default API base is https://api.openai.com/v1 — override for other providers:
# export OPENAI_BASE_URL="https://openrouter.ai/api/v1" # OpenRouter
# export OPENAI_BASE_URL="http://localhost:11434/v1" # Ollama (no key needed)
# export OPENAI_BASE_URL="http://localhost:1234/v1" # LM Studio (no key needed)
# Optional: override the embedding model (default: text-embedding-3-small)
# export OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
| Scenario | How | Modes |
|---|---|---|
| Text query | obsidian-hybrid-search "some topic" |
hybrid (default), semantic, fulltext, title |
| Similar notes | obsidian-hybrid-search --path notes/pkm/zettelkasten.md |
Always semantic (title + content) |
| Graph traversal | obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related |
Links & backlinks via BFS |
--mode only affects text queries. When --path is given, the search is always semantic regardless of --mode.
# Hybrid search (default)
obsidian-hybrid-search "zettelkasten atomic notes"
# Fulltext BM25 search
obsidian-hybrid-search "permanent notes" --mode fulltext
# Fuzzy title search (fast, typo-tolerant)
obsidian-hybrid-search "zettleksten" --mode title
# Semantic / vector search
obsidian-hybrid-search "how to build a knowledge graph" --mode semantic
# Limit results and set a score threshold
obsidian-hybrid-search "productivity systems" --limit 5 --threshold 0.3
# Restrict to a subfolder
obsidian-hybrid-search "daily review" --scope notes/periodic/
obsidian-hybrid-search "daily review" --folder notes/periodic/ # alias for --scope
# Restrict to multiple subfolders (AND)
obsidian-hybrid-search "productivity" --scope notes/pkm/ --scope notes/2024/
# Exclude a subfolder
obsidian-hybrid-search "programming" --scope notes/ --scope -notes/archive/
# Filter by tag
obsidian-hybrid-search "productivity" --tag pkm
obsidian-hybrid-search "machine learning" --tag note/basic/primary
# Filter by multiple tags (AND include, exclude with -)
obsidian-hybrid-search "learning" --tag pkm --tag work
# Filter by frontmatter / properties (exact match, case-insensitive)
obsidian-hybrid-search "notes" --frontmatter status:todo
obsidian-hybrid-search "notes" --prop priority:high # --prop is alias for --frontmatter
# Filter by multiple frontmatter fields (AND)
obsidian-hybrid-search "notes" --frontmatter status:todo --frontmatter priority:high
# Exclude by frontmatter value
obsidian-hybrid-search "notes" --frontmatter -status:done
# Filter-only mode: no query, just filters (returns all matching notes sorted by title)
obsidian-hybrid-search --frontmatter status:todo
obsidian-hybrid-search --folder notes/2024/
obsidian-hybrid-search --tag pkm
obsidian-hybrid-search --frontmatter status:done --tag archived
# Unlimited results in filter-only mode (default limit is 10)
obsidian-hybrid-search --folder notes/ --limit 0
# Find semantically similar notes
obsidian-hybrid-search --path notes/pkm/zettelkasten.md
# Graph traversal: show notes linked to/from this note
# Results show depth: -1/-2 = backlinks, 0 = source, +1/+2 = outgoing links
obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related
obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related --depth 2
# Only outgoing links (what this note references)
obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related --direction outgoing
# Only backlinks (who references this note)
obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related --direction backlinks
# Longer context around each link
obsidian-hybrid-search --path notes/pkm/zettelkasten.md --related --snippet-length 500
# Rerank results with a cross-encoder model (improves precision, ~1-3s extra latency)
# Downloads bge-reranker-v2-m3 ONNX (~570 MB) on first use, cached in ~/.cache/huggingface/
obsidian-hybrid-search "zettelkasten atomic notes" --rerank
# Show tags and aliases alongside results
obsidian-hybrid-search "zettelkasten" --extended
# JSON output (for scripting)
obsidian-hybrid-search "spaced repetition" --json
# Open results in Obsidian (each in a new tab)
obsidian-hybrid-search "zettelkasten" --open
# Reindex the vault
obsidian-hybrid-search reindex
# Force full reindex
obsidian-hybrid-search reindex --force
# Reindex a single file
obsidian-hybrid-search reindex notes/pkm/zettelkasten.md
# Show indexing status
obsidian-hybrid-search status
# Read a note by path (outputs raw content, like cat)
obsidian-hybrid-search read notes/pkm/zettelkasten.md
# Read multiple notes (separator between each)
obsidian-hybrid-search read notes/pkm/zettelkasten.md notes/pkm/evergreen-notes.md
# Cap content length
obsidian-hybrid-search read notes/pkm/zettelkasten.md --snippet-length 2000
# Structured output with all metadata
obsidian-hybrid-search read notes/pkm/zettelkasten.md --json
Add to your ~/.zshrc or ~/.bashrc for quick access:
alias ohs='obsidian-hybrid-search'
alias ohss='obsidian-hybrid-search --mode semantic'
alias ohst='obsidian-hybrid-search --mode title'
alias ohsf='obsidian-hybrid-search --mode fulltext'
alias ohsr='obsidian-hybrid-search read'
alias ohsi='obsidian-hybrid-search reindex'
alias ohsst='obsidian-hybrid-search status'
Then reload (source ~/.zshrc) and use:
ohs "zettelkasten" # hybrid search
ohss "how to build a knowledge graph" # semantic
ohst "zettelkasten" # fuzzy title (typo-tolerant)
ohsf "permanent notes" # fulltext BM25
ohsr "notes/pkm/zettelkasten.md" # read note by path
ohsi # reindex vault
ohsst # show status
Hybrid search returns a table with scores and snippets. Scores are color-coded by relevance:
| Score | Color | Meaning |
|---|---|---|
| 0.8 – 1.0 | green | Highly relevant |
| 0.5 – 0.8 | yellow | Moderately relevant |
| 0.2 – 0.5 | plain | Somewhat relevant |
| 0.0 – 0.2 | dim | Low relevance |
┌───────┬───────────────────────────────┬────────────────────────────────────────────┐
│ SCORE │ PATH │ SNIPPET │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│ 0.98 │ notes/pkm/zettelkasten.md │ A note-taking method developed by Niklas │
│ │ │ Luhmann. Each note contains one atomic... │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│ 0.72 │ notes/pkm/evergreen-notes.md │ Evergreen notes are written to evolve over │
│ │ │ time. Unlike fleeting notes, they are... │
└───────┴───────────────────────────────┴────────────────────────────────────────────┘
With --extended, a TAGS/ALIASES column is added. Tags are prefixed with #, aliases are shown as-is:
┌───────┬───────────────────────────────┬──────────────────┬──────────────────────────────┐
│ SCORE │ PATH │ TAGS/ALIASES │ SNIPPET │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│ 0.98 │ notes/pkm/zettelkasten.md │ #pkm │ A note-taking method... │
│ │ │ ЗК │ │
│ │ │ slip-box │ │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│ 0.72 │ notes/pkm/evergreen-notes.md │ #pkm │ Evergreen notes are written │
│ │ │ #writing │ to evolve over time... │
└───────┴───────────────────────────────┴──────────────────┴──────────────────────────────┘
Title mode omits the snippet column automatically.
Most AI assistants operate without access to your personal knowledge — they can only work with what you paste into the conversation. Adding this server gives any MCP-compatible assistant a persistent, searchable index of your entire vault. It becomes a tool call, not a copy-paste session: the assistant queries your notes the same way it calls any other tool, gets ranked results with snippets and links, and can navigate your knowledge graph on request.
Add to your MCP config (.mcp.json, claude_desktop_config.json, or equivalent for your client).
Uses the built-in Xenova/multilingual-e5-small model — works fully offline, supports 100+ languages. Downloads ~117 MB on first run.
{
"mcpServers": {
"obsidian-hybrid-search": {
"command": "npx",
"args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/vault"
}
}
}
}
{
"mcpServers": {
"obsidian-hybrid-search": {
"command": "npx",
"args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/vault",
"OBSIDIAN_IGNORE_PATTERNS": ".obsidian/**,templates/**,*.canvas",
"OPENAI_API_KEY": "sk-or-v1-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1",
"OPENAI_EMBEDDING_MODEL": "openai/text-embedding-3-small"
}
}
}
}
Note: On first run,
npxwill install the package automatically. Ignore patterns are persisted in the database and restored on every subsequent startup even if the env var is missing.
The server exposes four tools:
| Tool | Description |
|---|---|
search |
Search the vault. Use query for text search (mode: hybrid/semantic/fulltext/title) or path for semantic similarity. Combine path with related: true for graph traversal. Pass queries[] for multi-query fan-out (parallel search, RRF merge). Supports scope, tag, limit, threshold, depth, direction, snippet_length, rerank |
read |
Fetch one or more notes by vault-relative path. Returns full content, title, aliases, tags, links, and backlinks. On path miss: returns found: false with top-3 fuzzy suggestions. Accepts a single path or an array. Use snippet_length to cap content size |
reindex |
Reindex the vault or a specific file |
status |
Show total notes, indexed count, last indexed time |
| Environment variable | Default | Description |
|---|---|---|
OBSIDIAN_VAULT_PATH |
Required for MCP; CLI auto-detects | Absolute path to your vault |
OBSIDIAN_IGNORE_PATTERNS |
.obsidian/**,templates/**,*.canvas |
Comma-separated ignore patterns |
OPENAI_API_KEY |
— | API key; omit to use local model embeddings or keyless servers (Ollama, LM Studio) |
OPENAI_BASE_URL |
https://api.openai.com/v1 |
API base URL |
OPENAI_EMBEDDING_MODEL |
text-embedding-3-small |
Embedding model name |
folder/** — ignore a directory and all its contents*.canvas — ignore by extensionexact/path.md — ignore a specific fileThe ignore configuration is persisted in the database, so it is restored automatically even if the environment variable is missing on restart.
sqlite-vec.[[note]]) are resolved to note paths and stored; every search result includes links and backlinks arrays.chokidar watches for file changes and incrementally re-indexes in the background.npm install
npm test # run test suite
npm run build # compile TypeScript
Tests use fake embeddings (no API key required) and run against a temporary vault. All tests cover chunking, BM25 scoring, fuzzy search, links/backlinks, tag filtering, scope filtering, related-mode traversal, direction/score logic, snippet fallback, and ignore pattern matching.
MIT
Please log in to share your review and rating for this MCP.
Explore related MCPs that share similar capabilities and solve comparable challenges
by exa-labs
Provides real-time web search capabilities to AI assistants via a Model Context Protocol server, enabling safe and controlled access to the Exa AI Search API.
by perplexityai
Enables Claude and other MCP‑compatible applications to perform real‑time web searches through the Perplexity (Sonar) API without leaving the MCP ecosystem.
by MicrosoftDocs
Provides semantic search and fetch capabilities for Microsoft official documentation, returning content in markdown format via a lightweight streamable HTTP transport for AI agents and development tools.
by elastic
Enables natural‑language interaction with Elasticsearch indices via the Model Context Protocol, exposing tools for listing indices, fetching mappings, performing searches, running ES|QL queries, and retrieving shard information.
by graphlit
Enables integration between MCP clients and the Graphlit platform, providing ingestion, extraction, retrieval, and RAG capabilities across a wide range of data sources and connectors.
by ihor-sokoliuk
Provides web search capabilities via the SearXNG API, exposing them through an MCP server for seamless integration with AI agents and tools.
by mamertofabian
Fast cross‑platform file searching leveraging the Everything SDK on Windows, Spotlight on macOS, and locate/plocate on Linux.
by spences10
Provides unified access to multiple search engines, AI response tools, and content processing services through a single Model Context Protocol server.
by cr7258
Provides Elasticsearch and OpenSearch interaction via Model Context Protocol, enabling document search, index management, cluster monitoring, and alias operations.