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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。