Skip to main content
Glama
wirux

mcp-markdown-vault

πŸ“ 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


πŸ’‘ Why this server?

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

Differentiator

Details

🚫

No app or plugins required

Most 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 setup

Hybrid 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 editing

remark 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-agnostic

Obsidian vaults, Logseq graphs, Dendron workspaces, Foam, or any plain folder of .md files. If it's markdown, it works.

πŸ“¦

Single package, no infrastructure

Unlike 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

Feature

Description

πŸ—‚οΈ

Headless vault ops

Read, create, update, edit, delete .md notes with strict path traversal protection

πŸ“‘

Read by heading

Read a single section by heading title β€” returns only content under that heading (up to the next same-level heading), saving context window space

πŸ“¦

Bulk read

Read multiple files and/or heading-scoped sections in a single call β€” reduces MCP round-trips with per-item fault tolerance

πŸ”¬

Surgical editing

AST-based patching targets specific headings or block IDs β€” never overwrites the whole file

πŸ”

Fragment retrieval

Heading-aware chunking + TF-IDF + proximity scoring returns only relevant sections

πŸ“‚

Scoped search

Optional directory filter for global_search and semantic_search β€” restrict results to specific folders to reduce noise

🧠

Semantic search

Hybrid vector + lexical search with background auto-indexing

⚑

Zero-setup embeddings

Built-in local embeddings via @huggingface/transformers β€” Ollama optional

πŸ”„

Workflow tracking

Petri net state machine with contextual LLM hints

🌐

Dual transport

Stdio (single client) or SSE over HTTP (multi-client, Docker-friendly)

✏️

Freeform editing

Line-range replacement and string find/replace as AST fallback

🏷️

Frontmatter management

AST-based read and update of YAML frontmatter β€” safely manage tags, statuses, and metadata without corrupting file structure

πŸ‘€

Dry-run / diff preview

Preview any edit operation as a unified diff without saving β€” set dryRun=true on any edit action

πŸ“

Templating / scaffolding

Create new notes from template files with {{variable}} placeholder injection β€” refuses to overwrite existing files

πŸ—ΊοΈ

Vault overview

Structural map of the vault β€” total file count, recursive folder tree with file counts and last modification dates per folder

πŸ“¦

Batch edit

Apply multiple edit operations in a single call β€” sequential execution, stops on first error, supports dryRun, max 50 ops

πŸ”—

Backlinks index

Find all notes linking to a given path β€” supports wikilinks and markdown links with line numbers and context snippets

🎯

Typo resilience

Levenshtein-based fuzzy matching for edit operations


πŸ› οΈ MCP Tools

Tool

Actions

Description

πŸ“ vault

list read create update delete stat create_from_template

Full CRUD for vault notes + template scaffolding

✏️ edit

append prepend replace line_replace string_replace frontmatter_set batch

AST-based patching + freeform fallback + frontmatter update + batch edit (supports dryRun diff preview)

πŸ‘οΈ view

search global_search semantic_search outline read frontmatter_get bulk_read backlinks

Fragment retrieval, cross-vault search, hybrid semantic search, read by heading, frontmatter read, bulk read, backlinks

πŸ”„ workflow

status transition history reset

Petri net state machine control

βš™οΈ system

status reindex overview

Server 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.

🐳 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

Mode

Use case

How it works

πŸ“‘ stdio (default)

Single-client desktop apps (Claude Desktop)

Reads/writes stdin/stdout; 1:1 connection

🌊 sse

Multi-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

Variable

Default

Description

VAULT_PATH

/vault

Markdown vault directory

MCP_TRANSPORT_TYPE

stdio

stdio (single client) or sse (multi-client HTTP)

PORT

3000

HTTP port (SSE mode only)

OLLAMA_URL

(unset)

Set to enable Ollama embeddings

OLLAMA_MODEL

nomic-embed-text

Ollama embedding model name

OLLAMA_DIMENSIONS

768

Ollama 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:

Workflow

Trigger

What it does

PR Check

Pull request to main

Lint β†’ Build β†’ Test

Release

Push to main

Lint β†’ 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

Install Server
A
security – no known vulnerabilities
A
license - permissive license
A
quality - A tier

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/wirux/mcp-markdown-vault'

If you have feedback or need assistance with the MCP directory API, please join our Discord server