Obsidian MCP Server
Exposes a folder of Markdown notes (Obsidian vault or plain .md files) to LLM clients like Claude and ChatGPT via Streamable HTTP, with tools for searching, reading, writing, and managing notes directly on the filesystem.
README
Obsidian MCP Server
A remote MCP server that exposes a folder of Markdown notes — an Obsidian vault, or just a plain folder of .md files — to LLM clients like Claude and ChatGPT. It talks Streamable HTTP, operates directly on the filesystem, and has no dependency on the Obsidian app itself.
MCP client --HTTP--> server.mjs (127.0.0.1:MCP_PORT) --node:fs--> VAULT_ROOT
The server only binds to 127.0.0.1. It does not do TLS termination, authentication, or expose itself to the network — that's a separate concern, left to whatever you put in front of it (see Exposing it remotely).
What it can do
| Tool | Scope |
|---|---|
obsidian_search |
Full-text search across the vault (or a folder), with context, folder scoping, case sensitivity, and per-file match counts |
obsidian_list_notes |
List files/folders at a path |
obsidian_read_note |
Read any note; include_metadata adds frontmatter, tags, headings, word count |
obsidian_read_notes |
Batch-read up to 20 notes in one call; a missing note errors per-path, not the whole batch |
obsidian_recent_notes |
List the most recently modified notes, newest first |
obsidian_vault_tree |
Folder tree overview, to orient without many list calls |
obsidian_query_notes |
Structured metadata search: filter by folder, tags, frontmatter fields, or modified date |
obsidian_list_tags |
All tags in use (frontmatter + inline #tag) with usage counts, to avoid inventing near-duplicate tags |
obsidian_list_tasks |
Checkbox inventory (- [ ] / - [x]) across the vault, with folder/status filters |
obsidian_get_backlinks |
Outgoing links + backlinks for a note, resolved the way Obsidian resolves [[wikilinks]] |
obsidian_create_inbox_note |
Create a note in Inbox/ (fails if it exists) |
obsidian_append_inbox_note |
Append to a note in Inbox/ (creates if absent) |
obsidian_append_daily_note |
Append to today's (or a given date's) daily note, creating it if absent |
obsidian_capture_inbox |
Save a standardized capture (conversation, excerpt, decision, todo, etc.) into Inbox/ |
obsidian_update_note |
Edit an existing note anywhere in the vault — full replace, exact-string replace, or insert under a heading — fails if the note doesn't exist |
obsidian_move_note |
Move/rename a note anywhere in the vault, rewriting every other note's [[wikilink]] to it (alias/heading/embed preserved) — fails if the destination exists |
obsidian_delete_note |
Soft-delete a note into .trash/ (reversible); reports notes that link to it so you know what's now dangling |
Most of the metadata tools (query_notes, list_tags, list_tasks, get_backlinks) ride on one internal vault index that walks the vault once and caches parsed frontmatter/tags/headings/links/tasks per file, keyed by (path, mtime), so repeat calls only re-parse notes that actually changed.
Write model
- New notes can only be created inside
Inbox/(configurable). The one exception isobsidian_append_daily_note, which may create today's daily note outsideInbox/because that path is fully deterministic and the write is append-only. - Editing, moving/renaming, and deleting existing notes is allowed anywhere in the vault.
- Delete is soft:
obsidian_delete_notemoves the file into.trash/instead of unlinking it, so it's always recoverable by hand..trash/is excluded from every listing/search tool. - Move is wikilink-safe:
obsidian_move_noterewrites every other note's[[wikilink]]/![[embed]]that resolves to the moved note (bare filename if that's still unique, otherwise the full path), preserving aliases and#headinganchors. - Path safety: every tool resolves paths through one canonical helper that rejects absolute paths,
..traversal, and symlinks pointing outsideVAULT_ROOT. - Writes are atomic: temp file + rename in the same directory, so a client watching the folder (Obsidian, a sync client) never sees a partial write.
Configuration
Copy .env.example to .env and fill in:
| Variable | Default | Meaning |
|---|---|---|
VAULT_ROOT |
— (required) | Absolute path to the vault folder. |
MCP_PORT |
3001 |
Port the server listens on (loopback only). |
INBOX_FOLDER |
Inbox |
Where new-note creation is confined to. |
CAPTURE_WRITE_JSON_SIDECAR |
true |
Whether obsidian_capture_inbox also writes a .json sidecar next to the Markdown. |
CAPTURE_EMBED_RAW_JSON |
false |
Whether to embed the raw capture payload as a JSON block in the Markdown. |
CAPTURE_COLLISION_BEHAVIOR |
suffix |
suffix | overwrite | error — what to do if a capture's generated filename already exists. |
DAILY_NOTE_FOLDER / DAILY_NOTE_FORMAT |
— | Fallback for obsidian_append_daily_note only if .obsidian/daily-notes.json doesn't exist (the server reads your real Daily Notes plugin settings first). |
Running it
npm install
cp .env.example .env # set VAULT_ROOT
node server.mjs
curl -s http://127.0.0.1:3001/health # {"ok":true}
That's the whole server: one Node process, no database, no build step. npm run start does the same thing.
Exposing it remotely
Claude web/mobile and ChatGPT connect to MCP servers over the network, not over stdio like Claude Desktop — so using this from those clients means putting a real HTTPS URL with authentication in front of 127.0.0.1:MCP_PORT. This server has no authentication of its own; that's intentionally left to whatever sits in front of it. /mcp should be behind that auth layer; /health is safe to leave open, it returns nothing but {"ok":true}.
Once the client can reach the URL, add it as a custom connector (Claude) or a developer-mode connector (ChatGPT — standard ChatGPT connectors only invoke tools literally named search/fetch and won't show any actions here, since this server intentionally doesn't add those aliases).
A note on cloud-synced vaults
If VAULT_ROOT lives on a cloud-synced drive (iCloud Drive, Dropbox, OneDrive, etc.), a file can be an evicted placeholder that isn't actually on disk yet. readFileSync on one either blocks while it downloads or errors. The search/read tools handle this per-file — an unreadable note is reported individually rather than failing the whole call — but if it becomes a real problem, opening the file once in the desktop app (or your sync client's "keep local copy" option) forces it to materialize.
Development
The server is split into server.mjs (tool registration + Streamable HTTP transport) and lib/:
lib/config.mjs— env loading and validated config constantslib/vault-fs.mjs—resolveInVault, atomic writes, vault walking, ignore ruleslib/markdown.mjs— frontmatter/heading/task/wikilink/tag parsing (fence-aware)lib/vault-index.mjs— the cached vault-wide index and link resolution/backlink graphlib/daily-notes.mjs— reads.obsidian/daily-notes.json, Moment-token date formattinglib/capture.mjs— theobsidian_capture_inboxpayload normalizer and Markdown renderer
scripts/smoke-test.mjs drives the MCP surface end-to-end (initialize → tools/list → tools/call) against a scratch vault, without needing a real client:
VAULT_ROOT=/tmp/fake-vault node server.mjs &
node scripts/smoke-test.mjs
It exercises every tool above, including path-traversal rejection, wikilink rewriting on move, and dangling-backlink reporting on delete.
License
MIT — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.