obsidian-mcp

obsidian-mcp

Enables interaction with multiple Obsidian vaults through natural language, supporting note operations, search, and vault management with both REST and filesystem backends.

Category
Visit Server

README

obsidian-mcp

A FastMCP server for multiple Obsidian vaults. It talks to the Obsidian Local REST API plugin when Obsidian is running, and falls back to direct filesystem access when it isn't — so your notes stay reachable whether or not the app is open.

Every tool takes an optional vault argument, and obsidian_switch_vault sets the default for unqualified calls.

Why both backends

REST (Obsidian running) Filesystem (always)
Search Obsidian's own index and ranking substring scan, all terms must match
Tags resolved by Obsidian, with counts parsed from frontmatter + inline #tags
Backlinks ✅ from the link graph ❌ not available
Active note / open in UI / commands
Works with Obsidian closed
Works on a headless box or over SSH

The router probes REST health once and caches the result for OBSIDIAN_HEALTH_TTL seconds, so a closed Obsidian doesn't cost a failed connection on every call. If REST drops mid-call it retries on the filesystem automatically. Errors that mean "what you asked for doesn't exist" (missing note, bad path) are not retried — falling back would just fail again, slower.

Every response reports which backend served it, so a caller can tell whether it's seeing Obsidian's view or the raw files.

Setup

git clone <your-repo> obsidian-mcp && cd obsidian-mcp
uv venv && uv pip install -e ".[dev]"     # or: pip install -e ".[dev]"
pytest

Requires Python 3.11+. Works with MCP Python SDK 1.x (FastMCP) and 2.x (MCPServer) — _sdk.py papers over the rename.

Configuring vaults

Define vaults using whichever of these fits; the first one present wins.

A TOML file (best for 3+ vaults) — OBSIDIAN_VAULTS_FILE=~/.config/obsidian-mcp/vaults.toml:

default = "personal"

[vaults.personal]
path = "/Users/you/Vaults/Personal"
description = "Homelab, hobbies"
daily_folder = "Journal"

[vaults.work]
path = "/Users/you/Vaults/Work"
description = "Employer notes"
rest_base_url = "https://127.0.0.1:27125"   # note: NOT the default port
api_key = "this-vault's-own-key"

Inline JSONOBSIDIAN_VAULTS='{"default":"work","vaults":{...}}'. Accepts port/protocol/host shorthand instead of rest_base_url, and camelCase keys, so configs from other Obsidian MCP servers mostly paste straight in.

Per-vault env varsOBSIDIAN_VAULT_WORK_PATH, OBSIDIAN_VAULT_WORK_API_KEY, OBSIDIAN_VAULT_WORK_REST_BASE_URL, etc. The segment between OBSIDIAN_VAULT_ and the field name is the vault name.

Legacy single-vault varsOBSIDIAN_VAULT_PATH / OBSIDIAN_REST_BASE_URL / OBSIDIAN_API_KEY still work and define one vault named default.

⚠️ One port per vault

Every vault's Local REST API plugin defaults to port 27124, and only one process can bind a port. If you run two vaults at once, open each vault's Settings → Local REST API → Advanced and give it a unique port (27124, 27125, 27126…), then toggle the plugin off and on.

Each vault also generates its own API key, so a mismatched port usually shows up as a 401 rather than silently reading the wrong vault. To check positively:

obsidian_backend_status(verify=true)

That cross-checks each vault's REST root listing against its configured path and warns if they disagree.

Per-vault settings

path, rest_base_url, api_key, verify_ssl, ca_cert, daily_folder, daily_format, description

Global settings

Variable Default Notes
OBSIDIAN_DEFAULT_VAULT first defined Overrides default in the config file.
OBSIDIAN_PREFER_REST true Set false to always use the filesystem.
OBSIDIAN_READ_ONLY false Disables every mutating tool, across all vaults.
OBSIDIAN_MAX_FILE_BYTES 2000000 Refuse to read anything larger.
OBSIDIAN_HEALTH_TTL 20 Seconds to cache each vault's REST health probe.
OBSIDIAN_REQUEST_TIMEOUT 15 Per-request timeout in seconds.

To trust the plugin's cert rather than disabling verification, per vault:

curl -k https://127.0.0.1:27125/obsidian-local-rest-api.crt -o ~/.config/obsidian-mcp/work.crt
# then in vaults.toml:  ca_cert = "~/.config/obsidian-mcp/work.crt"  and  verify_ssl = true

Register it

Claude Code:

claude mcp add obsidian -- \
  uv --directory /path/to/obsidian-mcp run obsidian-mcp

Then set the env vars in .mcp.json or your shell profile.

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "obsidian": {
      "command": "uv",
      "args": ["--directory", "/path/to/obsidian-mcp", "run", "obsidian-mcp"],
      "env": {
        "OBSIDIAN_VAULTS_FILE": "/Users/you/.config/obsidian-mcp/vaults.toml"
      }
    }
  }
}

Tools

Vaultsobsidian_list_vaults, obsidian_switch_vault

Readsobsidian_list_notes, obsidian_read_note, obsidian_search_notes, obsidian_list_tags, obsidian_get_active_note*, obsidian_backend_status

Writesobsidian_write_note, obsidian_append_to_note, obsidian_patch_note, obsidian_append_to_daily_note, obsidian_move_note, obsidian_delete_note

App controlobsidian_open_note, obsidian_list_commands, obsidian_run_command*

* requires Obsidian to be running. These deliberately do not fall back — they return a message telling you to start Obsidian, rather than silently doing something different from what you asked.

All 17 tools accept an optional vault. Targeting works two ways, on purpose:

  • Per-callobsidian_search_notes(vault="work", query="..."). Explicit and stateless; the right choice when a task spans vaults.
  • Session defaultobsidian_switch_vault(vault="work") changes where unqualified calls go, so a long stretch of work in one vault doesn't repeat the argument.

A per-call vault always overrides the session default. Switching affects this server session only — it doesn't touch any vault's contents or change which vault Obsidian has open.

obsidian_backend_status is the one to call first when something fails with a connectivity error; with no vault named it probes all of them and reports which backends are live.

Safety choices

  • Deletes are recoverable by default. obsidian_delete_note moves the note to the vault's .trash, restorable from inside Obsidian. permanent=true is opt-in. Because the plugin's DELETE is unconditional, trashing is routed through the filesystem backend even when REST is live.
  • Absolute paths and .. traversal are rejected, not silently rewritten. Resolved paths are checked against the vault root.
  • obsidian_write_note won't clobber an existing note without overwrite=true.
  • OBSIDIAN_READ_ONLY=true disables every mutating tool in one switch — useful for a research-only session.

Known limitations

  • Moving a note does not rewrite wikilinks. Only Obsidian does that, and only for moves made inside the app. Search for the old name afterwards if it matters.
  • Frontmatter patches reformat the YAML block. Values round-trip through PyYAML, so tags: [a, b] comes back as a block list. Content is preserved; formatting isn't.
  • Filesystem search has no fuzzy matching or ranking beyond a title-match boost. When Obsidian is running you get its real index instead.
  • The filesystem backend doesn't see unsaved editor buffers. A note being actively edited may be stale on disk by a few seconds.
  • Cross-vault operations aren't atomic. obsidian_move_note works within one vault only; moving between vaults means read, write, delete as separate calls.
  • obsidian_get_active_note is per-vault, and only answers for a vault whose Obsidian window is open with the plugin bound to that vault's configured port.

Worth knowing before you build on this

As of v3+, the Local REST API plugin ships its own built-in MCP server at https://127.0.0.1:27124/mcp/ (streamable HTTP, bearer auth). If all you want is Obsidian access while Obsidian is running, point your client at that and skip this project entirely.

This server earns its place when you want the things that one can't do: working with the vault while Obsidian is closed, running on a headless machine, read-only enforcement, trash-by-default deletes, or custom workflow tools shaped around your own vault conventions.

Development

pytest                    # 40 tests, no Obsidian required
ruff check obsidian_mcp tests
npx @modelcontextprotocol/inspector uv --directory . run obsidian-mcp

The test suite fakes the REST backend, so fallback and multi-vault routing are covered without a running Obsidian.

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