CAT
/MCP
SkillsMCPMarketplacesDigestToolsAdvertise

This week in Claude

Every Monday: Claude Code, Agent SDK, MCP, and the Anthropic platform moves worth your time.

Skills by Category
Frontend DevelopmentBackend & APIsTesting & QASecurityDevOps & CI/CDGit & Pull RequestsDocumentationCode Review & QualityAI & Agent BuildingSkill Development
MCP Servers by Category
Sales & MarketingWeb & Browser AutomationDatabasesAI & LLM ToolsCloud & InfrastructureCommunication & MessagingDeveloper ToolsDesign & CreativeDocuments & KnowledgeSearch & Web Crawling
Marketplaces by Category
AI Agents & OrchestrationLLM IntegrationDevelopment ToolsFrontend & UIBackend & APIsDatabasesTesting & Code QualityDevOps & CloudSecurity & ComplianceGit & Version Control

Cross AI Tools

Discover Claude Code plugins, extensions, and tools. Automatically updated directory of Anthropic Claude AI marketplaces with development tools, productivity plugins, and integrations.

Resources

  • Browse Skills
  • Browse MCP Servers
  • Browse Marketplaces
  • Plugins Reference

Community

  • About
  • Tools
  • Feedback
  • Privacy Policy
  • Advertise

Built for the Claude Code community with Claude Code by @mertduzgun

Independent project, not affiliated with Anthropic

Markdown Vault MCP

pvliesdonk/markdown-vault-mcp
16authSTDIO, HTTPregistry active
Summary

Point this at any folder of Markdown files and you get a 30-tool MCP server that turns your notes into queryable context. It combines SQLite FTS5 full-text search with semantic vector search (FastEmbed, Ollama, or OpenAI), handles YAML frontmatter indexing, and exposes read, write, edit, delete, and rename operations with automatic incremental reindexing. The adaptive chunking splits long sections at progressively deeper heading levels until they fit a configurable word budget, and search returns sentence-scale snippets by default to keep context costs bounded. Ships with optional Git auto-commit, OIDC auth for HTTP deployments, and 6 prompt templates including one that scans recent notes and proposes missing wikilinks. Useful for Obsidian vaults, Zettelkasten collections, or any documentation folder you want Claude to search and modify in conversation.

CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →
CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →

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 chunk 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 a specific chunk 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 with automatic index updates
  • 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 — 31 LLM-visible tools including search, read, write, edit, delete, rename, 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 HTTP
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 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

FileDescription
examples/obsidian-readonly.envObsidian vault, read-only, Ollama embeddings
examples/obsidian-readwrite.envObsidian vault, read-write with git auto-commit
examples/obsidian-oidc.envObsidian vault, read-only, OIDC authentication (Authelia)
examples/ifcraftcorpus.envStrict 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).

  • Configuration Generator: in-browser config / Docker / systemd builder

Core

