Obsidian MCP Server

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.

Category
Visit Server

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 is obsidian_append_daily_note, which may create today's daily note outside Inbox/ 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_note moves 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_note rewrites 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 #heading anchors.
  • Path safety: every tool resolves paths through one canonical helper that rejects absolute paths, .. traversal, and symlinks pointing outside VAULT_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 constants
  • lib/vault-fs.mjs — resolveInVault, atomic writes, vault walking, ignore rules
  • lib/markdown.mjs — frontmatter/heading/task/wikilink/tag parsing (fence-aware)
  • lib/vault-index.mjs — the cached vault-wide index and link resolution/backlink graph
  • lib/daily-notes.mjs — reads .obsidian/daily-notes.json, Moment-token date formatting
  • lib/capture.mjs — the obsidian_capture_inbox payload 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured