mcp-markdown-kb
by Rodzman
README.md
# mcp-markdown-kb
An [MCP](https://modelcontextprotocol.io) server that turns any folder of
Markdown notes into a knowledge base an AI assistant can search and read.
Point it at your Obsidian vault, your `docs/` folder, or a pile of meeting
notes, and Claude can find the right note, follow links between notes, and
quote from them.
No database, no embeddings, no API keys: everything is indexed in memory at
startup with a small BM25 implementation written for this project.
## What it exposes
| Tool | What it does |
| --- | --- |
| `search_notes` | BM25 full-text search. Title, tags and headings are weighted above body text. Optional `tag` filter. Returns path, score and a snippet per hit. |
| `read_note` | Full body plus metadata (title, tags, headings, outgoing links, word count, modified time). |
| `list_notes` | Every note, optionally filtered by tag. |
| `get_backlinks` | Notes that link to a given note through `[[wikilinks]]` or relative `.md` links. |
| `list_tags` | Tag cloud with counts. |
| `reindex` | Re-scan the folder after you edit notes. |
Every note is also published as a resource at `note:///<relative/path.md>`
with `text/markdown` content, so clients that support resources can attach a
note directly to the conversation.
### Note format
Plain Markdown works as-is. The parser additionally understands:
- **Frontmatter** between `---` fences: `title`, `tags: [a, b]` or a `- item` list,
and any other `key: value` pairs (kept in `frontmatter`). This is a small
YAML subset, not a full YAML parser.
- **Titles**: frontmatter `title`, else the first `#` heading, else the file name.
- **Links**: `[[Wiki links]]`, `[[Wiki links|alias]]`, `[[Note#heading]]`, and
`[text](relative/path.md)`. Wikilinks resolve by title, file name, or path,
case-insensitively.
Hidden folders and `node_modules` are skipped.
## Running it
Requires Node 22.18+.
```sh
npm install
npm run build
node dist/cli.js ~/notes # or: MARKDOWN_KB_DIR=~/notes node dist/cli.js
```
The server speaks MCP over stdio. Logs go to stderr so they never corrupt the
protocol stream.
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"markdown-kb": {
"command": "node",
"args": ["/absolute/path/to/mcp-markdown-kb/dist/cli.js", "/absolute/path/to/notes"]
}
}
}
```
### Claude Code
```sh
claude mcp add markdown-kb -- node /absolute/path/to/mcp-markdown-kb/dist/cli.js /absolute/path/to/notes
```
Then ask things like "what do my notes say about rate limiting?" or "which
notes link to the API gateway design doc?".
## Development
```sh
npm run typecheck # tsc over source and tests
npm test # node --test, no test framework dependency
npm run build # emits dist/
npm run dev -- ./test/fixtures/notes # run from source, no build step
```
Tests spin up the real server and a real MCP client joined by the SDK's
`InMemoryTransport`, so the protocol layer (schemas, tool listing, resource
templates) is exercised end to end without spawning a process.
### How the pieces fit
```
src/markdown.ts parse one note: frontmatter, title, headings, tags, links
src/search.ts tokenizer + BM25 index + snippet extraction
src/kb.ts walk the folder, build the index, resolve links, backlinks
src/server.ts McpServer: tools and the note:/// resource template
src/cli.ts argument handling and the stdio transport
```
Design notes:
- `read_note` and the resource handler only accept paths that resolve inside
the root folder, so a client cannot read arbitrary files.
- Tools are annotated (`readOnlyHint`) so hosts can skip confirmation prompts
for the read-only ones.
- Only two runtime dependencies: the MCP SDK and Zod (which the SDK uses for
input validation and JSON Schema generation).
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues