SkillAgentSearch skills...

obsidian-mcp-server

Read, write, search, and surgically edit Obsidian vault notes, tags, and frontmatter via MCP. STDIO or Streamable HTTP.

Install / Use

claude mcp add cyanheads -- npx -y github:cyanheads/obsidian-mcp-server

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

89/100

Category

Marketing

Supported Platforms

Claude Code
Claude Desktop
<div align="center"> <h1>obsidian-mcp-server</h1> <p><b>Read, write, search, and surgically edit Obsidian vault notes, tags, and frontmatter via MCP. STDIO or Streamable HTTP.</b> <div>14 Tools • 3 Resources</div> </p> </div> <div align="center">

Version License Docker MCP SDK npm TypeScript Bun

</div> <div align="center">

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

</div>

Tools

Fourteen tools grouped by shape — readers fetch notes and metadata, writers create or surgically edit content, managers reconcile tags and frontmatter, and a guarded escape hatch dispatches Obsidian command-palette commands.

| Tool Name | Description | |:----------|:------------| | obsidian_get_note | Read a note as raw content, full structured form (content + frontmatter + tags + stat, with optional outgoing links), structural document map, or a single section. | | obsidian_list_notes | List notes and subdirectories under a vault path. Recursive walk (default depth 2, max depth 20; 1000-entry cap) with optional extension and nameRegex filters. | | obsidian_list_tags | List every tag found across the vault with usage counts, including hierarchical parents. Optional nameRegex post-filters the result set. | | obsidian_list_commands | List Obsidian command-palette commands, optionally filtered by nameRegex on display name. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true (paired with obsidian_execute_command). | | obsidian_search_notes | Search the vault by text, JSONLogic, or BM25-ranked Omnisearch (when the plugin is reachable). Results paginate via opaque cursors. | | obsidian_write_note | Create a note, replace a single section in place, or — with overwrite: true — clobber an existing file. Refuses whole-file writes against an existing path by default. | | obsidian_append_to_note | Append content to a note. Without section, creates the file if missing. With section, appends to a specific heading, block, or frontmatter field (file must exist). | | obsidian_patch_note | Surgical append / prepend / replace against a heading, block reference, or frontmatter field. | | obsidian_replace_in_note | Body-wide search-replace inside a single note. Literal or regex matching with whole-word, whitespace-flexible, and case-sensitivity options; supports capture-group replacement. | | obsidian_manage_frontmatter | Atomic get / set / delete on a single frontmatter key. | | obsidian_manage_tags | Add, remove, or list tags. Defaults to the frontmatter tags: array; location: 'inline' or 'both' opts into mutating the note body. | | obsidian_delete_note | Permanently delete a note. Elicits human confirmation when the client supports it. | | obsidian_open_in_ui | Open a file in the Obsidian app UI, with failIfMissing and newLeaf toggles. | | obsidian_execute_command | Execute an Obsidian command-palette command by ID. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true. |

obsidian_get_note

Read a note in one of four projections, addressed by vault path, the active file, or a periodic note (daily, weekly, monthly, quarterly, yearly).

  • format: "content" — raw markdown body
  • format: "full" — content, frontmatter, tags, and file metadata; pass includeLinks: true to also parse outgoing wiki and markdown link references from the body (vault-internal only — external URLs are filtered)
  • format: "document-map" — catalog of headings, block references, and frontmatter fields
  • format: "section" — single heading/block/frontmatter section value (requires section); heading sections include the full subtree under that heading

Pair the document-map projection with obsidian_patch_note to discover edit targets before patching.


obsidian_search_notes

Up to three search modes selected by mode:

  • text — substring match with surrounding context windows. contextLength controls characters of context per side of each match (default 100; bump it for more context per hit). Optional pathPrefix filter (text mode only — passing pathPrefix in any other mode is rejected with path_prefix_invalid_mode).
  • jsonlogic — JSONLogic tree evaluated against path, content, frontmatter.<key>, tags, and stat.{ctime,mtime,size}; custom glob and regexp operators
  • omnisearch — BM25-ranked search via the community Omnisearch plugin. Supports quoted phrases, -exclusion, path: / ext: filters, typo tolerance, and PDF + OCR coverage (via Text Extractor). Only present in the mode enum when the plugin's HTTP server is reachable at startup; the upstream hard-caps results at 50 — narrow the query to surface more (the response carries truncated: true when the cap was likely hit).

Results paginate via opaque cursors per the MCP 2025-11-25 spec: omit cursor for the first page, then pass nextCursor from the prior response. Every result carries totalCount (post-path-policy, pre-pagination); nextCursor is omitted on the last page. Text-mode hits are additionally clipped per file at maxMatchesPerHit (default 10) so a single match-heavy note can't blow the response budget — clipped hits carry truncated: true and totalMatches.


obsidian_write_note

Create or surgically replace, with a protective default against accidental whole-file overwrites.

  • Without section — full-file PUT. Refuses to clobber an existing file unless overwrite: true is set. The file_exists (Conflict) error suggests obsidian_patch_note / obsidian_append_to_note / obsidian_replace_in_note for in-place edits.
  • With sectionPATCH-with-replace against the named heading/block/frontmatter field, leaving the rest of the file untouched. The overwrite flag is ignored in section mode.

The output reports created: true when the call brought a new file into existence; false when it replaced an existing one or targeted a section. Every mutating tool also returns previousSizeInBytes and currentSizeInBytes so an agent can spot accidental clobbers, unexpected upstream behavior, or a typo path that landed at the wrong file.


obsidian_append_to_note

A combined upsert + section-append primitive that mirrors the upstream Local REST API behavior:

  • Without sectionPOST to /vault/{path}. Appends when the file exists, creates the file with your content as the entire body when it doesn't. The output's created: true flags the second branch so the agent can notice when a typo path or a not-yet-created daily note silently turned into a brand-new file.
  • With sectionPATCH-with-append against the named heading, block reference, or frontmatter field. The file must exist (PATCH preflight throws note_missing otherwise). Pass createTargetIfMissing: true to bring the section itself into existence inside an existing file. Block-reference targets concatenate adjacent to the block line without a separator — include a leading newline in content if you want one.

previousSizeInBytes is 0 on the upsert-create branch and the actual file size otherwise; currentSizeInBytes is the post-write size read from the upstream after the operation. Compare deltas against Buffer.byteLength(content) to detect auto-newline injection or concurrent writers.


obsidian_patch_note

Surgical edits at a single document target.

  • operation: "append" adds after the section
  • operation: "prepend" adds before the section
  • operation: "replace" swaps it out
  • Targets: heading path, block reference ID, or frontmatter field

Heading targets accept either the full Parent::Child path or a bare leaf name. A bare leaf that matches exactly one heading is expanded to its full path before the write, and the response echoes the locator the edit landed on; a leaf matching several headings is rejected with ambiguous_section, whose error data lists the candidate paths. The same resolution applies to obsidian_write_note and obsidian_append_to_note with section.

Use obsidian_get_note with format: "document-map" to discover what targets exist before patching.


obsidian_replace_in_note

Body-wide search-replace for edits that don't fit obsidian_patch_note's structural targets. The note is fetched, replacements are applied sequentially (each sees the previous output), and the result is written back in a single PUT.

Per-replacement options:

  • useRegex — treat search as an ECMAScript regex. With useRegex: true, the replacement honors $1 / $& capture-group references.
  • caseSensitive — when false, match case-insensitively
  • wholeWord — wrap the pattern in \b…\b; works in both literal and regex modes
  • flexibleWhitespace — substitute any run of whitespace in search with \s+. Literal mode only — has no effect when useRegex: true (express it directly).
  • replaceAll — when false, only the first match is replaced

Literal mode preserves $1 / $& in the replacement verbatim — only useRegex: true expands capture-group references.


obsidian_manage_tags

Add, remove, or list tags on a note. Operates on one of two representations, defaulting to the canonical Obsidian frontmatter location:

  • location: 'frontmatter' (default) — only the frontmatter tags: array; the note body is left untouched
  • location: 'inline' — only inline #tag syntax in the body; add appends #tag at end-of-file
  • location: 'both' — opt-in reconciliation across both representations

add ensures the tag is present in the requested location(s); remove strips it; list ignores the input tags array. Inline #tag occurrences inside fenced code blocks are intentionally left alone.


obsidian_delete_note

Permanently delete a note. When the client supports elicit, the server requests human confirmation before issuing the DELETE and the prompt includes the file's byte size — destructive blast radius visible before the user con

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars683
CategoryMarketing
Updated2d ago
Forks104

Languages

TypeScript

Security Score

100/100

Audited on Sep 19, 2026

No findings