markdown-vault-mcp

CI codecov PyPI Python License Docker Docs llms.txt Ask DeepWiki Template

A generic markdown vault MCP server with FTS5 full-text search, semantic vector search, frontmatter-aware indexing, incremental reindexing, and non-markdown attachment support.

Documentation | Config wizard | PyPI | Docker

Point it at a directory of Markdown files (an Obsidian vault, a docs folder, a Zettelkasten, a PARA vault) and it exposes search, read, write, and edit tools over the Model Context Protocol.

Features

  • Full-text search — SQLite FTS5 with BM25 scoring, porter stemming
  • Semantic search — cosine similarity over embedding vectors (FastEmbed, Ollama, or OpenAI)
  • Hybrid search — Reciprocal Rank Fusion combining FTS5 and vector results
  • Diversity-aware ranking — each search result list caps a single document at 2 chunks (configurable), downweights chunks of long documents, and returns sentence-scale snippets — bounded LLM context cost per query, with full-section recovery via read(path, section=heading)
  • Adaptive heading-level chunking — long sections are recursively re-split at deeper heading levels (H1 → H6) until each chunk fits a configurable word budget, improving retrieval precision on synthesising essays without manual restructuring

Upgrading. As of this release, search returns query-relevant snippets in the content field by default (approximately 200 words). Pass snippet_words=0 to recover the prior full-chunk behaviour, or use read(path, section=heading) to fetch the full section after seeing a snippet. Documents are also re-chunked on next reindex to honour the adaptive MARKDOWN_VAULT_MCP_MAX_CHUNK_WORDS threshold (default 400).

  • Frontmatter-aware — indexes YAML frontmatter fields, supports required field enforcement
  • Incremental reindexing — hash-based change detection, only re-processes modified files; an automatic boot-time reconciliation pass picks up changes made while no server was running, and the vector index converges to the reconciled chunk set (embedding exactly the delta)
  • Write operations — create, edit, delete, rename documents, and move entire folder subtrees with automatic index updates
  • Folder conventions: per-folder _conventions.md files carry your authoring rules, such as "reference notes stay self-contained"; the server surfaces them to LLM clients at write time via the get_conventions tool and in write/edit results, without interpreting them
  • Attachment support — read, write, delete, and list non-markdown files (PDFs, images, etc.)
  • Git integration — optional auto-commit and push on every write via GIT_ASKPASS
  • OIDC authentication — optional token-based auth for HTTP deployments (Authelia, Keycloak, etc.)
  • MCP tools: 33 LLM-visible tools including search, read, write, edit, delete, rename, move_folder, git history, manual git sync, one-time transfer links, and admin operations; plus 6 app-only tools for MCP Apps clients
  • MCP resources — 9 resources exposing vault configuration, statistics, tags, folders, document outlines, similar notes, recent notes, and an interactive SPA
  • MCP prompts — 7 prompt templates including template-driven note creation

What you can do with it

With this server mounted in Claude, you can:

  • Capture a URL as a note. "Fetch , summarize as a Resource note under 3-Resources/, and link any existing notes on the topic." — Claude composes fetch + search + write.
  • Research a topic into your vault. "Research product security regulations, compare them, and create a set of interlinked notes — one per regulation, plus a map-of-content." — Claude composes web-search tools (client-side) + write with wikilinks. See the Research workflows guide for the full loop.
  • Distill today's thinking. "Summarize today's conversations into Inbox notes." — Claude.ai only; uses conversation_search + recent_chats + write. The para-capture-chats prompt is the one-click version.
  • Find missing links. Fire the propose-links prompt from the + menu — it scans recently-modified notes, proposes meaningful connections, and writes them on confirmation.
  • Split or merge captures. "Split this Inbox note into two." / "Merge this into <existing note> instead of duplicating." — Claude composes read + write + delete.

No external scheduler, no separate capture app — the vault sits behind your conversations and absorbs their output.

Installation

From PyPI

pip install markdown-vault-mcp

With optional dependencies:

pip install markdown-vault-mcp[mcp]            # FastMCP server
pip install markdown-vault-mcp[embeddings-api]  # Ollama/OpenAI embeddings via API
pip install markdown-vault-mcp[embeddings]      # FastEmbed local embeddings
pip install markdown-vault-mcp[all]             # MCP + FastEmbed + API embeddings

