mdvault-mcp
Supports a Logseq pages folder as a directory of Markdown files, providing search, note reading, wikilink and backlink navigation, tag/frontmatter queries, and link-aware note refactoring with dry-run rename support.
Works directly with an Obsidian-style Markdown vault without requiring Obsidian to be running, enabling AI agents to search notes, read parsed frontmatter and links, inspect backlinks and outgoing links, query tags and properties, detect broken or ambiguous links, create/append/edit notes, and safely rename or move notes while updating wikilinks and Markdown links.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
mdvault-mcp
Let your AI work with a folder of markdown notes the way you do: search it, follow the links, query the properties, and refactor it without breaking anything.
mdvault-mcp is an MCP server for an Obsidian-style vault, a Logseq pages folder, or any directory of .md files. It does not need Obsidian running and talks to the files directly.
Why another notes server? Several Obsidian MCP servers exist already (for example StevenStavrakis/obsidian-mcp, laurentiudanielgi-coder/obsidian-mcp, farmerajf/obsidian-mcp-server), and some of them already update links on rename. This one is built around not damaging your notes, and says so with tests:
Rename is a reviewable refactor.
rename_notedefaults to a dry run that lists every file and every link line it would change, then reports broken links before and after. Its tests re-parse the whole vault in a fresh index after each rename and check that every link still resolves to the same note.Ambiguity is reported, never guessed. Two notes called
Meeting Notesin different folders make[[Meeting Notes]]ambiguous. You get both candidate paths, and ambiguous links are left alone by renames.Byte-exact edits. Line endings (CRLF stays CRLF), BOM, frontmatter comments and formatting are preserved. Edits are text splices, never a re-serialised file.
Confined, atomic, no surprise overwrites. Symlink and Windows junction escapes are blocked (tested), dot-folders like
.gitand.obsidianare never touched, files are written via temp file +os.replace, and nothing is overwritten withoutoverwrite=true.Fast on big vaults. In-process BM25 search; parsed notes are cached in SQLite (outside your vault) keyed by mtime. Tested on a generated 5,000-note vault.
Turkish-friendly.
sekerfindsŞeker; links are case-insensitive and Unicode-normalised.
Python, one dependency (mcp), runs with uvx.
What it looks like
Real output from the test vault:
> rename_note "Beta Plan" -> "Beta Roadmap" (dry_run defaults to true)
DRY RUN, nothing written.
Rename: Projects/Beta/Beta Plan.md -> Projects/Beta/Beta Roadmap.md
3 link(s) in 2 file(s) would be updated:
Home.md (1 link)
L8: Welcome. See [[Projects/Alpha/Plan]] and [[Beta Plan|the beta]].
-> Welcome. See [[Projects/Alpha/Plan]] and [[Beta Roadmap|the beta]].
Projects/Alpha/Alpha Plan.md (2 links)
L14: Links: [[Home]], [[Alpha Plan#Goal]], [[Beta Plan#^b1|beta block]], [[Meeting Notes]].
-> Links: [[Home]], [[Alpha Plan#Goal]], [[Beta Roadmap#^b1|beta block]], [[Meeting Notes]].
L15: Markdown: [home](../../Home.md), [beta](../Beta/Beta%20Plan.md#top), ...
-> Markdown: [home](../../Home.md), [beta](../Beta/Beta%20Roadmap.md#top), ...
Call again with dry_run=false to apply.
> read_note "Meeting Notes"
'Meeting Notes' is ambiguous: 2 notes match. Pass the full path of one of them:
- Areas/Meeting Notes.md
- Projects/Meeting Notes.md
> note_links "Alpha Plan" direction=in
Backlinks to Projects/Alpha/Alpha Plan.md: 3 links from 2 notes
Home.md:10 (embed) Embed: ![[diagram.png]] and ![[Alpha Plan]].
Projects/Beta/Beta Plan.md:8 [2 links] Back to [[Alpha Plan]] and [alpha](../Alpha/Alpha%20Plan.md).Related MCP server: Obsidian MCP Server
Install
You need uv. Point the server at your notes folder.
Claude Code
claude mcp add notes -- uvx mdvault-mcp --vault "C:\Users\you\Documents\Notes"Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"notes": {
"command": "uvx",
"args": ["mdvault-mcp", "--vault", "C:\\Users\\you\\Documents\\Notes"]
}
}
}Add "--read-only" to the args to disable every writing tool. MDVAULT_PATH and MDVAULT_READ_ONLY=1 work instead of the flags. MDVAULT_CACHE_DIR moves the index cache (default: %LOCALAPPDATA%\mdvault-mcp, ~/Library/Caches/mdvault-mcp or ~/.cache/mdvault-mcp).
Tools
Tool | What it does |
| Note count, top tags, most linked notes, orphans, broken and ambiguous links, notes with bad frontmatter. |
| BM25-ranked full text with a snippet and line number. Optional |
| By path, name or |
| Backlinks (with the surrounding line) and/or outgoing links with where each resolves. |
| Tag (nested tags included) and frontmatter queries: |
| Broken links with did-you-mean, and ambiguous links with all candidates. |
| New note with optional frontmatter; refuses to overwrite; warns about duplicate names. |
| Append to a note, or to today's daily note ( |
| Exact-text replace that must match once; |
| Rename or move and update every link; dry run by default. |
Links understood: [[Note]], [[Note#Heading]], [[Note#^block]], [[Note|alias]], ![[embed]], [[Folder/Note]], [text](path/Note.md#h) (relative, /rooted, %20-encoded, <angle>). Links inside code fences and inline code are ignored.
Try asking
"Give me an overview of my vault. What is broken or orphaned?"
"Search my notes for kernel scheduler and show me the best match."
"Which notes link to my Roadmap note, and what do they say around the link?"
"List every note with status=draft and the tag project, due before December."
"Rename 'Q3 Plan' to 'Q4 Plan'. Show me the dry run first."
"Add '- call the dentist' to today's daily note."
"In the 'Alpha Plan' note, change the owner line to 'owner: fadi'."
"Are there two notes with the same name? Which links are ambiguous?"
Security
The server reads and writes files, so the limits are deliberate:
One folder. Every path is resolved against the vault root.
.., absolute paths, drive letters, and any component starting with.(.git,.obsidian,.trash) are refused. Symlinks and Windows junctions are never followed when scanning, and any write path that passes through one is refused, even when it points back inside the vault.No silent overwrite.
create_noteneedsoverwrite=true;rename_notenever overwrites;edit_noteneeds the old text to match exactly once.Atomic. Each file is written to a temp file in its folder, fsynced, then moved into place with
os.replace. A rename stages every changed file first, re-checks that none changed while planning, and only then moves anything.Not UTF-8? Untouched. A note that is not valid UTF-8 is reported and never rewritten.
File names stay portable. New names with characters Windows rejects (
: ? * | " < >), reserved device names or trailing dots are refused.--read-onlyremoves the ability to write at all.
The index cache lives outside the vault and holds parsed note text (words and link positions), so treat it like your notes.
Limitations
Reference-style links (
[x]: path), raw HTML links, Logseqkey:: valueproperties and((block-uuid))references are not parsed.Frontmatter is a practical YAML subset: maps, lists, flow collections, quoted strings, numbers, booleans,
|and>blocks. Anchors, tags and multi-line plain scalars are reported as errors on that note (it is still searchable and linkable).Frontmatter
aliasesare not used to resolve links (Obsidian does not resolve them either).A rename rewrites the link target only. If a link's visible text was the old name (
[[Old]]), it now shows the new name, as in Obsidian; use[[Old|text]]to keep the display.Renames apply to notes, not attachments.
If the vault changes on disk between tool calls (Obsidian sync, your editor), the next call re-scans it. There is no file watcher.
Cold indexing is CPU-cheap (about 0.6 ms per note to parse) but reads every file once; on a Windows machine with real-time antivirus scanning, 5,000 freshly written notes took about 25 s on the first run. A restart reads the cache in about 0.2 s.
Development
uv sync --extra test
uv run pytest -m "not perf" # fast suite
uv run pytest tests/test_perf.py -s # 5,000-note vault
uv run ruff check src tests && uv run mypy --strict srcCompanion tutorial that builds a minimal version from scratch: mdvault-mcp-the-hard-way.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Search, read, and safely update Markdown notes in your connected Phasoric knowledge vaults.
Search your Obsidian vault to quickly find notes by title or keyword, summarize related content, a…
Notes and memory assistant: one Markdown vault that Claude, ChatGPT and any MCP client can share.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables comprehensive management of Obsidian vaults with full CRUD operations, advanced search, link/tag extraction, backlinks discovery, frontmatter editing, and template-based note creation through natural language.16MIT
- FlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to read, write, search, and navigate Obsidian vault notes with support for CRUD operations, full-text search, graph navigation, daily notes, and frontmatter management.3,647 npm-
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to manage Obsidian vaults through full CRUD operations, wikilink management, and section-level manipulation. It supports frontmatter editing, tag-based searching, and automated link updates to maintain vault integrity.MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to search, read, and traverse Markdown note vaults (Obsidian-compatible) with full-text search, backlinks, knowledge graphs, and a persistent memory system for cross-session context.1612 npm4MIT