vault-mcp
Provides tools for searching, reading, creating, editing, renaming, and relating notes within an Obsidian-style markdown vault, including YAML frontmatter and wiki-link support.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@vault-mcpWhat notes do I have about the OpenAI API?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
vault-mcp
An MCP server that exposes a markdown vault (Obsidian-style: YAML frontmatter +
[[wiki-links]]) as a shared memory substrate for coding/research agents —
Claude Code, Gemini CLI, Codex, or anything else that speaks MCP.
Design
The vault is the source of truth. Durable, human-readable markdown files, versioned by git/jj. The server never stores state anywhere else.
The DuckDB index is disposable infrastructure. Frontmatter and wiki-links are parsed into an in-memory DuckDB database that backs search filters,
related, andquery. It is rebuilt from the files on demand (30s TTL, invalidated on every write) and is never authoritative.Writes are constrained verbs, never arbitrary file writes. Each write tool targets one convention-enforced location (an atomic note, an inbox item, a journal log line). Version control is the safety net.
The rule that matters more than the machinery, baked into the server's MCP instructions so every connected agent receives it:
The vault is a collection of durable, human-readable artifacts — not an agent transcript store. Do not create memories merely because information appeared in a conversation. Write a memory only when it represents a durable fact, decision, idea, relationship, or useful piece of project context.
Related MCP server: obsidian-local-rest-api
Tool surface
Tool | Kind | What it does |
| read |
|
| read | resolve a vault-relative path, note name, or frontmatter alias (typos auto-correct above 0.95 similarity; below that the error carries did-you-mean candidates) |
| read | graph neighborhood: outlinks, backlinks, unresolved links, shared-tag neighbors |
| read | read-only SQL (DuckDB dialect, SELECT/WITH only) over |
| read | most recently modified notes |
| write | atomic idea note in |
| write | exact string replacement anywhere in a note (frontmatter included); |
| write | replace a note's entire body; the frontmatter block is preserved verbatim |
| write | rename file + first H1 to the new title and rewrite |
| write | open action item under |
| write | timestamped line in today's journal |
| admin | force index rebuild; returns note/link counts |
Index schema for query:
notes(path, name, title, type, tags VARCHAR[], aliases VARCHAR[], date, status,
frontmatter JSON, modified TIMESTAMP, size, body /* SELECT columns, not * */)
links(source /* note path */, target /* wiki-link name as written */)Ranked search is DuckDB's FTS extension (BM25; digits searchable, stopwords
disabled — see docs/research/duckdb-fts.md for the extension's real
constraints). The FTS index builds lazily, once per rebuild, on first ranked
query.
templates/, raw/, and dot-directories are excluded from indexing and search.
Configuration
The vault root defaults to ~/Documents/seandavis; override with the
VAULT_MCP_ROOT environment variable.
Requires ripgrep (rg) on PATH.
Transports
vault-mcp speaks stdio by default. Pass --http to serve streamable HTTP
at /mcp (--host/--port, default 127.0.0.1:8787; also settable via
VAULT_MCP_HTTP, VAULT_MCP_HOST, VAULT_MCP_PORT).
Claude Code
# stdio (local spawn)
claude mcp add vault-memory -- uv run --directory ~/Documents/git/vault-mcp vault-mcp
# HTTP (shared server, e.g. over the tailnet)
claude mcp add --transport http vault-memory https://<machine>.<tailnet>.ts.net/mcpGemini CLI (~/.gemini/settings.json)
{
"mcpServers": {
"vault-memory": {
"command": "uv",
"args": ["run", "--directory", "/Users/davsean/Documents/git/vault-mcp", "vault-mcp"]
}
}
}Codex (~/.codex/config.toml)
[mcp_servers.vault-memory]
command = "uv"
args = ["run", "--directory", "/Users/davsean/Documents/git/vault-mcp", "vault-mcp"]Serving the tailnet
One HTTP server co-located with the vault gives every dev machine the same memory substrate — one canonical index, one writer (which also keeps Obsidian-sync conflicts down, since remote machines write through the API instead of writing files and hoping sync merges them).
macOS (launchd)
On the (Mac) machine that owns the vault, run the server as a LaunchAgent so it starts at login and restarts if it dies:
mkdir -p ~/.local/state # log destination
cp deploy/com.seandavis.vault-mcp.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.seandavis.vault-mcp.plistThe agent runs deploy/vault-mcp-tailnet.sh, which waits for tailscaled,
resolves the machine's Tailscale IP, and binds it directly on port 9321 —
no tailscale serve layer needed.
macOS privacy (TCC): launchd jobs have no access to
~/Documents, so if the repo or the vault lives there the agent dies withOperation not permittedin the log. Grant Full Disk Access to the job's interpreter — System Settings → Privacy & Security → Full Disk Access → + → ⌘⇧G →/bin/sh— then restart it withlaunchctl kickstart -k gui/$(id -u)/com.seandavis.vault-mcp. (Terminal sessions don't hit this because the terminal app carries the grant; launchd carries none.)
Verify and manage it with:
launchctl print gui/$(id -u)/com.seandavis.vault-mcp | head # state
tail -f ~/.local/state/vault-mcp-http.log # logs
launchctl kickstart -k gui/$(id -u)/com.seandavis.vault-mcp # restart (e.g. after git pull)
launchctl bootout gui/$(id -u)/com.seandavis.vault-mcp # stop + unloadClients on the tailnet connect to http://<tailscale-ip>:9321/mcp, e.g.:
claude mcp add --transport http vault-memory http://100.72.62.9:9321/mcpLinux (systemd)
The same wrapper script works as a systemd user service on a Linux tailnet
member — deploy/vault-mcp.service carries the install steps in its header
(copy to ~/.config/systemd/user/, systemctl --user enable --now vault-mcp,
and loginctl enable-linger so it survives logout).
Security model
On the tailnet the server runs with no auth; Tailscale is the auth layer.
That holds only while it binds the machine's Tailscale IP (what the wrapper
does) or loopback behind tailscale serve — never bind 0.0.0.0. If you
want TLS and a stable DNS name instead of the raw IP, the loopback +
tailscale serve --bg --https=443 127.0.0.1:8787 arrangement still works;
the direct bind is just fewer moving parts.
OAuth (optional)
For any deployment where network trust isn't enough (the public Bioconductor layer, or defense-in-depth on the tailnet), turn on OAuth:
export VAULT_MCP_OAUTH_CLIENT_ID=$(gcloud secrets versions access latest --secret=vault-mcp-oauth-client-id)
export VAULT_MCP_OAUTH_CLIENT_SECRET=$(gcloud secrets versions access latest --secret=vault-mcp-oauth-client-secret)
vault-mcp --http --auth google --base-url https://<machine>.<tailnet>.ts.netThis is the MCP spec's OAuth 2.1 flow (via FastMCP's OAuth proxy): clients
like Claude Code discover the server's auth metadata and pop the browser
login on their own — the claude mcp add --transport http ... line doesn't
change. Register <base-url>/auth/callback as an authorized redirect URI on
the OAuth client (Google Cloud console → Credentials).
Providers are a registry in src/vault_mcp/auth.py — google and github
are wired; adding another is one entry (all FastMCP providers take
client_id / client_secret / base_url). For launchd, use
deploy/vault-mcp-http.sh, which pulls the credentials from Google Secret
Manager at boot so secrets never sit in the plist.
Development
uv run pytest # fixture-vault tests + a read-only smoke test on the real vault
uv run vault-mcp # run the server on stdio
uv run python -m vault_mcp.eval # retrieval eval (query set: <vault>/.vault-mcp/eval.yaml)Retrieval benchmark
vault_mcp.eval runs a fixed query set against each search engine and reports
rank-of-first-expected-hit, hit rate, MRR, and latency per engine
(uv run python -m vault_mcp.eval). Query sets reference real note paths, so
they live inside the vault (<vault>/.vault-mcp/eval.yaml), never in this repo.
Representative results on a ~2,200-note vault, 11 queries spanning topical paraphrases, substring/exact-phrase/regex lookups, and digit-bearing identifiers:
engine | hit@5 | hit@10 | mean latency |
| 70% | 90% | ~100 ms |
| 40% | 40% | ~75 ms |
The engines are complementary, not redundant: substring, exact-phrase, and regex queries all miss in ranked mode and hit in exact mode (BM25 tokenizes and has no phrase syntax), while topical paraphrases do the reverse (literal matching can't cross word gaps). The first ranked query after a rebuild pays the lazy BM25 index build (~200 ms at this size); a warm full index rebuild is ~630 ms.
Known failure mode: natural-language questions against long notes — the FTS extension normalizes even title-restricted matches by whole-document length, so short notes outrank long ones with exact title matches. A title-term bonus is the planned fix (tracked on the wayfinder map).
Roadmap
v0.2 — consolidation agent. Nightly promotion pass modeled on memory consolidation: scan the episodic tier (journal, inbox), search existing memories, then propose creates/merges/updates for human approval — never silent rewrites of the long-term store.
Public community layer. Anonymous-read project memory for a community (first target: Bioconductor) — same primitives (files + index + MCP), plus a curated
INDEX.mdas the human orientation layer, served without exposing private state.Embeddings — only if needed. Added as another disposable index, and only once keyword + metadata + link retrieval demonstrably misses; not part of the ontology.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server that treats Obsidian vaults as knowledge graphs, enabling AI agents to traverse wikilinks, assemble token-budgeted context, and search with backlink awareness.31MIT
- Alicense-qualityAmaintenanceBuilt-in MCP server that gives AI agents direct access to an Obsidian vault for reading, writing, searching notes, and executing commands.1982,741MIT
- Alicense-qualityBmaintenanceAn MCP server that provides controlled read/write tools for managing local-first research memory in an Obsidian vault, enabling AI agents to maintain project context across sessions.71MIT
- Alicense-qualityAmaintenanceAn MCP server that enables AI agents to read, search, and write to your Obsidian vault.4MIT
Related MCP Connectors
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Shared long-term memory vault for AI agents with 20 MCP tools.
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/seandavi/vault-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server