From source

git clone https://github.com/pvliesdonk/markdown-vault-mcp.git
cd markdown-vault-mcp
uv sync --all-extras --all-groups

Docker

docker pull ghcr.io/pvliesdonk/markdown-vault-mcp:latest

The Docker image uses [all] (MCP + FastEmbed + API embeddings). By default, semantic search works locally with FastEmbed and can switch to Ollama/OpenAI when configured. A compose.yml ships at the repo root as a starting point — copy .env.example to .env, edit, and docker compose up -d.

To attach a remote Python debugger (development only; the protocol is unauthenticated), see Remote debugging.

Linux packages (.deb / .rpm)

Download .deb or .rpm packages from the GitHub Releases page. Both install a hardened systemd unit; env configuration is sourced from /etc/markdown-vault-mcp/env (copy from the shipped /etc/markdown-vault-mcp/env.example). See the systemd deployment guide for details.

Claude Desktop (.mcpb bundle)

Download the .mcpb bundle from the GitHub Releases page. Double-click to install, or run:

mcpb install markdown-vault-mcp-<version>.mcpb

Claude Desktop opens a GUI wizard that prompts for required env vars — no manual JSON editing needed. See Step 0 of the Claude Desktop guide for details.

Claude Code plugin

/plugin marketplace add pvliesdonk/claude-plugins
/plugin install markdown-vault-mcp@pvliesdonk

Installs the MCP server and the vault-workflow skill. See the Claude Code plugin guide for details.

Quick Start

As a library

from pathlib import Path
from markdown_vault_mcp.vault import Vault

vault = Vault(source_dir=Path("/path/to/vault"))
vault.index.build_index()
results = vault.reader.search("query text", limit=10)

As an MCP server

export MARKDOWN_VAULT_MCP_SOURCE_DIR=/path/to/vault
markdown-vault-mcp serve

With Docker Compose

  1. Copy an example env file:

    cp examples/obsidian-readonly.env .env
    
  2. Edit .env to set MARKDOWN_VAULT_MCP_SOURCE_DIR to the absolute path of your vault on the host.

  3. Start the service:

    docker compose up -d
    
  4. Check the logs:

    docker compose logs -f markdown-vault-mcp
    

Example env files

File Description
examples/obsidian-readonly.env Obsidian vault, read-only, Ollama embeddings
examples/obsidian-readwrite.env Obsidian vault, read-write with git auto-commit
examples/obsidian-oidc.env Obsidian vault, read-only, OIDC authentication (Authelia)
examples/ifcraftcorpus.env Strict frontmatter enforcement, read-only corpus

For reverse proxy (Traefik) and deployment setup, see docs/deployment.md.

Server info

The server registers a built-in get_server_info tool (via fastmcp_pvl_core.register_server_info_tool) so operators can confirm the deployed version with a single MCP call. The response carries server_name, server_version, and core_version.

Configuration

All configuration is via environment variables with the MARKDOWN_VAULT_MCP_ prefix (except embedding provider settings, which use their own conventions).

Core

Variable Default Required Description
MARKDOWN_VAULT_MCP_SOURCE_DIR Yes Path to the markdown vault directory
MARKDOWN_VAULT_MCP_READ_ONLY true No Set to false to enable write operations
MARKDOWN_VAULT_MCP_INDEX_PATH in-memory No Path to the SQLite FTS5 index file; set for persistence across restarts
MARKDOWN_VAULT_MCP_EMBEDDINGS_PATH disabled No Path to the numpy embeddings file; required to enable semantic search
MARKDOWN_VAULT_MCP_STATE_PATH {SOURCE_DIR}/.markdown_vault_mcp/state.json No Path to the change-tracking state file
MARKDOWN_VAULT_MCP_INDEXED_FIELDS (none) No Comma-separated frontmatter fields to promote to the tag index for structured filtering. Changing it cold-rebuilds the index once on next startup (and, when SEARCHABLE_FIELDS is unset, also re-embeds the vault, since the searchable set inherits this value)
MARKDOWN_VAULT_MCP_REQUIRED_FIELDS No Comma-separated frontmatter fields required on every document; documents missing any are excluded from the index
MARKDOWN_VAULT_MCP_EXCLUDE No Comma-separated glob patterns to exclude from scanning (e.g. .obsidian/**,.trash/**)
MARKDOWN_VAULT_MCP_TITLE_FIELD title No Frontmatter field used as the document title (falls back to title, the first H1, then the filename). Changing it cold-rebuilds the index once on next startup
MARKDOWN_VAULT_MCP_SEARCHABLE_FIELDS defaults to INDEXED_FIELDS No Comma-separated frontmatter fields whose text values become keyword-searchable, and also enrich first-chunk embedding input (independent of EMBED_CONTEXT). Defaults to INDEXED_FIELDS when unset; set explicitly to diverge, or to none for no searchable fields at all. Setting or changing it cold-rebuilds the index and re-embeds the vault once on next startup
MARKDOWN_VAULT_MCP_TEMPLATES_FOLDER _templates No Relative folder path where note templates live (used by the create_from_template prompt)
MARKDOWN_VAULT_MCP_PROMPTS_FOLDER No Path to a directory of .md prompt files that extend or override built-in prompts (see User-defined prompts)
MARKDOWN_VAULT_MCP_CONVENTIONS_FILE _conventions.md No Filename of the per-folder conventions files surfaced to clients at write time (bare .md filename without glob characters; none disables). Convention files are excluded from the search index but stay readable. Existing notes matching the configured name are removed from the index on the next boot reconcile; set none to keep them indexed
MARKDOWN_VAULT_MCP_DRAIN_TIMEOUT_S 60 No Maximum seconds an index-querying read tool waits for the IndexWriter to drain when called with wait_for_pending_writes=True. On timeout the tool answers from the current index rather than raising and reports index_stale=True in the response's _meta.
MARKDOWN_VAULT_MCP_BUILD_TIMEOUT_S 60 No Maximum seconds a relational/FTS-backed tool or resource waits for the index to become queryable during a cold-start background build before raising IndexUnavailableError(reason="timeout"). Increase for very large vaults.

Server identity

Variable Default Description
MARKDOWN_VAULT_MCP_SERVER_NAME markdown-vault-mcp MCP server name shown to clients; useful for multi-instance setups
MARKDOWN_VAULT_MCP_INSTRUCTIONS (auto) System-level instructions injected into LLM context; defaults to a description that reflects read-only vs read-write state
MARKDOWN_VAULT_MCP_DISABLE_APPS_UI false Hide MCP-Apps UI tools (browse_vault, show_context) from the tool listing for clients that do not render MCP Apps panels (saves a few listing tokens)
MARKDOWN_VAULT_MCP_HTTP_PATH /mcp HTTP endpoint path for streamable HTTP transport (used by serve --transport http)
MARKDOWN_VAULT_MCP_KV_STORE_URL file:///data/state Unified key-value backend for HTTP session persistence (the events keyspace is namespaced inside the directory). file:///path (default) survives restarts; memory:// for dev (lost on restart). Preferred over EVENT_STORE_URL.
MARKDOWN_VAULT_MCP_EVENT_STORE_URL (unset) Legacy alias for KV_STORE_URL; honoured only when KV_STORE_URL is unset, and logs a one-shot deprecation warning. Prefer KV_STORE_URL.
MARKDOWN_VAULT_MCP_APP_DOMAIN (auto) Override the Claude app domain used for MCP Apps iframe sandboxing. Auto-computed from BASE_URL when not set.
FASTMCP_LOG_LEVEL INFO Log level for FastMCP internals (DEBUG, INFO, WARNING, ERROR). App loggers default to INFO. -v overrides both to DEBUG.
FASTMCP_ENABLE_RICH_LOGGING true Rich key=value text by default. Set to false for one-JSON-object-per-record output — recommended for production / log-aggregator deployments.

Search and embeddings

Variable Default Description
MARKDOWN_VAULT_MCP_EMBEDDING_PROVIDER auto-detect Embedding provider: openai, ollama, or fastembed
OLLAMA_HOST http://localhost:11434 Ollama server URL (not MARKDOWN_VAULT_MCP_-prefixed)
OPENAI_API_KEY OpenAI API key for the OpenAI embedding provider (not MARKDOWN_VAULT_MCP_-prefixed)
MARKDOWN_VAULT_MCP_OPENAI_BASE_URL / OPENAI_BASE_URL https://api.openai.com/v1 OpenAI-compatible API base URL for embeddings
MARKDOWN_VAULT_MCP_OPENAI_EMBEDDING_MODEL / OPENAI_EMBEDDING_MODEL text-embedding-3-small OpenAI-compatible embedding model name
MARKDOWN_VAULT_MCP_OLLAMA_MODEL nomic-embed-text Ollama embedding model name
MARKDOWN_VAULT_MCP_OLLAMA_CPU_ONLY false Force Ollama to use CPU only
MARKDOWN_VAULT_MCP_FASTEMBED_MODEL BAAI/bge-small-en-v1.5 FastEmbed model name
MARKDOWN_VAULT_MCP_FASTEMBED_CACHE_DIR FastEmbed default FastEmbed model cache directory (in Docker, stored under /data/state/fastembed)
MARKDOWN_VAULT_MCP_EMBED_CONTEXT false Enrich embedding input with the note title, chunk heading, and (first chunk) searchable-field values. Flipping it re-embeds the whole vault once on next startup
MARKDOWN_VAULT_MCP_MAX_CHUNK_WORDS 400 Word cap per chunk; the adaptive chunker splits at deeper heading levels, then paragraph/word boundaries, to respect it. Match it to the embedding model's context. A non-zero CHUNK_OVERLAP_WORDS can push an overlapped fragment past this cap. A reindex applies a new value.
MARKDOWN_VAULT_MCP_MAX_CHUNK_CHARS (bounded default) Character cap the chunker enforces alongside MAX_CHUNK_WORDS to bound token-dense chunks (CJK, code, tables) that fit the word cap yet exceed the model's token context. Unset → min(1500, round(context_length × 2.8)), so the default stays retrieval-sized and memory-safe regardless of model context. The default BAAI/bge-small-en-v1.5 (512 tokens) derives ~1434 chars, below the ceiling and unchanged; a longer-context model (context above ~536 tokens) is capped at 1500; an unknown context falls back to 1500. Set a positive value to force an exact cap. Set -1 to scale with the model's full context with no ceiling, or 1500 when the context is unknown, which can OOM the fastembed/ONNX path on a long-context model. A reindex applies a new value.
MARKDOWN_VAULT_MCP_CHUNK_OVERLAP_WORDS 40 Words of overlap between adjacent budget-split fragments of the same heading section (0 disables). Applies to new/re-indexed notes; run reindex to apply to an existing vault.
MARKDOWN_VAULT_MCP_CHUNKS_PER_FILE 2 Maximum chunks returned per document in search results.
MARKDOWN_VAULT_MCP_SNIPPET_WORDS 200 Width of the snippet window (words) in search results; 0 returns full chunk content.
MARKDOWN_VAULT_MCP_LENGTH_DOWNWEIGHT_ALPHA 0.25 Down-weights longer chunks in ranking (score / (1 + alpha · log(chunk_count))).
MARKDOWN_VAULT_MCP_FOLDER_WEIGHTS none Folder-prefix score multipliers (prefix:weight,..., weights > 0) applied to all search modes; the deepest matching prefix wins (sessions:0.5 demotes sessions/**).
MARKDOWN_VAULT_MCP_FTS_WEIGHTS all 1.0 Per-column BM25 weights (column:weight,..., weights ≥ 0) for keyword ranking. Columns: path, title, folder, heading, content, summary.

Note: the chunker's character cap (MARKDOWN_VAULT_MCP_MAX_CHUNK_CHARS) is derived from the embedding model's context length, so changing the embedding model re-chunks the FTS index — not just the embeddings — and triggers an automatic cold rebuild of the index on the next startup. The defaults stay memory-light (BAAI/bge-small-en-v1.5 for FastEmbed, nomic-embed-text for Ollama); long-context models — nomic-ai/nomic-embed-text-v1.5 (8192 tokens) for FastEmbed, or bge-m3:latest for Ollama — are opt-in and need substantially more RAM/VRAM during indexing.

Git integration

Git integration has three modes:

  • Managed mode (MARKDOWN_VAULT_MCP_GIT_REPO_URL set): server owns repo setup. On startup it clones into SOURCE_DIR when empty, or validates existing origin. Pull loop + auto-commit + deferred push are enabled.
  • Unmanaged / commit-only mode (no GIT_REPO_URL): writes are committed to a local git repo if SOURCE_DIR is already a git checkout. No pull, no push.
  • No-git mode: if SOURCE_DIR is not a git repo, git callbacks are no-ops.

When token auth is used (MARKDOWN_VAULT_MCP_GIT_TOKEN), remotes must be HTTPS. SSH remotes (for example [email protected]:owner/repo.git) are rejected with a startup error. Fix with: git -C /path/to/vault remote set-url origin https://github.com/owner/repo.git

Backward compatibility: MARKDOWN_VAULT_MCP_GIT_TOKEN without GIT_REPO_URL still works (legacy mode) but logs a deprecation warning.

Variable Default Description
MARKDOWN_VAULT_MCP_GIT_REPO_URL HTTPS remote URL for managed mode; enables clone/remote validation on startup
MARKDOWN_VAULT_MCP_GIT_USERNAME x-access-token Username for HTTPS auth prompts (x-access-token for GitHub, oauth2 for GitLab, account name for Bitbucket)
MARKDOWN_VAULT_MCP_GIT_TOKEN Token/password for HTTPS auth (GIT_ASKPASS)
MARKDOWN_VAULT_MCP_GIT_PULL_INTERVAL_S 600 Seconds between git fetch + ff-only update attempts; 0 disables periodic pull
MARKDOWN_VAULT_MCP_GIT_PUSH_DELAY_S 30 Seconds of write-idle time before pushing; 0 = push only on shutdown
MARKDOWN_VAULT_MCP_GIT_COMMIT_NAME markdown-vault-mcp Git committer name for auto-commits; set this in Docker where git config user.name is empty
MARKDOWN_VAULT_MCP_GIT_COMMIT_EMAIL noreply@markdown-vault-mcp Git committer email for auto-commits
MARKDOWN_VAULT_MCP_GIT_COMMIT_NAME_CLAIM OIDC claim key to use as the commit author name (e.g. name); overrides GIT_COMMIT_NAME per-request when an OIDC token is present
MARKDOWN_VAULT_MCP_GIT_COMMIT_EMAIL_CLAIM OIDC claim key to use as the commit author e-mail (e.g. email); overrides GIT_COMMIT_EMAIL per-request when an OIDC token is present
MARKDOWN_VAULT_MCP_GIT_LFS true Enable Git LFS — runs git lfs pull on startup to fetch LFS-tracked attachments (PDFs, images). Set to false for repos without LFS.
MARKDOWN_VAULT_MCP_GITHUB_WEBHOOK_SECRET Shared secret for GitHub push-event webhook; when set, mounts POST /github-webhook on HTTP/SSE transports to trigger immediate pull + reindex on push events

File Watcher

Variable Default Description
MARKDOWN_VAULT_MCP_FILE_WATCHER true Enable filesystem-event watcher for external changes; auto-disabled when git pull or webhook is active
MARKDOWN_VAULT_MCP_FILE_WATCHER_DEBOUNCE_S 2.0 Seconds of quiet after the last event before triggering reindex
MARKDOWN_VAULT_MCP_FILE_WATCHER_ROOT_FLOOR true Keep the non-recursive watch on the vault root; set false to register zero source-directory-rooted FSEvents streams (avoids repeated macOS access prompts on a $HOME-rooted vault), at the cost of root-level files relying on scans

Requires the watchdog optional extra: pip install 'markdown-vault-mcp[file-watcher]'. Automatically disabled when GIT_PULL_INTERVAL_S > 0 or GITHUB_WEBHOOK_SECRET is set. The watcher scopes one recursive watch per non-excluded top-level directory (not a single recursive watch on the root), so excluded directories are never registered and content under a deliberately watched dot-directory delivers its own edits. See docs/configuration.md for details.

Attachments

Non-markdown file support. See Attachments for details.

Variable Default Description
MARKDOWN_VAULT_MCP_ATTACHMENT_EXTENSIONS (built-in list) Comma-separated allowed extensions without dot (e.g. pdf,png,jpg); use * to allow all non-.md files
MARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MB 1.0 Maximum attachment size in MB returned by read() / accepted by write(); 0 disables the limit
MARKDOWN_VAULT_MCP_MAX_NOTE_READ_BYTES 262144 (256 KB) Maximum bytes returned by full-document read() for .md files; raises ValueError if exceeded. Use read(path, section=...) for partial reads. 0 disables the limit.

Bearer token authentication

Simple static token auth for HTTP deployments. Set a single env var — clients must send Authorization: Bearer <token>.

Variable Required Description
MARKDOWN_VAULT_MCP_BEARER_TOKEN Yes Static bearer token; any non-empty string enables auth

OIDC authentication

Full OAuth 2.1 authentication for HTTP deployments. OIDC activates when all four required variables are set. See Authentication for setup details.

Multi-auth: If both BEARER_TOKEN and all OIDC variables are set, the server accepts either credential — a valid bearer token or a valid OIDC session. This is useful when different clients use different auth flows (e.g. Claude web via OIDC and Claude Code via bearer token).

Variable Required Description
MARKDOWN_VAULT_MCP_BASE_URL Yes Public base URL of the server (e.g. https://mcp.example.com; include prefix if mounted under subpath, e.g. https://mcp.example.com/vault). Used for OIDC auth and to auto-compute the MCP Apps domain.
MARKDOWN_VAULT_MCP_OIDC_CONFIG_URL Yes OIDC discovery endpoint (e.g. https://auth.example.com/.well-known/openid-configuration)
MARKDOWN_VAULT_MCP_OIDC_CLIENT_ID Yes OIDC client ID registered with your provider
MARKDOWN_VAULT_MCP_OIDC_CLIENT_SECRET Yes OIDC client secret
MARKDOWN_VAULT_MCP_OIDC_JWT_SIGNING_KEY No JWT signing key; required on Linux/Docker — the default is ephemeral and invalidates tokens on restart. Generate with openssl rand -hex 32
MARKDOWN_VAULT_MCP_OIDC_AUDIENCE No Expected JWT audience claim; leave unset if your provider does not set one
MARKDOWN_VAULT_MCP_OIDC_REQUIRED_SCOPES No Comma-separated required scopes; default openid
MARKDOWN_VAULT_MCP_OIDC_VERIFY_ACCESS_TOKEN No Set true to verify the upstream access token as a JWT instead of the id token. Only needed when your provider issues JWT access tokens and you require audience-claim validation on that token. Default: verify the id token (works with all providers, including opaque-token issuers like Authelia)

CLI Reference

markdown-vault-mcp <command> [options]

serve

Start the MCP server.

markdown-vault-mcp serve [--transport {stdio|sse|http}] [--host HOST] [--port PORT] [--http-path PATH]
Flag Default Description
--transport stdio MCP transport: stdio (stdin/stdout, default), sse (Server-Sent Events), http (streamable-HTTP). Use http for Docker with a reverse proxy or when OIDC is enabled.
--host 127.0.0.1 Bind host for the http transport (ignored for stdio and sse); pass 0.0.0.0 to bind all interfaces inside Docker
--port 8000 Port for the http transport (ignored for stdio and sse)
--http-path (alias --path) env MARKDOWN_VAULT_MCP_HTTP_PATH or /mcp MCP HTTP path for http transport; useful for reverse-proxy subpath mounting (e.g. /vault/mcp). The legacy --path spelling is still accepted.

Reverse Proxy Subpath Mounts

By default, HTTP transport serves MCP on /mcp. You can run it under a subpath:

markdown-vault-mcp serve --transport http --http-path /vault/mcp

Equivalent env-based config:

MARKDOWN_VAULT_MCP_HTTP_PATH=/vault/mcp

For reverse proxies, you can either:

  • Keep app path at /mcp and use proxy rewrite/strip-prefix middleware.
  • Set app path directly to the public path (/vault/mcp) and route without rewrite.

When OIDC is enabled under a subpath, the configuration is different: the subpath goes in BASE_URL only, and HTTP_PATH stays at /mcp. See OIDC subpath deployments.

Then your redirect URI is:

https://mcp.example.com/vault/auth/callback

index

Build the full-text search index.

markdown-vault-mcp index [--source-dir PATH] [--index-path PATH] [--force]

search

Search the vault from the CLI.

markdown-vault-mcp search <query> [-n LIMIT] [-m {keyword|semantic|hybrid}] [--folder PATH] [--json]

reindex

Incrementally reindex the vault (only processes changed files). When semantic search is configured, the vector index is converged to the updated chunk set — exactly the changed documents are re-embedded and orphaned vectors dropped, never the whole corpus.

markdown-vault-mcp reindex [--source-dir PATH] [--index-path PATH]

MCP Tools

Tool Description
search Hybrid full-text + semantic search with optional frontmatter filters
read Read a document or attachment by relative path
write Create or overwrite a document or attachment
edit Replace text in a document — exact match, line-range, or scoped match with normalized fallback
delete Delete a document or attachment and its index entries
rename Rename/move a document or attachment, updating all index entries; pass update_links=true to also rewrite backlinks in other notes
move_folder Move an entire folder subtree to a new prefix, rewriting all vault links that point into the moved subtree in one call
list_documents List indexed documents; pass include_attachments=true to also list non-markdown files
list_folders List all folder paths in the vault
list_tags List all unique frontmatter tag values
reindex Force a full reindex of the vault
stats Get vault statistics (document count, chunk count, link health metrics, etc.)
build_embeddings Build or rebuild vector embeddings for semantic search
embeddings_status Check embedding provider and index status
get_index_status Check background FTS build state (queryable / building / failed)
get_backlinks Find all documents that link to a given document
get_outlinks Find all links from a document, with existence check
get_broken_links Find all links pointing to non-existent documents
get_similar Find semantically similar notes by document path
get_toc Heading outline for a note or a folder subtree
get_recent Get the most recently modified notes
get_context Get a consolidated context dossier for a note (backlinks, outlinks, similar, folder peers, tags, modified time)
get_orphan_notes Find all notes with no inbound or outbound links
get_most_linked Find the most-linked-to notes ranked by backlink count
get_connection_path Find the shortest path between two notes via BFS on the undirected link graph (max 10 hops)
summarize Summarize a note, a set of notes, or a folder subtree with an LLM; the synthesis references the individual source notes by path. A slow summary is promoted to a background job (retrieved via get_summary) so the tool never hangs. Hidden unless an OpenAI-compatible backend is configured (OPENAI_API_KEY or a base URL). Sends note content to the model provider.
get_summary Retrieve a summary that summarize promoted to a background job, by its job_id. Registered alongside summarize.
get_history List commits that touched a note, attachment, or the whole vault (git-backed vaults only)
get_diff Return a diff of a note or attachment between a reference commit/timestamp and HEAD; binary attachments return a --stat size summary instead of a unified patch (git-backed vaults only)
git_sync Force an immediate git pull / push / both, bypassing the periodic loops. Returns structured state (SHAs, commit counts, Syncthing-style conflict file paths if any). Hidden when MARKDOWN_VAULT_MCP_GIT_REPO_URL isn't set or READ_ONLY=true.
fetch Download a file from a URL and save it to the vault as a note or attachment (MCP-to-MCP transfer)
create_download_link Mint a one-time capability URL to download a vault note or attachment (HTTP/SSE only; BASE_URL required)
create_upload_link Mint a one-time capability URL to upload bytes to a fixed vault path (HTTP/SSE only; BASE_URL required; hidden when READ_ONLY=true)
browse_vault Open the vault explorer SPA in a supporting MCP Apps client
show_context Open the Context Card for a specific note in a supporting MCP Apps client

Write tools (write, edit, delete, rename, move_folder, fetch, git_sync, create_upload_link) are only available when MARKDOWN_VAULT_MCP_READ_ONLY=false. git_sync additionally requires managed git mode (MARKDOWN_VAULT_MCP_GIT_REPO_URL set).

summarize is registered only when a summarization backend is configured: an OPENAI_API_KEY, or an OpenAI-compatible base URL for local endpoints that need no key. It needs the openai SDK (pip install 'markdown-vault-mcp[summarize]') and sends note content to the model provider. Any OpenAI-compatible endpoint works: OpenAI itself, a local Ollama (http://localhost:11434/v1, no key needed), the Anthropic compatibility endpoint (https://api.anthropic.com/v1), vLLM, and others. See Configuration for provider recipes.

browse_vault and show_context are LLM-visible in all clients; when called in an MCP Apps-capable client they open the interactive SPA. Six additional internal tools (vault_context, vault_list, vault_read, vault_search, vault_graph_neighborhood, vault_graph_hubs) use visibility="app" and are used by the SPA only — they are never visible to the LLM.

Resources

MCP resources expose vault metadata as structured JSON that clients can read directly without invoking tools.

URI Description
config://vault Current vault configuration (source dir, indexed fields, read-only state, etc.)
stats://vault Vault statistics (document count, chunk count, embedding count, etc.)
tags://vault All frontmatter tag values grouped by indexed field
tags://vault/{field} Tag values for a specific indexed frontmatter field (template)
folders://vault All folder paths in the vault
toc://vault/{path} Table of contents (heading outline) for a specific document (template)
similar://vault/{path} Top 10 semantically similar notes for a document (template)
recent://vault 20 most recently modified notes with ISO timestamps
ui://markdown_vault_mcp/app.html Interactive vault explorer SPA for MCP Apps clients

Prompts

Prompt templates guide the LLM through multi-step workflows using the vault tools.

Prompt Parameters Description
summarize path Read a document and produce a structured summary with key themes and takeaways
research topic Search for a topic, synthesize findings, and create a new note at research/{topic}.md
discuss path Analyze a document and suggest improvements using edit (not write)
create_from_template template_name (optional) Discover templates (if needed), read a template, gather user values, and write a new note
related path Find related notes via search and suggest cross-references as markdown links
compare path1, path2 Read two documents and produce a side-by-side comparison
propose-links scope (optional), per_note_limit (optional) Scan a candidate set of notes (a folder, recent, or all), propose meaningful links between semantically-close notes that aren't already connected, and write them on confirmation

Write prompts (research, discuss, create_from_template, propose-links) are only available when MARKDOWN_VAULT_MCP_READ_ONLY=false.

Templates are regular markdown files. If placeholder template text pollutes search results, add your templates folder to MARKDOWN_VAULT_MCP_EXCLUDE (for example _templates/**).

User-defined prompts

Mount a directory of .md prompt files to override or extend the built-in prompts. Set MARKDOWN_VAULT_MCP_PROMPTS_FOLDER to the path. Each file's frontmatter defines description, arguments (a list of objects, each with name, description, and required fields), and optional tags. A user prompt with the same name as a built-in replaces it.

For a complete example — including Zettelkasten capture, development, and review prompts — see the Zettelkasten guide. For an alternative action-oriented workflow — Projects, Areas, Resources, Archive with triage, kickoff, and weekly review prompts — see the PARA guide.

MCP Apps

The server ships four browser-based views that MCP clients supporting the MCP Apps protocol can render inline or in fullscreen. They are delivered as a single HTML resource at ui://markdown_vault_mcp/app.html and registered using visibility="app" so they appear only in supporting clients and do not clutter the standard tool list. See the MCP Apps guide for details.

View Description
Context Card Displays a note dossier (backlinks, outlinks, similar notes, tags) for the note currently in focus
Graph Explorer Interactive force-directed link graph of the vault, powered by vis-network
Vault Browser Searchable, filterable file tree for navigating the vault without issuing tool calls
Note Preview Full-width markdown preview with a Contents popover, collapsible frontmatter properties and tags, copy-markdown / copy-vault-link controls, and a "Send to Claude" button

The two primary tools exposed to MCP Apps clients are:

Tool Description
browse_vault Returns the vault tree structure for the Vault Browser view
show_context Returns the full context dossier for a given note path (used by the Context Card view)

Domain configuration: MCP Apps iframes are sandboxed to a specific Claude app domain. The domain is auto-computed from MARKDOWN_VAULT_MCP_BASE_URL. Override with MARKDOWN_VAULT_MCP_APP_DOMAIN if your deployment is hosted on a custom domain or behind a proxy that changes the apparent hostname.

Vendored dependencies (JavaScript libraries bundled at build time, no runtime CDN): vis-network (graph rendering), marked.js (markdown rendering), DOMPurify (XSS sanitization), ext-apps SDK (MCP Apps lifecycle). The one runtime network dependency is web fonts (Newsreader, Public Sans, IBM Plex Mono), loaded from Google Fonts with system-font fallbacks.

One-Time Transfer Links

create_download_link and create_upload_link mint short-lived capability URLs so vault files can move to a browser or another service without inflating th