VariableDefaultRequiredDescription
MARKDOWN_VAULT_MCP_SOURCE_DIR—YesPath to the markdown vault directory
MARKDOWN_VAULT_MCP_READ_ONLYtrueNoSet to false to enable write operations
MARKDOWN_VAULT_MCP_INDEX_PATHin-memoryNoPath to the SQLite FTS5 index file; set for persistence across restarts
MARKDOWN_VAULT_MCP_EMBEDDINGS_PATHdisabledNoPath to the numpy embeddings file; required to enable semantic search
MARKDOWN_VAULT_MCP_STATE_PATH{SOURCE_DIR}/.markdown_vault_mcp/state.jsonNoPath to the change-tracking state file
MARKDOWN_VAULT_MCP_INDEXED_FIELDS—NoComma-separated frontmatter fields to promote to the tag index for structured filtering
MARKDOWN_VAULT_MCP_REQUIRED_FIELDS—NoComma-separated frontmatter fields required on every document; documents missing any are excluded from the index
MARKDOWN_VAULT_MCP_EXCLUDE—NoComma-separated glob patterns to exclude from scanning (e.g. .obsidian/**,.trash/**)
MARKDOWN_VAULT_MCP_TEMPLATES_FOLDER_templatesNoRelative folder path where note templates live (used by the create_from_template prompt)
MARKDOWN_VAULT_MCP_PROMPTS_FOLDER—NoPath to a directory of .md prompt files that extend or override built-in prompts (see User-defined prompts)
MARKDOWN_VAULT_MCP_DRAIN_TIMEOUT_S60NoMaximum 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_S60NoMaximum 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

VariableDefaultDescription
MARKDOWN_VAULT_MCP_SERVER_NAMEmarkdown-vault-mcpMCP 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_UIfalseHide 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/mcpHTTP endpoint path for streamable HTTP transport (used by serve --transport http)
MARKDOWN_VAULT_MCP_KV_STORE_URLfile:///data/stateUnified 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_LEVELINFOLog level for FastMCP internals (DEBUG, INFO, WARNING, ERROR). App loggers default to INFO. -v overrides both to DEBUG.
FASTMCP_ENABLE_RICH_LOGGINGtrueRich key=value text by default. Set to false for one-JSON-object-per-record output — recommended for production / log-aggregator deployments.

Search and embeddings

VariableDefaultDescription
MARKDOWN_VAULT_MCP_EMBEDDING_PROVIDERauto-detectEmbedding provider: openai, ollama, or fastembed
OLLAMA_HOSThttp://localhost:11434Ollama 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_URLhttps://api.openai.com/v1OpenAI-compatible API base URL for embeddings
MARKDOWN_VAULT_MCP_OPENAI_EMBEDDING_MODEL / OPENAI_EMBEDDING_MODELtext-embedding-3-smallOpenAI-compatible embedding model name
MARKDOWN_VAULT_MCP_OLLAMA_MODELnomic-embed-textOllama embedding model name
MARKDOWN_VAULT_MCP_OLLAMA_CPU_ONLYfalseForce Ollama to use CPU only
MARKDOWN_VAULT_MCP_FASTEMBED_MODELBAAI/bge-small-en-v1.5FastEmbed model name
MARKDOWN_VAULT_MCP_FASTEMBED_CACHE_DIRFastEmbed defaultFastEmbed model cache directory (in Docker, stored under /data/state/fastembed)
MARKDOWN_VAULT_MCP_MAX_CHUNK_WORDS400Word 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 reindex applies a new value.
MARKDOWN_VAULT_MCP_MAX_CHUNK_CHARS(derived from model context)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 → round(context_length × 2.8) (e.g. 8192-token model → 22938 chars; the default BAAI/bge-small-en-v1.5 model → ~1434 chars); unknown context → 6000. Set to override. A reindex applies a new value.
MARKDOWN_VAULT_MCP_CHUNKS_PER_FILE2Maximum chunks returned per document in search results.
MARKDOWN_VAULT_MCP_SNIPPET_WORDS200Width of the snippet window (words) in search results; 0 returns full chunk content.
MARKDOWN_VAULT_MCP_LENGTH_DOWNWEIGHT_ALPHA0.25Down-weights longer chunks in ranking (score / (1 + alpha · log(chunk_count))).

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 git@github.com: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.

VariableDefaultDescription
MARKDOWN_VAULT_MCP_GIT_REPO_URL—HTTPS remote URL for managed mode; enables clone/remote validation on startup
MARKDOWN_VAULT_MCP_GIT_USERNAMEx-access-tokenUsername 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_S600Seconds between git fetch + ff-only update attempts; 0 disables periodic pull
MARKDOWN_VAULT_MCP_GIT_PUSH_DELAY_S30Seconds of write-idle time before pushing; 0 = push only on shutdown
MARKDOWN_VAULT_MCP_GIT_COMMIT_NAMEmarkdown-vault-mcpGit committer name for auto-commits; set this in Docker where git config user.name is empty
MARKDOWN_VAULT_MCP_GIT_COMMIT_EMAILnoreply@markdown-vault-mcpGit 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_LFStrueEnable 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

VariableDefaultDescription
MARKDOWN_VAULT_MCP_FILE_WATCHERtrueEnable filesystem-event watcher for external changes; auto-disabled when git pull or webhook is active
MARKDOWN_VAULT_MCP_FILE_WATCHER_DEBOUNCE_S2.0Seconds of quiet after the last event before triggering reindex

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.

Attachments

Non-markdown file support. See Attachments for details.

VariableDefaultDescription
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_MB1.0Maximum attachment size in MB returned by read() / accepted by write(); 0 disables the limit
MARKDOWN_VAULT_MCP_MAX_NOTE_READ_BYTES262144 (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>.

VariableRequiredDescription
MARKDOWN_VAULT_MCP_BEARER_TOKENYesStatic 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).

VariableRequiredDescription
MARKDOWN_VAULT_MCP_BASE_URLYesPublic 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_URLYesOIDC discovery endpoint (e.g. https://auth.example.com/.well-known/openid-configuration)
MARKDOWN_VAULT_MCP_OIDC_CLIENT_IDYesOIDC client ID registered with your provider
MARKDOWN_VAULT_MCP_OIDC_CLIENT_SECRETYesOIDC client secret
MARKDOWN_VAULT_MCP_OIDC_JWT_SIGNING_KEYNoJWT 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_AUDIENCENoExpected JWT audience claim; leave unset if your provider does not set one
MARKDOWN_VAULT_MCP_OIDC_REQUIRED_SCOPESNoComma-separated required scopes; default openid
MARKDOWN_VAULT_MCP_OIDC_VERIFY_ACCESS_TOKENNoSet 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]
FlagDefaultDescription
--transportstdioMCP 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.
--host127.0.0.1Bind host for the http transport (ignored for stdio and sse); pass 0.0.0.0 to bind all interfaces inside Docker
--port8000Port for the http transport (ignored for stdio and sse)
--http-path (alias --path)env MARKDOWN_VAULT_MCP_HTTP_PATH or /mcpMCP 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

ToolDescription
searchHybrid full-text + semantic search with optional frontmatter filters
readRead a document or attachment by relative path
writeCreate or overwrite a document or attachment
editReplace text in a document — exact match, line-range, or scoped match with normalized fallback
deleteDelete a document or attachment and its index entries
renameRename/move a document or attachment, updating all index entries; pass update_links=true to also rewrite backlinks in other notes
list_documentsList indexed documents; pass include_attachments=true to also list non-markdown files
list_foldersList all folder paths in the vault
list_tagsList all unique frontmatter tag values
reindexForce a full reindex of the vault
statsGet vault statistics (document count, chunk count, link health metrics, etc.)
build_embeddingsBuild or rebuild vector embeddings for semantic search
embeddings_statusCheck embedding provider and index status
get_index_statusCheck background FTS build state (queryable / building / failed)
get_backlinksFind all documents that link to a given document
get_outlinksFind all links from a document, with existence check
get_broken_linksFind all links pointing to non-existent documents
get_similarFind semantically similar notes by document path
get_recentGet the most recently modified notes
get_contextGet a consolidated context dossier for a note (backlinks, outlinks, similar, folder peers, tags, modified time)
get_orphan_notesFind all notes with no inbound or outbound links
get_most_linkedFind the most-linked-to notes ranked by backlink count
get_connection_pathFind the shortest path between two notes via BFS on the undirected link graph (max 10 hops)
get_historyList commits that touched a note, attachment, or the whole vault (git-backed vaults only)
get_diffReturn 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_syncForce 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.
fetchDownload a file from a URL and save it to the vault as a note or attachment (MCP-to-MCP transfer)
create_download_linkMint a one-time capability URL to download a vault note or attachment (HTTP/SSE only; BASE_URL required)
create_upload_linkMint 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_vaultOpen the vault explorer SPA in a supporting MCP Apps client
show_contextOpen the Context Card for a specific note in a supporting MCP Apps client

Write tools (write, edit, delete, rename, 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).

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.

URIDescription
config://vaultCurrent vault configuration (source dir, indexed fields, read-only state, etc.)
stats://vaultVault statistics (document count, chunk count, embedding count, etc.)
tags://vaultAll frontmatter tag values grouped by indexed field
tags://vault/{field}Tag values for a specific indexed frontmatter field (template)
folders://vaultAll 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://vault20 most recently modified notes with ISO timestamps
ui://vault/app.htmlInteractive vault explorer SPA for MCP Apps clients

Prompts

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

PromptParametersDescription
summarizepathRead a document and produce a structured summary with key themes and takeaways
researchtopicSearch for a topic, synthesize findings, and create a new note at research/{topic}.md
discusspathAnalyze a document and suggest improvements using edit (not write)
create_from_templatetemplate_name (optional)Discover templates (if needed), read a template, gather user values, and write a new note
relatedpathFind related notes via search and suggest cross-references as markdown links
comparepath1, path2Read two documents and produce a side-by-side comparison
propose-linksscope (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://vault/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.

ViewDescription
Context CardDisplays a note dossier (backlinks, outlinks, similar notes, tags) for the note currently in focus
Graph ExplorerInteractive force-directed link graph of the vault, powered by vis-network
Vault BrowserSearchable, filterable file tree for navigating the vault without issuing tool calls
Note PreviewFull-width markdown preview with frontmatter table and "Send to Claude" button

The two primary tools exposed to MCP Apps clients are:

ToolDescription
browse_vaultReturns the vault tree structure for the Vault Browser view
show_contextReturns 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 (bundled at build time, no runtime CDN): vis-network (graph rendering), marked.js (markdown rendering), DOMPurify (XSS sanitization), ext-apps SDK (MCP Apps lifecycle).

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 the LLM context window. The token embedded in the URL is the only credential — no Authorization header is required on the /transfer/{token} route.

# Download a vault file
create_download_link(path="reports/q1.pdf", ttl_seconds=600)
# → {"url": "https://mcp.example.com/transfer/<token>", ...}
curl "https://mcp.example.com/transfer/<token>" -o q1.pdf

# Upload a file to the vault
create_upload_link(path="assets/new-diagram.png")
# → {"url": "https://mcp.example.com/transfer/<token>", ...}
curl -X POST --data-binary @new-diagram.png "https://mcp.example.com/transfer/<token>"

Each token is consumed on its first successful use. A failed or interrupted transfer does not burn the token — retry is permitted until the TTL expires.

Requirements: HTTP or SSE transport; MARKDOWN_VAULT_MCP_BASE_URL set. See the transfer links guide for the full walkthrough and security model.

VariableDefaultDescription
MARKDOWN_VAULT_MCP_TRANSFER_TTL_DEFAULT_S3600Default token lifetime (seconds) when the caller omits ttl_seconds; clamped to the max below.
MARKDOWN_VAULT_MCP_TRANSFER_TTL_MAX_S86400Maximum permitted TTL; any larger ttl_seconds is silently clamped to this ceiling.
MARKDOWN_VAULT_MCP_TRANSFER_MAX_UPLOAD_BYTES104857600 (100 MiB)Per-upload size cap; requests whose body exceeds it are rejected with HTTP 413.

Attachments

In addition to Markdown notes, the server can read, write, delete, rename, and list non-markdown files (PDFs, images, spreadsheets, etc.). All existing tools are overloaded — no new tool names.

How it works

Path dispatch is extension-based: a path ending in .md is treated as a note; any other path is treated as an attachment if the extension is in the allowlist. The kind field on returned objects distinguishes the two: "note" or "attachment".

Reading attachments

read returns base64-encoded content for binary attachments:

{
  "path": "assets/diagram.pdf",
  "mime_type": "application/pdf",
  "size_bytes": 12345,
  "content_base64": "<base64 string>",
  "modified_at": 1741564800.0
}

Writing attachments

write accepts a content_base64 parameter for binary content:

{ "path": "assets/diagram.pdf", "content_base64": "<base64 string>" }

Listing attachments

list_documents with include_attachments=true returns both notes and attachments:

[
  { "path": "notes/intro.md", "kind": "note", "title": "Intro", "folder": "notes", "frontmatter": {}, "modified_at": 1741564800.0 },
  { "path": "assets/diagram.pdf", "kind": "attachment", "folder": "assets", "mime_type": "application/pdf", "size_bytes": 12345, "modified_at": 1741564800.0 }
]

Default allowed extensions

pdf, docx, xlsx, pptx, odt, ods, odp, png, jpg, jpeg, gif, webp, svg, bmp, tiff, zip, tar, gz, mp3, mp4, wav, ogg, txt, csv, tsv, json, yaml, toml, xml, html, css, js, ts

Override with MARKDOWN_VAULT_MCP_ATTACHMENT_EXTENSIONS. Use * to allow all non-.md files.

Hidden directories: Attachments inside hidden directories (.git/, .obsidian/, .markdown_vault_mcp/, etc.) are never listed, regardless of extension settings. MARKDOWN_VAULT_MCP_EXCLUDE patterns are also applied to attachments.

Authentication

The server supports four auth modes:

  1. Multi-auth — both bearer token and OIDC configured; either credential accepted (e.g. Claude web via OIDC + Claude Code via bearer token on the same instance)
  2. Bearer token — set MARKDOWN_VAULT_MCP_BEARER_TOKEN to a secret string
  3. OIDC — full OAuth 2.1 flow via OIDC_CONFIG_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, and BASE_URL
  4. No auth — server accepts all connections (default)

Auth requires --transport http (or sse). It has no effect with --transport stdio.

For setup instructions, troubleshooting, and provider-specific guides, see the Authentication guide.

Development

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

# Run tests
uv run python -m pytest tests/ -x -q

# Lint and format
uv run ruff check src/ tests/
uv run ruff format src/ tests/

# Type check
uv run mypy src/ tests/

GitHub secrets

CI workflows reference three repository secrets. Configure them via Settings → Secrets and variables → Actions or with gh secret set:

SecretUsed byHow to generate
RELEASE_TOKENrelease.yml, copier-update.ymlFine-grained PAT at https://github.com/settings/personal-access-tokens/new with contents: write and pull_requests: write (the copier-update cron opens PRs). Scoped to this repo.
CODECOV_TOKENci.ymlhttps://codecov.io — sign in with GitHub, add the repo, copy the upload token from the repo settings page.
CLAUDE_CODE_OAUTH_TOKENclaude.yml, claude-code-review.ymlRun claude setup-token locally and paste the result.

GITHUB_TOKEN is auto-provided — no action needed.

Troubleshooting

Moving a scaffolded project

uv sync creates .venv/bin/* scripts with absolute shebangs pointing at the venv Python. If you move the repo (mv /old/path /new/path), uv run pytest fails with ModuleNotFoundError because the stale shebang resolves to a different interpreter than the venv's site-packages.

Fix:

rm -rf .venv
uv sync --all-extras --all-groups

uv run python -m pytest also works as a one-shot workaround.

uv.lock refresh after copier update

When copier update introduces new dependencies, CI runs uv sync --frozen which fails against a stale lockfile. Run uv lock locally and commit the refreshed uv.lock alongside accepting the copier-update PR.

Upgrading from earlier versions

  • v2.0.0 (issue #469): search, get_similar, and get_context.similar now return grouped results. Each file appears once with a sections list; the flat content, heading, and score fields have moved inside each SectionHit. Library consumers must update iteration:

    # Before: result.content, result.heading
    # After:  result.sections[0].content, result.sections[0].heading
    

    MARKDOWN_VAULT_MCP_CHUNKS_PER_FILE replaces MARKDOWN_VAULT_MCP_CHUNKS_PER_DOC. SimilarItem is removed; use GroupedResult (also re-exported at the package level).

  • MARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MB default lowered from 10 MB to 1 MB. Most LLM contexts can't survive a 10 MB base64-encoded attachment; the old default was a silent context-blow-up. If you have non-LLM consumers (scripts, CI) that need the old behaviour, set MARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MB=10 explicitly.

  • MARKDOWN_VAULT_MCP_MAX_NOTE_READ_BYTES is a new env var (default 256 KB). Whole-document .md reads above this raise ValueError. Partial reads via read(path, section=heading) bypass the cap.

License

MIT

Featured
CodeRabbit
CodeRabbit
AI writes the code. CodeRabbit catches the slop.
Try For Free →
Keep your Mac awake
Keep your Mac awake
Keep your Mac awake while Claude Code and 40+ AI agents run. Sleeps when they're idle.
One time payment $9 →
Context.devContext.dev
Context.dev
Integrate web data into your AI product. One API to scrape website & brand data.
Get API Key Now →
Make your agent a DeFi expert
Make your agent a DeFi expert
Agent, run crypto. Access onchain data & trade routes via 1inch.
Install now →
Make money from your Skills
Make money from your Skills
On Capafy, your Skill runs online 24/7 as an agent product, and you get paid every time someone uses it.
Start earning →
AppSignal
AppSignal
Monitor with ease. Code with confidence.
Start Free Trial →

Configuration

MARKDOWN_VAULT_MCP_SOURCE_DIR*

Absolute path to the markdown vault directory

MARKDOWN_VAULT_MCP_READ_ONLYdefault: true

Disable write tools

FASTMCP_LOG_LEVELdefault: INFO

Log level for FastMCP internals; app loggers default to INFO, -v overrides both to DEBUG

MARKDOWN_VAULT_MCP_EVENT_STORE_URLdefault: file:///data/state/events

Event store backend for HTTP session persistence (file:///path or memory://)

MARKDOWN_VAULT_MCP_SERVER_NAMEdefault: markdown-vault-mcp

MCP server name shown to clients

MARKDOWN_VAULT_MCP_STATE_PATH

Directory for index and embeddings state files

MARKDOWN_VAULT_MCP_INDEX_PATH

Path to the FTS5 SQLite index file

MARKDOWN_VAULT_MCP_EMBEDDINGS_PATH

Path to the numpy embeddings file

MARKDOWN_VAULT_MCP_INDEXED_FIELDS

Comma-separated frontmatter fields to index for search

MARKDOWN_VAULT_MCP_REQUIRED_FIELDS

Comma-separated frontmatter fields required on every document

MARKDOWN_VAULT_MCP_EXCLUDE

Comma-separated glob patterns to exclude from indexing

MARKDOWN_VAULT_MCP_EMBEDDING_PROVIDER

Embedding provider to use

OPENAI_API_KEYsecret

OpenAI API key (required when MARKDOWN_VAULT_MCP_EMBEDDING_PROVIDER=openai)

MARKDOWN_VAULT_MCP_OLLAMA_MODELdefault: nomic-embed-text

Ollama embedding model name

MARKDOWN_VAULT_MCP_OLLAMA_CPU_ONLYdefault: false

Force CPU-only inference for Ollama

OLLAMA_HOSTdefault: http://localhost:11434

Ollama server base URL

MARKDOWN_VAULT_MCP_GIT_TOKENsecret

Git authentication token for push/pull

MARKDOWN_VAULT_MCP_GIT_REPO_URL

Remote git repository URL for managed mode

MARKDOWN_VAULT_MCP_GIT_USERNAMEdefault: x-access-token

Git username for token auth

MARKDOWN_VAULT_MCP_GIT_COMMIT_NAMEdefault: markdown-vault-mcp

Git committer name

MARKDOWN_VAULT_MCP_GIT_COMMIT_EMAILdefault: noreply@markdown-vault-mcp

Git committer email

MARKDOWN_VAULT_MCP_GIT_PUSH_DELAY_Sdefault: 30

Seconds to wait before pushing (batches writes)

MARKDOWN_VAULT_MCP_GIT_LFSdefault: true

Enable Git LFS support

MARKDOWN_VAULT_MCP_GIT_PULL_INTERVAL_Sdefault: 600

Seconds between periodic git pulls (0 to disable)

Categories
Documents & KnowledgeSearch & Web Crawling
Registryactive
Packagemarkdown-vault-mcp
TransportSTDIO, HTTP
AuthRequired
UpdatedApr 23, 2026
View on GitHub

Related Documents & Knowledge MCP Servers

View all →
Pdf Document Mcp

csoai-org/pdf-document-mcp

pdf-document-mcp MCP server by MEOK AI Labs
Mcp Document Converter

xt765/mcp-document-converter

Convert PDF, DOCX, HTML, Markdown, and Text for AI assistant context injection.
10
Markdown Formatter

io.github.xjtlumedia/markdown-formatter

AI Answer Copier — Convert Markdown to PDF, DOCX, HTML, LaTeX, CSV, JSON, XML, XLSX, RTF, PNG
3
Better Notion

io.github.ai-aviate/better-notion

Operate Notion with a single Markdown document — read, create, and update pages in one call.
2
Notion

suekou/mcp-notion-server

Notion MCP Server enables LLMs to access Notion workspaces with optional Markdown conversion to save tokens.
892
Docx

meterlong/mcp-doc

A powerful Word document processing service based on FastMCP, enabling AI assistants to create, edit, and manage docx files with full formatting support. Preserves original styles when editing content. 基于FastMCP的强大Word文档处理服务,使AI助手能够创建、编辑和管理docx文件,支持完整的格式设置功能。在编辑内容时能够保留原始样式和格式,实现精确的文档操作。
185