Skip to main content

MCP server for semantic search and file management over Obsidian vaults using Qdrant and local embeddings

Project description

obsidian-qdrant-search

Obsidian Qdrant Search

Version PyPI Python License Qdrant MCP Obsidian

MCP server for semantic search and file management over an Obsidian vault. Uses Qdrant as vector store and FastEmbed for local embeddings. Provides a complete set of tools for AI agents to read, write, search, and manage vault content โ€” no external Obsidian plugins required.


Table of Contents

Section Description
? Why? The problem this solves
โœจ Features Full feature list
โšก Quick Start Installation and setup
๐Ÿ“– LLM Wiki Pattern Karpathy-inspired knowledge base model
๐Ÿค– Agent Skills Skill and agent for Claude Code
๐Ÿ”ง MCP Tools All 27 tools โ€” Search, Read, Write, Discover, Graph, Batch, Log, Health, Maintenance
๐Ÿ’ป CLI Commands Command-line interface for any agent
๐Ÿ—๏ธ Architecture How it works under the hood
๐Ÿ“ Project Structure File layout

Why?

Standard text search in Obsidian (and MCP tools like mcp-obsidian) is keyword-based โ€” it only finds exact matches. This means:

  • Searching for "API logs" won't find a section titled "Execution tracking endpoints"
  • Searching for "how does authentication work" returns nothing unless those exact words appear
  • Typos, synonyms, and rephrased concepts are invisible to keyword search

obsidian-qdrant-search uses vector embeddings to understand the meaning of your query and match it against the meaning of your documentation. It finds relevant results even when the wording is completely different.

Additionally, it provides full CRUD file operations directly on the vault filesystem, so AI agents can read, create, update, and manage notes without relying on external Obsidian community plugins like Local Rest API.

Features

  • LLM Wiki pattern โ€” Karpathy-inspired three-layer architecture for persistent, compounding knowledge bases
  • Semantic search โ€” find docs by meaning, not just keywords
  • Full file management โ€” read, create, update, append, patch, and delete vault files
  • Targeted patching โ€” modify specific sections by heading or frontmatter field
  • Text search โ€” case-insensitive keyword search across all markdown files
  • Markdown-aware chunking โ€” tables and code blocks are never split mid-block
  • Frontmatter filters โ€” narrow results by project, document type, or tags
  • Context expansion โ€” fetch adjacent chunks around a search result
  • Wikilink graph โ€” navigate backlinks, outgoing links, find broken links and orphan files
  • Vault health checks โ€” comprehensive lint with broken links, orphans, stale docs, missing metadata
  • Operation log โ€” chronological record of ingest, query, lint, and maintenance actions
  • Vault migration โ€” non-destructive upgrade of existing vaults to the LLM Wiki conventions
  • Multi-agent CLI โ€” 7 CLI commands with --json output for any agent (Codex, OpenCode, etc.)
  • Vault map โ€” visualize directory structure with file counts
  • Frontmatter schema discovery โ€” see all fields, types, and usage across the vault
  • Tag discovery โ€” list all tags (frontmatter + inline) with occurrence counts
  • Recent changes โ€” track recently modified files
  • Batch operations โ€” update frontmatter or rename tags across multiple files at once
  • Incremental indexing โ€” only re-embeds changed files
  • Auto-reindex on write โ€” modified files are automatically re-indexed (best-effort)
  • Auto-start Qdrant โ€” Docker container is managed automatically
  • Local embeddings โ€” no API keys needed, runs entirely on your machine
  • Path security โ€” all file operations are validated to prevent access outside the vault

Prerequisites

  • Python 3.11+
  • Docker (for Qdrant)
  • uv (recommended) or pip

Quick start

1. MCP Configuration

Add to your .mcp.json (project root or Claude Code settings):

{
  "mcpServers": {
    "obsidian-qdrant-search": {
      "command": "uvx",
      "args": ["obsidian-qdrant-search"],
      "env": {
        "VAULT_PATH": "/absolute/path/to/your/vault"
      }
    }
  }
}

Qdrant is started automatically via Docker when needed. If a qdrant container already exists, it will be reused.

2. Initial indexing

VAULT_PATH=/path/to/your/vault uvx --from obsidian-qdrant-search vault-index --full

LLM Wiki Pattern

Inspired by Karpathy's LLM Wiki, this project supports a three-layer architecture for building persistent, compounding knowledge bases maintained by LLMs:

Layer Directory Purpose
Raw sources raw/ Immutable source documents โ€” articles, papers, transcripts, web clips. The LLM reads from these but never modifies them.
Wiki wiki/ LLM-maintained pages โ€” entities, concepts, summaries, syntheses. The LLM owns this layer entirely.
Schema CLAUDE.md / AGENTS.md Conventions that tell the LLM how the wiki is structured and what workflows to follow.

Operations

  • Ingest โ€” Drop a new source into raw/, the LLM reads it, creates/updates wiki pages, adds wikilinks, and logs the operation
  • Query โ€” Search the wiki, synthesize answers, and optionally file valuable results back as new wiki pages
  • Lint โ€” Run lint_vault for a comprehensive health check (broken links, orphans, stale docs, missing metadata)

Migration from older versions

Existing vaults can be upgraded with the migration tool. From Claude Code (or any MCP client), just ask in natural language:

"migrate my vault to the LLM Wiki pattern"

Claude Code will call the migrate_vault MCP tool automatically โ€” first in preview mode, then ask for confirmation before applying.

From the command line (for other agents or manual use):

# Preview what would change
VAULT_PATH=/path/to/vault uvx --from obsidian-qdrant-search vault-search-migrate

# Apply changes (creates raw/ and wiki/ dirs, adds missing frontmatter, initializes log)
VAULT_PATH=/path/to/vault uvx --from obsidian-qdrant-search vault-search-migrate --apply

The migration is non-destructive (never moves or deletes files) and idempotent (safe to run multiple times). See CLAUDE.md for the full document structure rules and conventions.

Agent Skills

This repo includes Claude Code skills and agents in .claude/. Copy the .claude/ directory into your project to make them available. Claude will automatically discover and use them based on context.

/vault-search โ€” Skill (.claude/skills/vault-search/)

Guides the agent through semantic search, text search, file reading, and knowledge graph navigation. Claude can invoke it automatically or you can use it as a slash command:

/vault-search how does authentication work

doc-manager โ€” Agent (.claude/agents/)

An autonomous documentation agent that creates, updates, organizes, and maintains vault documentation. Includes templates, conventions, health check workflows, and restructuring procedures. Claude dispatches it as a subagent when documentation tasks are needed.

/doc-manager document the new authentication module in projects/core
/doc-manager run a vault health check
/doc-manager create an ADR for switching to PostgreSQL

Environment variables

Variable Default Description
VAULT_PATH Current working directory Path to the Obsidian vault directory
QDRANT_URL http://localhost:6333 Qdrant server URL
COLLECTION_NAME vault_docs Qdrant collection name
VAULT_LOG_FILE _log.md Operation log filename

MCP Tools

Search

search_vault

Semantic search over the vault documentation.

Parameter Type Default Description
query string required Natural language search query
project string null Filter by project name (e.g. "core")
doc_type string null Filter by document type (e.g. "api-contract", "service-layer")
tag string null Filter by frontmatter tag (e.g. "kubernetes", "database")
top_k int 5 Number of results to return

simple_search

Case-insensitive text search across all markdown files.

Parameter Type Default Description
query string required Text to search for
context_length int 100 Characters of context around each match

get_chunk_context

Expand context around a search result by fetching adjacent chunks.

Parameter Type Default Description
file_path string required The file_path from a search result
chunk_index int required The chunk_index from a search result
window int 1 Number of chunks before/after to include

Read

get_file_contents

Read the raw content of a vault file.

Parameter Type Default Description
filepath string required Path relative to vault root

get_file_metadata

Get frontmatter metadata, tags, and file stats (size, dates).

Parameter Type Default Description
filepath string required Path relative to vault root

list_files_in_dir

List files and subdirectories in a vault directory (non-recursive).

Parameter Type Default Description
dirpath string "" Relative directory path (empty for root)

list_files_in_vault

List all top-level files and directories in the vault root.

Write

create_or_update_file

Create a new file or overwrite an existing one. Parent directories are created automatically.

Parameter Type Default Description
filepath string required Path relative to vault root
content string required Full file content

append_content

