AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Markdown Vault Mcp

mcp-pvliesdonk-markdown-vault-mcp · by pvliesdonk

Generic markdown collection MCP server with FTS5 + semantic search, frontmatter-aware indexing, and incremental reindexing

No reviews yet
0 installs
43 views
0.0% view→install

Install

$ agentstack add mcp-pvliesdonk-markdown-vault-mcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-pvliesdonk-markdown-vault-mcp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Markdown Vault Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

markdown-vault-mcp

[](https://github.com/pvliesdonk/markdown-vault-mcp/actions/workflows/ci.yml) [](https://codecov.io/gh/pvliesdonk/markdown-vault-mcp) [](https://pypi.org/project/markdown-vault-mcp/) [](https://pypi.org/project/markdown-vault-mcp/) [](LICENSE) [](https://github.com/pvliesdonk/markdown-vault-mcp/pkgs/container/markdown-vault-mcp) [](https://pvliesdonk.github.io/markdown-vault-mcp/) [](https://pvliesdonk.github.io/markdown-vault-mcp/latest/llms.txt) [](https://deepwiki.com/pvliesdonk/markdown-vault-mcp) [](https://github.com/pvliesdonk/fastmcp-server-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
  • 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 — 32 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](examples/para/prompts/para-capture-chats.md) 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 ` 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](docs/deployment/docker.md#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-.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:

``bash cp examples/obsidian-readonly.env .env ``

  1. Edit .env to set MARKDOWN_VAULT_MCP_SOURCE_DIR to the absolute path of your vault on the host.
  1. Start the service:

``bash docker compose up -d ``

  1. Check the logs:

``bash 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](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 | — | No | Comma-separated frontmatter fields to promote to the tag index for structured filtering | | 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_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](#user-defined-prompts)) | | 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_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 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_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))). |

> 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

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.