markdown-vault-mcp
Integrate with Authelia for OIDC authentication to secure HTTP deployments of the MCP server.
Automatically commit and push changes to a Git repository on every write operation, with manual sync tools available.
Integrate with Keycloak for OIDC authentication to secure HTTP deployments of the MCP server.
Interact with an Obsidian vault: search, read, write, edit, and organize Markdown notes with full-text and semantic search, frontmatter-aware indexing, and attachment support.
Use Ollama for local embedding generation to enable semantic vector search across the vault.
Use OpenAI's API for embedding generation to enable semantic vector search across the vault.
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., "@markdown-vault-mcpsearch for meeting notes about project planning"
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.
markdown-vault-mcp
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 | 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,
searchreturns query-relevant snippets in thecontentfield by default (approximately 200 words). Passsnippet_words=0to recover the prior full-chunk behaviour, or useread(path, section=heading)to fetch a specific chunk after seeing a snippet. Documents are also re-chunked on nextreindexto honour the adaptiveMARKDOWN_VAULT_MCP_MAX_CHUNK_WORDSthreshold (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_ASKPASSOIDC 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
Related MCP server: mcp-markdown-vault
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 composesfetch+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) +
writewith 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. Thepara-capture-chatsprompt is the one-click version.Find missing links. Fire the
propose-linksprompt 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 composesread+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-mcpWith 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 embeddingsFrom source
git clone https://github.com/pvliesdonk/markdown-vault-mcp.git
cd markdown-vault-mcp
uv sync --all-extras --all-groupsDocker
docker pull ghcr.io/pvliesdonk/markdown-vault-mcp:latestThe 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>.mcpbClaude 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@pvliesdonkInstalls 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 serveWith Docker Compose
Copy an example env file:
cp examples/obsidian-readonly.env .envEdit
.envto setMARKDOWN_VAULT_MCP_SOURCE_DIRto the absolute path of your vault on the host.Start the service:
docker compose up -dCheck the logs:
docker compose logs -f markdown-vault-mcp
Example env files
File | Description |
| Obsidian vault, read-only, Ollama embeddings |
| Obsidian vault, read-write with git auto-commit |
| Obsidian vault, read-only, OIDC authentication (Authelia) |
| 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. Wire upstream version reporting (when applicable) inside the DOMAIN-UPSTREAM-START / DOMAIN-UPSTREAM-END sentinel in src/markdown_vault_mcp/server.py.
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 |
| — | Yes | Path to the markdown vault directory |
|
| No | Set to |
| in-memory | No | Path to the SQLite FTS5 index file; set for persistence across restarts |
| disabled | No | Path to the numpy embeddings file; required to enable semantic search |
|
| No | Path to the change-tracking state file |
| — | No | Comma-separated frontmatter fields to promote to the tag index for structured filtering |
| — | No | Comma-separated frontmatter fields required on every document; documents missing any are excluded from the index |
| — | No | Comma-separated glob patterns to exclude from scanning (e.g. |
|
| No | Relative folder path where note templates live (used by the |
| — | No | Path to a directory of |
|
| No | Maximum seconds an index-querying read tool waits for the IndexWriter to drain when called with |
|
| 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 |
Server identity
Variable | Default | Description |
|
| MCP server name shown to clients; useful for multi-instance setups |
| (auto) | System-level instructions injected into LLM context; defaults to a description that reflects read-only vs read-write state |
|
| HTTP endpoint path for streamable HTTP transport (used by |
|
| Unified key-value backend for HTTP session persistence (the |
| (unset) | Legacy alias for |
| (auto) | Override the Claude app domain used for MCP Apps iframe sandboxing. Auto-computed from |
|
| Log level for FastMCP internals ( |
|
| Rich |
Search and embeddings
Variable | Default | Description |
| auto-detect | Embedding provider: |
|
| Ollama server URL (not |
| — | OpenAI API key for the OpenAI embedding provider (not |
|
| OpenAI-compatible API base URL for embeddings |
|
| OpenAI-compatible embedding model name |
|
| Ollama embedding model name |
|
| Force Ollama to use CPU only |
|
| FastEmbed model name |
| FastEmbed default | FastEmbed model cache directory (in Docker, stored under |
|
| 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 reindex applies a new value. |
| (derived from model context) | Character cap the chunker enforces alongside |
|
| Maximum chunks returned per document in |
|
| Width of the snippet window (words) in |
|
| Down-weights longer chunks in ranking ( |
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.5for FastEmbed,nomic-embed-textfor Ollama); long-context models —nomic-ai/nomic-embed-text-v1.5(8192 tokens) for FastEmbed, orbge-m3:latestfor 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_URLset): server owns repo setup. On startup it clones intoSOURCE_DIRwhen empty, or validates existingorigin. Pull loop + auto-commit + deferred push are enabled.Unmanaged / commit-only mode (no
GIT_REPO_URL): writes are committed to a local git repo ifSOURCE_DIRis already a git checkout. No pull, no push.No-git mode: if
SOURCE_DIRis 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.
Variable | Default | Description |
| — | HTTPS remote URL for managed mode; enables clone/remote validation on startup |
|
| Username for HTTPS auth prompts ( |
| — | Token/password for HTTPS auth ( |
|
| Seconds between |
|
| Seconds of write-idle time before pushing; |
|
| Git committer name for auto-commits; set this in Docker where |
|
| Git committer email for auto-commits |
| — | OIDC claim key to use as the commit author name (e.g. |
| — | OIDC claim key to use as the commit author e-mail (e.g. |
|
| Enable Git LFS — runs |
| — | Shared secret for GitHub push-event webhook; when set, mounts |
File Watcher
Variable | Default | Description |
|
| Enable filesystem-event watcher for external changes; auto-disabled when git pull or webhook is active |
|
| Seconds 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.
Variable | Default | Description |
| (built-in list) | Comma-separated allowed extensions without dot (e.g. |
|
| Maximum attachment size in MB returned by |
|
| Maximum bytes returned by full-document |
Bearer token authentication
Simple static token auth for HTTP deployments. Set a single env var — clients must send Authorization: Bearer <token>.
Variable | Required | Description |
| 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_TOKENand 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 |
| Yes | Public base URL of the server (e.g. |
| Yes | OIDC discovery endpoint (e.g. |
| Yes | OIDC client ID registered with your provider |
| Yes | OIDC client secret |
| No | JWT signing key; required on Linux/Docker — the default is ephemeral and invalidates tokens on restart. Generate with |
| No | Expected JWT audience claim; leave unset if your provider does not set one |
| No | Comma-separated required scopes; default |
| No | Set |
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 |
|
| MCP transport: |
|
| Bind host for the |
|
| Port for the |
| env | MCP HTTP path for |
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/mcpEquivalent env-based config:
MARKDOWN_VAULT_MCP_HTTP_PATH=/vault/mcpFor reverse proxies, you can either:
Keep app path at
/mcpand 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/callbackindex
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 |
| Hybrid full-text + semantic search with optional frontmatter filters |
| Read a document or attachment by relative path |
| Create or overwrite a document or attachment |
| Replace text in a document — exact match, line-range, or scoped match with normalized fallback |
| Delete a document or attachment and its index entries |
| Rename/move a document or attachment, updating all index entries; pass |
| List indexed documents; pass |
| List all folder paths in the vault |
| List all unique frontmatter tag values |
| Force a full reindex of the vault |
| Get vault statistics (document count, chunk count, link health metrics, etc.) |
| Build or rebuild vector embeddings for semantic search |
| Check embedding provider and index status |
| Check background FTS build state ( |
| Find all documents that link to a given document |
| Find all links from a document, with existence check |
| Find all links pointing to non-existent documents |
| Find semantically similar notes by document path |
| Get the most recently modified notes |
| Get a consolidated context dossier for a note (backlinks, outlinks, similar, folder peers, tags, modified time) |
| Find all notes with no inbound or outbound links |
| Find the most-linked-to notes ranked by backlink count |
| Find the shortest path between two notes via BFS on the undirected link graph (max 10 hops) |
| List commits that touched a note, attachment, or the whole vault (git-backed vaults only) |
| Return a diff of a note or attachment between a reference commit/timestamp and HEAD; binary attachments return a |
| 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 |
| Download a file from a URL and save it to the vault as a note or attachment (MCP-to-MCP transfer) |
| Mint a one-time capability URL to download a vault note or attachment (HTTP/SSE only; |
| Mint a one-time capability URL to upload bytes to a fixed vault path (HTTP/SSE only; |
| Open the vault explorer SPA in a supporting MCP Apps client |
| Open 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.
URI | Description |
| Current vault configuration (source dir, indexed fields, read-only state, etc.) |
| Vault statistics (document count, chunk count, embedding count, etc.) |
| All frontmatter tag values grouped by indexed field |
| Tag values for a specific indexed frontmatter field (template) |
| All folder paths in the vault |
| Table of contents (heading outline) for a specific document (template) |
| Top 10 semantically similar notes for a document (template) |
| 20 most recently modified notes with ISO timestamps |
| 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 |
|
| Read a document and produce a structured summary with key themes and takeaways |
|
| Search for a topic, synthesize findings, and create a new note at |
|
| Analyze a document and suggest improvements using |
|
| Discover templates (if needed), read a template, gather user values, and write a new note |
|
| Find related notes via search and suggest cross-references as markdown links |
|
| Read two documents and produce a side-by-side comparison |
|
| Scan a candidate set of notes (a folder, |
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.
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 frontmatter table and "Send to Claude" button |
The two primary tools exposed to MCP Apps clients are:
Tool | Description |
| Returns the vault tree structure for the Vault Browser view |
| 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 (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.
Variable | Default | Description |
|
| Default token lifetime (seconds) when the caller omits |
|
| Maximum permitted TTL; any larger |
|
| 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_EXCLUDEpatterns are also applied to attachments.
Authentication
The server supports four auth modes:
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)
Bearer token — set
MARKDOWN_VAULT_MCP_BEARER_TOKENto a secret stringOIDC — full OAuth 2.1 flow via
OIDC_CONFIG_URL,OIDC_CLIENT_ID,OIDC_CLIENT_SECRET, andBASE_URLNo 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:
Secret | Used by | How to generate |
|
| Fine-grained PAT at https://github.com/settings/personal-access-tokens/new with |
|
| https://codecov.io — sign in with GitHub, add the repo, copy the upload token from the repo settings page. |
|
| Run |
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-groupsuv 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, andget_context.similarnow return grouped results. Each file appears once with asectionslist; the flatcontent,heading, andscorefields have moved inside eachSectionHit. Library consumers must update iteration:# Before: result.content, result.heading # After: result.sections[0].content, result.sections[0].headingMARKDOWN_VAULT_MCP_CHUNKS_PER_FILEreplacesMARKDOWN_VAULT_MCP_CHUNKS_PER_DOC.SimilarItemis removed; useGroupedResult(also re-exported at the package level).MARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MBdefault 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, setMARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MB=10explicitly.MARKDOWN_VAULT_MCP_MAX_NOTE_READ_BYTESis a new env var (default 256 KB). Whole-document.mdreads above this raiseValueError. Partial reads viaread(path, section=heading)bypass the cap.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
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/pvliesdonk/markdown-vault-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server