AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Obsidian Mcp

mcp-yuchi-chang-obsidian-mcp · by yuchi-chang

obsidian mcp

No reviews yet
0 installs
30 views
0.0% view→install

Install

$ agentstack add mcp-yuchi-chang-obsidian-mcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-yuchi-chang-obsidian-mcp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Obsidian Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

obsidian-mcp

MCP server that wraps the official Obsidian CLI so an LLM agent can drive a running Obsidian instance — read/write notes, search, manage frontmatter, navigate links, run plugins, and more.

This server is a thin, comprehensive wrapper. Every tool maps 1:1 to an obsidian CLI command.

Prerequisites

  1. Obsidian must be running. The CLI talks to the live app over IPC; it does not read the vault on disk directly.
  2. Register the CLI binary. In Obsidian: Settings → General → Command line interface → Register CLI. Obsidian will add obsidian to your PATH.
  3. Verify: obsidian version prints the CLI version.

Install

Two paths depending on whether you want to build it yourself or grab a pre-published version from npm.

Option A — Clone & build (works today)

Clone the repo and build locally, then point Claude Code at the built file:

git clone https://github.com/yuchichang/obsidian-mcp.git
cd obsidian-mcp
npm install
npm run build

Register it with Claude Code (one command):

# Add (user scope — available across all projects)
claude mcp add -s user obsidian -- node /absolute/path/to/obsidian-mcp/dist/index.js

# Remove
claude mcp remove obsidian

# List configured servers
claude mcp list

-s user registers it for your whole user account. Use -s project to commit it to the repo's .mcp.json instead, or -s local for the current project only (default).

Or write it into .mcp.json manually:

{
  "mcpServers": {
    "obsidian": {
      "command": "node",
      "args": ["/absolute/path/to/obsidian-mcp/dist/index.js"]
    }
  }
}

Option B — Install from npm (zero-build)

> Prerequisite: the package must already be published to npm. The maintainer publishes once via npm publish; all subsequent users get it via npx automatically. If you forked this repo and want this flow under your own scope, change name in package.json to @/obsidian-mcp, then npm publish.

Once published, no clone or build needed:

claude mcp add -s user obsidian -- npx -y @yuchichang/obsidian-mcp

Or in .mcp.json / Claude Desktop's claude_desktop_config.json:

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "@yuchichang/obsidian-mcp"]
    }
  }
}

Override the CLI path

If obsidian isn't on PATH, set the OBSIDIAN_CLI env var. Works with either install path:

{
  "mcpServers": {
    "obsidian": {
      "command": "node",
      "args": ["/absolute/path/to/obsidian-mcp/dist/index.js"],
      "env": {
        "OBSIDIAN_CLI": "C:/Users/you/AppData/Local/Obsidian/obsidian.cmd"
      }
    }
  }
}

Tools

Vault & files

| Tool | Wraps | |---|---| | obsidian_list_files | obsidian files | | obsidian_list_folders | obsidian folders | | obsidian_read_note | obsidian read | | obsidian_get_metadata | obsidian file | | obsidian_create_note | obsidian create | | obsidian_append_note | obsidian append | | obsidian_prepend_note | obsidian prepend | | obsidian_move_note | obsidian move | | obsidian_delete_note | obsidian delete (permanent flag supported) |

Frontmatter properties

| Tool | Wraps | |---|---| | obsidian_get_properties | obsidian properties | | obsidian_set_property | obsidian property:set | | obsidian_remove_property | obsidian property:remove |

Search

| Tool | Wraps | |---|---| | obsidian_search | obsidian search | | obsidian_search_context | obsidian search:context |

Tags & links

| Tool | Wraps | |---|---| | obsidian_list_tags | obsidian tags | | obsidian_files_with_tag | obsidian tag | | obsidian_rename_tag | obsidian tags:rename | | obsidian_get_links | obsidian links | | obsidian_get_backlinks | obsidian backlinks | | obsidian_list_unresolved | obsidian unresolved | | obsidian_list_orphans | obsidian orphans |

Daily notes

| Tool | Wraps | |---|---| | obsidian_daily_read | obsidian daily:read | | obsidian_daily_append | obsidian daily:append | | obsidian_daily_path | obsidian daily:path |

Plugins

| Tool | Wraps | |---|---| | obsidian_list_plugins | obsidian plugins | | obsidian_enable_plugin | obsidian plugin:enable | | obsidian_disable_plugin | obsidian plugin:disable | | obsidian_reload_plugin | obsidian plugin:reload |

Developer / advanced

| Tool | Wraps | Notes | |---|---|---| | obsidian_eval | obsidian eval | ⚠️ Runs arbitrary JS inside Obsidian. Treat as destructive. | | obsidian_dev_screenshot | obsidian dev:screenshot | Returns base64 PNG. | | obsidian_dev_errors | obsidian dev:errors | | | obsidian_dev_console | obsidian dev:console | |

Meta

| Tool | Wraps | |---|---| | obsidian_topic_stats | reports the persistent topic → folder map for a vault | | obsidian_register_topic | binds a topic to a folder (no prompt) | | obsidian_remove_topic | removes a topic from the persistent store | | obsidian_scan_root | lists root-level notes with preview for bulk-organize | | obsidian_organize_apply | validates + applies a routing plan (dry-run supported) | | obsidian_version | obsidian version | | obsidian_help | obsidian help |

Conventions

  • Targeting a note — file-targeting tools accept either:
  • file — wikilink-style note name (e.g. "My Note"), or
  • path — vault-relative file path (e.g. "Folder/My Note.md").
  • Multi-vault setups — every tool accepts an optional vault parameter. When omitted, the most recently focused vault is used.
  • Output format — list/search/metadata tools default to JSON for easy machine parsing.

Sensitive operations & user confirmation

The following tools are gated behind a user-confirmation step:

| Tool | Reason | |---|---| | obsidian_delete_note | Removes data (especially with permanent: true). | | obsidian_move_note | Renames + rewrites wikilinks across the vault. | | obsidian_remove_property | Removes frontmatter data. | | obsidian_rename_tag | Bulk-rewrites tags across every note. | | obsidian_enable_plugin | Grants a community plugin code execution. | | obsidian_eval | Runs arbitrary JavaScript inside Obsidian. |

How the gate works:

  1. MCP elicitation (preferred). If the connected client supports the elicitation capability (Claude Code does), the server sends an elicitation/create request and the client shows the user a Proceed? prompt with the action and target spelled out. Only accept + confirm: true proceeds.
  2. Explicit confirm: true parameter. Every sensitive tool's input schema includes an optional confirm: boolean. Passing confirm: true skips the elicitation prompt — use this only when the caller has already obtained user approval.
  3. Refusal fallback. If the client doesn't support elicitation and confirm: true was not provided, the tool returns an isError result that names the action and instructs the caller to retry with confirm: true.

Bypass for batch / automation

OBSIDIAN_MCP_AUTO_CONFIRM=1

Set this env var (in your MCP client's env block) to skip every confirmation prompt. Use only in fully-trusted automation contexts.

Topic → folder routing (vault-aware, persistent)

The MCP runs a per-vault topic store at ~/.obsidian-mcp//topic-map.json. It learns where each topic of note belongs and reuses that decision next time.

Agent: create_note(path="kungpao.md", topic="recipe-chinese", vault="MyVault")
   ↓
MCP: is "recipe-chinese" already in the store?
   ├── yes → use the stored folder, increment usage, write
   └── no  → scan vault for similar folders ("Recipes/Chinese", "食譜/中式" …)
            → MCP elicits the user: "Where should 'recipe-chinese' notes live?
              Suggestions: ..."
            → user types or picks a folder
            → MCP records the route, then writes

What lives where, and why:

  • The persistent store, not env vars, is the source of truth — the MCP is the only thing that sees vault state across sessions, so storing the conventions there is what gives this layer its leverage.
  • The user is asked once per topic; subsequent notes for the same topic land silently.
  • Folders are auto-created by the Obsidian CLI as deep as needed — no mkdir from the MCP.

Resolution order

| | Condition | Action | |---|---|---| | 1 | path contains / | Used as-is, topic ignored. | | 2 | topic present in store | Reuse stored folder, increment usage. | | 3 | folder arg passed alongside topic | Treat as pre-decided; record in store. | | 4 | topic unknown, client supports elicitation | Scan vault, prompt user, record answer. | | 5 | topic unknown, no elicitation | Auto-create / folder, record, hint at similar existing folders in the response. | | 6 | No topic, no folder | Write at vault root. |

Topic-store tools

| Tool | What it does | |---|---| | obsidian_topic_stats | Show the learned map for a vault, sorted by usage. | | obsidian_register_topic | Bind topic → folder programmatically (no elicitation). | | obsidian_remove_topic | Forget a topic from the store (existing notes untouched). |

Theory pointers

Faceted folder routing here is the simplest slice of a much larger idea. Worth reading if you want to push further:

  • Ranganathan, S.R. (1933) Colon Classification — PMEST facets
  • Ranganathan, S.R. (1931) Five Laws of Library Science
  • Tiago Forte (2022) Building a Second Brain — PARA method (actionability axis)
  • Niklas Luhmann (1981) "Kommunikation mit Zettelkästen" — graph-over-tree
  • Bates, M.J. (1989) "The design of browsing and berrypicking"

Bulk organize root notes

When the vault root accumulates loose .md files, a caller LLM can sweep them into the right subfolders in three steps:

  1. Scan — list root notes with metadata + body preview:

``jsonc // tool: obsidian_scan_root { "ignore": ["Daily/*", "*.excalidraw.md"] } ``

  1. Classify (caller side) — the LLM reads each preview and proposes a routing plan:

``jsonc [ { "path": "WebRTC 連線建立流程.md", "target_folder": "webrtc", "topic": "webrtc", "reason": "covers signaling/SDP/ICE" }, { "path": "舊筆記.md", "target_folder": "Notes", "topic": "misc" } ] ``

  1. Apply — dry-run first to preview, then call again with dry_run: false:

```jsonc // tool: obsidianorganizeapply { "plan": [...], "dryrun": true } // → { "summary": { "willmove": 2, "willcreatefolders": 1, ... }, "items": [...] }

{ "plan": [...], "dry_run": false, "confirm": true } // → moves files, creates new folders as needed, registers topic→folder mappings ```

Per-entry failure isolation: a single move failure marks that entry status: "failed" without aborting the rest of the batch. Successful moves with a topic field are recorded in the persistent topic store, so future single-note writes for that topic auto-route.

Long content & argv limits

The Obsidian CLI does not (yet) support reading parameter values from stdin or from files — every value travels on the command line. That collides with platform limits:

| Platform | Practical command-line limit | |---|---| | Windows (cmd.exe) | ~8,191 chars total | | macOS / Linux | ARG_MAX (typically 128 KB – 2 MB) |

To stay safe, the server automatically chunks long writes:

| Tool | Chunking strategy | |---|---| | obsidian_create_note | First chunk via create, remaining chunks via append. | | obsidian_append_note | Sequential append calls. | | obsidian_prepend_note | prepend calls in reverse order so final order is preserved. | | obsidian_daily_append | Resolves the daily note path, then chunked append. | | obsidian_eval | Not chunked — JS can't be split. Returns an error suggesting the script-via-note workaround. |

Splits happen at line boundaries when possible; oversized single lines fall back to UTF-8-safe character boundaries. Reassembled content is byte-identical to the original.

Configure the per-call byte threshold (defaults: 6,000 on Windows, 100,000 elsewhere):

OBSIDIAN_MCP_MAX_ARG_BYTES=4000

If a chunk in the middle of a multi-chunk write fails, the server returns isError with a clear message stating which chunks made it to disk so the caller can recover.

Develop

npm run dev      # tsc --watch
npm run inspect  # launch MCP Inspector against the built server
node scripts/smoke-test.mjs   # initialize + tools/list smoke test

How it works

runObsidian() (src/exec.ts) shell-quotes arguments, invokes the obsidian binary via child_process.exec, and parses stdout. Most read-style tools request format=json; results are parsed to structuredContent for clients that consume structured tool output, while still returning a text representation in content.

Tool registry lives in src/tools.ts — adding a new wrapped command is a single entry there.

Reference

  • Obsidian CLI: https://obsidian.md/help/cli
  • MCP spec: https://modelcontextprotocol.io

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.