An opinionated MCP server for capturing Claude conversations into an Obsidian vault.
Asking Claude to "save this thought" without structure produces inconsistent markdown blobs: drifting frontmatter, missing sections, ad-hoc filenames. vault-mcp closes that gap by making the convention itself a tool the model can read. Before writing, Claude calls read_capture_convention(), validates its output against the spec, and writes the file in the right place with the right shape. The convention lives in the vault (not in code), so editing it does not require redeploying the server.
capture_to_vault(...): validate a capture against the convention and write it into$WISSENSVAULT/inbox/captures/.list_recent_captures(limit=10): surface recent capture filenames so the model can orient itself before writing.read_capture_convention(): return the current convention text so the model can self-orient before writing.
pip install -r requirements.txt
export WISSENSVAULT="$HOME/Vaults/notizen"
python server.pyClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"vault": {
"command": "python",
"args": ["/absolute/path/to/server.py"],
"env": { "WISSENSVAULT": "/absolute/path/to/your/vault" }
}
}
}Claude.ai web (Settings, Connectors, Add custom connector): point it at the running server's URL once you front it with an HTTP transport (e.g. via fastmcp's ASGI mode).
WISSENSVAULT defaults to $HOME/Vaults/notizen if unset.
The server reads its convention at runtime from $WISSENSVAULT/conventions/capture-format.md. A copyable example sits at conventions/capture-format.example.md in this repo.
The convention defines: required frontmatter (created, type: capture, source, session_date, topic), optional frontmatter (project, tags, status, session_ref), the five mandatory body sections, and the filename pattern YYYY-MM-DD-{topic-kebab}.md.
Captures land in $WISSENSVAULT/inbox/captures/. Filename collisions on the same day get a numeric suffix.
This is what the author runs day-to-day. The body section names written into each markdown file (## Kontext, ## Inhalt, ## Verbindungen, ## Offene Fragen, ## Quelle) are German because the source vault is German; the slugify function uses opinionated German transliteration (ä to ae, ß to ss, etc.). The argument names on capture_to_vault mirror those German section names. There is no abstraction layer for swapping languages or schemas: fork the repo and edit server.py if you want a different shape. This is not meant as a general-purpose vault gateway.
MIT. See LICENSE.