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-serverIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
MarketingSupported Platforms
Tags
Our assessment of obsidian-mcp-server
obsidian-mcp-server scores 89/100 on our quality scale, 257th of 582 Marketing skills we index (top 45%).
Its MCP Server is 32 KB long, well organised into 35 sections with 6 code examples: a thorough specification that gives an agent plenty to work with.
It has 702 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 6 days ago, so obsidian-mcp-server is actively maintained.
- Our last check on 2026-10-18 found the source still online.
- It is released under the Apache-2.0 license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
obsidian-mcp-server compared with similar skills
All 4 of these similar skills score higher than obsidian-mcp-server; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| obsidian-mcp-server (this skill)by cyanheads | 89 | 702 | 6d ago | MCP Server |
| Agent-Reachby Panniantong | 100 | 109.3k | today | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 79.0k | today | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.8k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 98.3k | today | MCP Server |
Frequently asked questions
- How do I install obsidian-mcp-server?
- Run
claude mcp add cyanheads -- npx -y github:cyanheads/obsidian-mcp-server. The install tabs above show the steps for each supported agent. - Which AI agents does obsidian-mcp-server work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is obsidian-mcp-server safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It is Apache-2.0-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is obsidian-mcp-server still maintained?
- The repository was last updated 6 days ago, so obsidian-mcp-server is actively maintained.
Skill content
View source on GitHubOverview
Read, write, search, and surgically edit Obsidian vault notes — sections, frontmatter, tags — over the Local REST API plugin, with folder-scoped read/write permissions built in. Runs as a stdio process or a local Streamable HTTP server.
Tools
| Tool | 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 vault tags with usage counts, including hierarchical parents. Ordered by count descending and capped at limit (default 200, max 10000), with the withheld remainder disclosed. Optional nameRegex and minCount narrow the set first. |
| 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 | Search-replace inside a single note, scoped to the body by default. 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. Always asks the user to confirm first — the call is answered with a confirmation request and retried with the answer. |
| 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. |
Resources
| Resource | Description |
|:---|:---|
| obsidian://vault/{+path} | A note in the vault — content, frontmatter, tags, and file metadata. |
| obsidian://tags | All tags found across the vault, with usage counts (full snapshot). |
| obsidian://status | Server reachability, auth status, plugin/Obsidian version info, and registered API extensions. |
Vault-note and tag data are also reachable via tools — obsidian_get_note for obsidian://vault/{+path}, obsidian_list_tags for obsidian://tags (count-ranked and capped, unlike the resource's raw snapshot). obsidian://status has no tool equivalent. Resources exist for clients that prefer attaching a note or vault snapshot to a conversation.
Capability reference
obsidian_get_note <sub>tool</sub>
format: "content" | "full" | "document-map" | "section"selects the projection;fullacceptsincludeLinks: truefor outgoing wiki/markdown links (vault-internal only — external URLs are filtered)- Addressed by vault
path, theactivefile, or aperiodicnote (daily/weekly/monthly/quarterly/yearly) - Heading sections use
Parent::Childsyntax and find headings the way the document map does — setext headings (underlined with===or---) count,#lines inside a list item, HTML block, or fence do not — so every heading path the map lists reads back as itself, over the same span a section write edits; a bare leaf name matching several headings, or a full path that repeats in the note, returns the first match and lists every colliding path incandidates - Forgiving
pathresolution: a case-mismatched path retries against the canonical filename, an ambiguous case match fails withConflict, and aNotFoundcarriesDid you mean: …?suggestions when near-matches exist - Typed errors include
note_missing,path_forbidden,no_active_file,periodic_unsupported/periodic_disabled, andpath_traversal
obsidian_list_notes <sub>tool</sub>
- Recursive walk from
path(default vault root);depth1–20 (default 2 = target plus immediate children) - Optional
extensionandnameRegex(≤256 chars, no nested quantifiers) filters; a directory failingnameRegexis skipped without recursing into it - Hard cap of 1000 entries per call —
excluded.reason: "entry_cap"signals a truncated walk; narrowpathor the filters to see the rest - Per-directory
truncated: truemarks entries cut off by the depth limit or by path policy
obsidian_list_tags <sub>tool</sub>
- Vault-wide tag counts, including hierarchical parents (
work/taskscontributes to bothworkandwork/tasks) - Ordered by count descending, capped at
limit(default 200, max 10000); optionalnameRegexandminCountnarrow the candidate set before ranking - Reports
truncated/shown/capwhen the limit withheld results - Not narrowed by
OBSIDIAN_READ_PATHS— tag names (never note contents) can surface from outside the read scope
obsidian_list_commands <sub>tool</sub>
- Lists Obsidian command-palette IDs and display names; optional
nameRegexfilters on display name - Opt-in via
OBSIDIAN_ENABLE_COMMANDS=true— absent fromtools/listwhen unset - Discovery partner for
obsidian_execute_command
obsidian_search_notes <sub>tool</sub>
mode: "text" | "jsonlogic"always;"omnisearch"is added to the schema only when the Omnisearch plugin's HTTP server is reachable at startup (restart to re-probe)text— whitespace-split tokens, all required, each matched case-insensitively as a substring (quotes are literal, so there is no phrase operator), withcontextLength-sized context windows (default 100) and an optionalpathPrefix; tokens within 2 ×contextLengthof each other, such as a phrase's words, share one match location;jsonlogic— a JSONLogic tree withvarpaths intopath/content/frontmatter.<key>/tags/stat.{ctime,mtime,size}, plusglob/regexpoperators taking[PATTERN, VALUE];omnisearch— BM25-ranked, quoted phrases,-exclusion,path:/ext:filters, typo tolerance, PDF/OCR via Text Extractor, hard-capped at 50 upstream hits (truncated: truewhen likely hit)- Cursor pagination — omit
cursorfor page one, passnextCursorfrom the prior response; text-mode hits additionally clip tomaxMatchesPerHitmatch locations (default 10), flagged withtruncated/totalMatches - No dedicated backlinks tool — express "what links here" via
jsonlogic:{"regexp": ["\\[\\[Target Note(\\||#|\\]\\])", {"var": "content"}]}
obsidian_write_note <sub>tool</sub>
- Without
section— full-file write; refuses to clobber an existing note unlessoverwrite: true(file_existsconflict otherwise, naming the surgical-edit tools as the alternative) - With
section—PATCH-with-replace against a heading/block/frontmatter target, leaving the rest of the file untouched (overwriteis ignored); a bare heading leaf shared by several headings fails withambiguous_sectionunless one of them has no parent heading, which the write then targets, and a full heading path that repeats in the note fails the same way - Output reports
created, pluspreviousSizeInBytes/currentSizeInByteson every call to spot an accidental clobber or a mistyped path
obsidian_append_to_note <sub>tool</sub>
- Without
section— appends to an existing file, or creates it with the given content as the whole body (created: trueflags the second case) - With
section— appends to a heading/block/frontmatter target; the file must already exist, andcreateTargetIfMissing: truebrings the section itself into existence. On plugin v5.0 and later, content appended to a heading is separated from the section's existing content by a blank line (except a list item appended to a section that ends in a list and has no sub-headings, which continues that list), and a heading in it must sit below the section's own level (heading_outside_sectionotherwise) - Block-reference targets concatenate with no separator — include a leading newline in
contentfor one previousSizeInBytes/currentSizeInBytesbracket every call for drift detection
obsidian_patch_note <sub>tool</sub>
operation: "append" | "prepend" | "replace"against one heading, block reference, or frontmatter field per call; on plugin v5.0 and later, content appended or prepended to a heading is separated from the section's existing content by a blank line (except a list item appended to a section that ends in a list and has no sub-headings, or prepended to one that opens with a list, which continues that list), and a heading in it must sit below the section's own level (heading_outside_sectionotherwise)- Heading targets accept the full
Parent::Childpath or a bare leaf name; a leaf matching several headings fails withambiguous_sectionand lists the candidates, unless one of them has
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
109.3kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
79.0kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.8kOpen-source personal AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Scrapling
98.3k🕷️ The BEST Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