Append content to a file (creates the file if it doesn't exist).

Parameter Type Default Description
filepath string required Path relative to vault root
content string required Content to append

patch_content

Targeted modification of a specific section by heading or frontmatter field.

Parameter Type Default Description
filepath string required Path relative to vault root
operation string required "append", "prepend", or "replace"
target_type string required "heading" or "frontmatter"
target string required Heading text (e.g. "Setup" or "Setup::Installation") or frontmatter field name
content string required Content to insert or replace with

delete_file

Delete a file from the vault.

Parameter Type Default Description
filepath string required Path relative to vault root
confirm bool false Must be true to actually delete (safety guard)

Discover

list_projects

Lists all indexed projects with file and chunk counts.

list_tags

Lists all tags (frontmatter + inline #tag) with occurrence counts across the vault.

get_recent_changes

Returns recently modified markdown files sorted by modification date.

Parameter Type Default Description
days int 14 Only include files modified within this many days
limit int 10 Maximum number of results

get_vault_map

Get the vault's directory structure as a tree with file counts.

Parameter Type Default Description
max_depth int 3 Maximum directory depth to show

get_frontmatter_schema

Discover all frontmatter fields used across the vault with types, frequency, and examples.

Graph

get_backlinks

Find all files that contain wikilinks pointing to the given file.

Parameter Type Default Description
filepath string required Relative path to the target file

get_outgoing_links

List all files that the given file links to via wikilinks.

Parameter Type Default Description
filepath string required Relative path to the source file

find_broken_links

Find all wikilinks in the vault that point to non-existent files.

find_orphan_files

Find files that have no incoming wikilinks from other files.

Batch

batch_update_frontmatter

Update a frontmatter field across multiple files matching a filter.

Parameter Type Default Description
filter_type string required "project", "tag", or "glob"
filter_value string required Filter value (project name, tag, or glob pattern)
field string required Frontmatter field to update
value string required Value to set/append/remove (YAML parsed)
operation string "set" "set", "append", or "remove"
confirm bool false Set to true to apply (default returns preview)

batch_rename_tag

Rename a tag across all vault files (both frontmatter and inline #tags).

Parameter Type Default Description
old_tag string required Tag to rename (without #)
new_tag string required New tag name (without #)
confirm bool false Set to true to apply (default returns preview)

Log

log_operation

Append a structured entry to the vault operation log.

Parameter Type Default Description
operation_type string required "ingest", "query", "lint", or "maintenance"
title string required Short title for the entry
summary string "" Optional description
pages_touched list [] Optional list of modified file paths
source string "" Optional source file path (for ingest)

get_operation_log

Read recent entries from the operation log.

Parameter Type Default Description
last_n int 20 Number of recent entries to return
filter_type string "" Filter by operation type (e.g. "ingest")

Health

lint_vault

Comprehensive vault health check. Reports broken wikilinks (critical), orphan files (warning), missing frontmatter (warning), stale documents (info), stub documents (info), and isolated pages (info).

Parameter Type Default Description
stale_days int 90 Flag files not modified within this many days

Maintenance

reindex_vault

Re-indexes the vault into Qdrant. After upgrading, run with full=true to rebuild the index.

Parameter Type Default Description
full bool false If true, drops and recreates the collection

migrate_vault

Migrate an existing vault to the LLM Wiki pattern. Creates raw/ and wiki/ directories, adds missing frontmatter fields with sensible defaults, and initializes the operation log. Non-destructive and idempotent.

Parameter Type Default Description
confirm bool false Set to true to apply (default returns preview)

CLI Commands

MCP Server & Indexing

Command Description
obsidian-qdrant-search Start the MCP server (stdio transport)
vault-index [--full] Run indexing (incremental by default, --full drops and recreates)

Multi-Agent CLI

All commands support --json for structured output that any agent can parse.

Command Description
vault-search-search "<query>" [--project X] [--top-k 5] [--json] Semantic search
vault-search-read <filepath> Read a vault file
vault-search-write <filepath> --content "..." Create or update a file
vault-search-lint [--stale-days 90] [--json] Vault health check
vault-search-log <type> "<title>" [--summary "..."] [--source "..."] Log an operation
vault-search-log --read [--last 20] [--filter <type>] [--json] Read log entries
vault-search-map [--depth 3] [--json] Show vault structure
vault-search-migrate [--apply] [--json] Migrate vault to LLM Wiki pattern

These CLI commands make the vault accessible to any agent that can shell out (Codex, OpenCode, etc.), not just MCP-aware clients. See AGENTS.md for the full agent-oriented reference.

Architecture

Obsidian vault (.md files)
    |
    v
indexer โ”€โ”€ chunk by H2/H3 sections โ”€โ”€> Qdrant (vector DB)
    |         preserves tables              |
    |         preserves code blocks         |
    v                                       v
fastembed (BAAI/bge-small-en-v1.5)    server (MCP stdio)
    local embeddings, 384 dim            search / CRUD / reindex

Chunking strategy: Documents are split by ## headings, then ### if needed. Tables and fenced code blocks are never split mid-block. Large sections fall back to a block-aware sliding window with overlap.

Incremental indexing: Files are tracked by SHA-256 hash. Only changed files are re-embedded on reindex_vault(). Deleted files are automatically cleaned up.

Auto-reindex on write: When files are created, updated, or deleted via MCP tools, the search index is automatically updated for the affected file. This is best-effort โ€” if Qdrant is unavailable, the write still succeeds.

Project structure

obsidian-qdrant-search/
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ CHANGELOG.md
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ CLAUDE.md              # schema layer for Claude Code (auto-loaded)
โ”œโ”€โ”€ AGENTS.md              # schema layer for other agents (Codex, OpenCode)
โ”œโ”€โ”€ .claude/
โ”‚   โ”œโ”€โ”€ skills/
โ”‚   โ”‚   โ””โ”€โ”€ vault-search/SKILL.md   # /vault-search slash command
โ”‚   โ””โ”€โ”€ agents/
โ”‚       โ””โ”€โ”€ doc-manager.md           # documentation manager agent
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_path_utils.py
โ”‚   โ”œโ”€โ”€ test_vault_ops.py
โ”‚   โ”œโ”€โ”€ test_indexer.py
โ”‚   โ”œโ”€โ”€ test_log.py
โ”‚   โ”œโ”€โ”€ test_lint.py
โ”‚   โ””โ”€โ”€ test_migrate.py
โ””โ”€โ”€ src/
    โ””โ”€โ”€ vault_search/
        โ”œโ”€โ”€ __init__.py
        โ”œโ”€โ”€ __main__.py      # python -m vault_search
        โ”œโ”€โ”€ cli.py            # CLI entry points (index + 7 commands)
        โ”œโ”€โ”€ config.py         # env-based configuration
        โ”œโ”€โ”€ path_utils.py     # path security & validation
        โ”œโ”€โ”€ vault_ops.py      # CRUD, batch, log, lint operations
        โ”œโ”€โ”€ migrate.py        # vault migration to LLM Wiki pattern
        โ”œโ”€โ”€ qdrant.py         # auto-start Qdrant Docker container
        โ”œโ”€โ”€ indexer.py        # markdown parsing, chunking, wikilinks, embedding
        โ””โ”€โ”€ server.py         # MCP server + 27 tools

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

obsidian_qdrant_search-0.4.1.tar.gz (882.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

obsidian_qdrant_search-0.4.1-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

File details

Details for the file obsidian_qdrant_search-0.4.1.tar.gz.

File metadata

  • Download URL: obsidian_qdrant_search-0.4.1.tar.gz
  • Upload date:
  • Size: 882.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.10","id":"questing","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for obsidian_qdrant_search-0.4.1.tar.gz
Algorithm Hash digest
SHA256 a30997e00b0d63c8b8546897c6b91285ad3dbc7260aa2695ad712e08b3c3dfa1
MD5 e1fbaa09ee06deb89e5e242bf5955fdc
BLAKE2b-256 9af1a396f6ff982044e93131cdb81b243b713f2ab6117f319b9e5a1a8ead0c38

See more details on using hashes here.

File details

Details for the file obsidian_qdrant_search-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: obsidian_qdrant_search-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 39.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.10","id":"questing","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for obsidian_qdrant_search-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0377a0fb5c7e5873c80efb34e6cf449505583cd8e4828a34d6912c22a14b3ff8
MD5 d83459184a03a0649bdae8b7f062aa0b
BLAKE2b-256 f7d883564229aee69afa9882865d781878a1c84a34781a3f7c15a352b534c7be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page