MCP Hub
Back to servers

mcp-markdown-vault

Headless semantic MCP server for Obsidian, Logseq, Dendron, Foam, and any markdown folder. Features built-in hybrid semantic search, surgical AST editing, template scaffolding, zero-config local embeddings, and workflow tracking.

glama
Updated
Apr 14, 2026

📁 Markdown Vault MCP Server

Headless semantic MCP server for Obsidian, Logseq, Dendron, Foam, and any folder of markdown files.

npm install and point it at a folder. Hybrid search, AST editing, zero-config embeddings. No app, no plugins, no API keys.

CI / Release PR Check npm version Docker License: MIT TypeScript Node.js Tests mcp-markdown-vault MCP server

Markdown Vault MCP Server Demo


💡 Why this server?

TL;DR — One npx command. No running app. No plugins. No vector DB. Semantic search works out of the box.

DifferentiatorDetails
🚫No app or plugins requiredMost Obsidian MCP servers (mcp-obsidian, obsidian-mcp-server) need Obsidian running with the Local REST API plugin. This server reads and writes .md files directly — point it at a folder and go.
🧠Built-in semantic search, zero setupHybrid search: cosine-similarity vectors + TF-IDF + word proximity. Local embeddings (@huggingface/transformers, all-MiniLM-L6-v2, 384d) download on first run. No API keys, no external services. Ollama optional for higher quality.
🔬Surgical AST-based editingremark AST pipeline patches specific headings or block IDs without touching the rest of the file. Freeform line-range & string replace as fallback. Levenshtein fuzzy matching handles LLM typos.
🔓Tool-agnosticObsidian vaults, Logseq graphs, Dendron workspaces, Foam, or any plain folder of .md files. If it's markdown, it works.
📦Single package, no infrastructureUnlike Python alternatives that need ChromaDB or other vector stores, everything runs in one Node.js process. npx @wirux/mcp-markdown-vault and you're running. Docker image available.

💎 Obsidian · 📓 Logseq · 🌳 Dendron · 🫧 Foam · 📂 Any .md folder


✨ Features

FeatureDescription
🗂️Headless vault opsRead, create, update, edit, delete .md notes with strict path traversal protection
📑Read by headingRead a single section by heading title — returns only content under that heading (up to the next same-level heading), saving context window space
📦Bulk readRead multiple files and/or heading-scoped sections in a single call — reduces MCP round-trips with per-item fault tolerance
🔬Surgical editingAST-based patching targets specific headings or block IDs — never overwrites the whole file
🔍Fragment retrievalHeading-aware chunking + TF-IDF + proximity scoring returns only relevant sections
📂Scoped searchOptional directory filter for global_search and semantic_search — restrict results to specific folders to reduce noise
🧠Semantic searchHybrid vector + lexical search with background auto-indexing
Zero-setup embeddingsBuilt-in local embeddings via @huggingface/transformers — Ollama optional
🔄Workflow trackingPetri net state machine with contextual LLM hints
🌐Dual transportStdio (single client) or SSE over HTTP (multi-client, Docker-friendly)
✏️Freeform editingLine-range replacement and string find/replace as AST fallback
🏷️Frontmatter managementAST-based read and update of YAML frontmatter — safely manage tags, statuses, and metadata without corrupting file structure
👀Dry-run / diff previewPreview any edit operation as a unified diff without saving — set dryRun=true on any edit action
📝Templating / scaffoldingCreate new notes from template files with {{variable}} placeholder injection — refuses to overwrite existing files
🗺️Vault overviewStructural map of the vault — total file count, recursive folder tree with file counts and last modification dates per folder
📦Batch editApply multiple edit operations in a single call — sequential execution, stops on first error, supports dryRun, max 50 ops
🔗Backlinks indexFind all notes linking to a given path — supports wikilinks and markdown links with line numbers and context snippets
🎯Typo resilienceLevenshtein-based fuzzy matching for edit operations

🛠️ MCP Tools

ToolActionsDescription
📁 vaultlist read create update delete stat create_from_templateFull CRUD for vault notes + template scaffolding
✏️ editappend prepend replace line_replace string_replace frontmatter_set batchAST-based patching + freeform fallback + frontmatter update + batch edit (supports dryRun diff preview)
👁️ viewsearch global_search semantic_search outline read frontmatter_get bulk_read backlinksFragment retrieval, cross-vault search, hybrid semantic search, read by heading, frontmatter read, bulk read, backlinks
🔄 workflowstatus transition history resetPetri net state machine control
⚙️ systemstatus reindex overviewServer health, indexing info, vault structure overview

All tool responses include contextual hints based on the current workflow state.


🚀 Quick Start

Prerequisites

📦 Install from NPM

npm install -g @wirux/mcp-markdown-vault

Then run directly:

VAULT_PATH=/path/to/your/vault markdown-vault-mcp

🔌 MCP Client Configuration

Add to your MCP client config (e.g. Claude Desktop, Claude Code):

{
  "mcpServers": {
    "markdown-vault": {
      "command": "npx",
      "args": ["-y", "@wirux/mcp-markdown-vault"],
      "env": {
        "VAULT_PATH": "/path/to/your/vault"
      }
    }
  }
}

npx -y auto-installs the package if not already present — no global install needed.

Try it in the browser: You can test this server directly at Glama Inspector — no local install required.

🐳 Docker

Pull the pre-built multi-arch image from GitHub Container Registry:

docker pull ghcr.io/wirux/mcp-markdown-vault:latest

Or use Docker Compose:

docker compose up

Edit docker-compose.yml to point at your markdown vault directory. The default compose file uses SSE transport on port 3000.

🛠️ Development (from source)

git clone https://github.com/Wirux/mcp-obsidian.git
cd mcp-obsidian
npm install
npm run build
VAULT_PATH=/path/to/your/vault node dist/index.js

🌐 Transport Modes

ModeUse caseHow it works
📡 stdio (default)Single-client desktop apps (Claude Desktop)Reads/writes stdin/stdout; 1:1 connection
🌊 sseMulti-client setups (Docker, Claude Code)HTTP server with SSE streams; one connection per client

SSE starts an HTTP server on PORT (default 3000):

  • GET /sse — establishes an SSE stream (one per client)
  • POST /messages?sessionId=... — receives JSON-RPC messages
MCP_TRANSPORT_TYPE=sse PORT=3000 VAULT_PATH=/path/to/vault npx @wirux/mcp-markdown-vault

Each SSE client gets its own workflow state. Shared resources (vault, vector index, embedder) are reused across all connections.


🧠 Embedding Providers

The server selects an embedding provider automatically:

OLLAMA_URL set?Ollama reachable?Provider used
❌ No🏠 Local (@huggingface/transformers, all-MiniLM-L6-v2, 384d)
✅ Yes✅ Yes🦙 Ollama (nomic-embed-text, 768d)
✅ Yes❌ No🏠 Local (fallback with warning)

No configuration needed for local embeddings — the model downloads on first use and is cached automatically.


⚙️ Configuration

VariableDefaultDescription
VAULT_PATH/vaultMarkdown vault directory
MCP_TRANSPORT_TYPEstdiostdio (single client) or sse (multi-client HTTP)
PORT3000HTTP port (SSE mode only)
OLLAMA_URL(unset)Set to enable Ollama embeddings
OLLAMA_MODELnomic-embed-textOllama embedding model name
OLLAMA_DIMENSIONS768Ollama embedding vector dimensions

🏗️ Architecture

Clean Architecture with strict layer separation:

src/
├── domain/           🔷 Errors, interfaces (ports), value objects
├── use-cases/        🔶 Business logic (AST, chunking, search, workflow)
├── infrastructure/   🟢 Adapters (file system, Ollama, vector store)
└── presentation/     🟣 MCP tool bindings, transport layer (stdio/SSE)

See CLAUDE.md for detailed architecture docs and CHANGELOG.md for implementation history.


🚢 CI/CD & Release

Fully automated via GitHub Actions and Semantic Release:

WorkflowTriggerWhat it does
PR CheckPull request to mainLint → Build → Test
ReleasePush to mainLint → Test → Semantic Release (NPM + GitHub Release) → Docker build & push to ghcr.io

🧪 Testing

318 tests across 31 files, written test-first (TDD).

npm test                                          # Run all tests
npx vitest run src/use-cases/ast-patcher.test.ts  # Single file
npm run test:watch                                # Watch mode
npm run test:coverage                             # Coverage report

Tests use real temp directories for file system operations and in-memory MCP transport for integration tests. No external services required.


🔒 Security

  • 🛡️ All file paths validated through SafePath value object before any I/O
  • 🚫 Blocks path traversal: ../, URL-encoded (%2e%2e), double-encoded (%252e), backslash, null bytes
  • ✍️ Atomic file writes (temp file + rename) prevent partial writes
  • 👤 Docker container runs as non-root user

📄 License

MIT

Reviews

No reviews yet

Sign in to write a review