obsidian-mcp-pro
obsidian-mcp-pro gives AI assistants deep, structured access to an Obsidian vault for reading, writing, searching, tagging, link analysis, graph traversal, and canvas manipulation.
Read & Search
search_notes— Full-text search with optional folder scopingget_note— Read full content and metadata by pathlist_notes— List all notes in the vault or a specific folderget_daily_note— Retrieve today's or a specific date's daily notesearch_by_frontmatter— Find notes by frontmatter property values
Write & Modify
create_note— Create a note with optional frontmatter and contentappend_to_note/prepend_to_note— Add content to end or beginning of a noteupdate_frontmatter— Update frontmatter without altering the note bodycreate_daily_note— Create a daily note, optionally from a templatemove_note— Move or rename a note (with automatic link updates)delete_note— Delete a note (to trash by default, or permanently)
Tags
get_tags— List all tags with usage counts, sortable by count or namesearch_by_tag— Find notes by single or multiple tags, with optional content preview
Links & Graph
get_backlinks/get_outlinks— Find notes linking to or from a given notefind_orphans— Identify notes with no incoming or outgoing linksfind_broken_links— Detect wikilinks pointing to non-existent notesget_graph_neighbors— Traverse the link graph up to 5 hops in any direction
Canvas
list_canvases— List all.canvasfiles in the vaultread_canvas— Read a canvas's full node and edge dataadd_canvas_node— Add a text, file, link, or group node with position, size, and coloradd_canvas_edge— Add a directed edge between nodes with optional label and side anchors
MCP Resources
Access vault data via URI patterns: obsidian://note/{path}, obsidian://tags, and obsidian://daily.
Vault selection is configured via OBSIDIAN_VAULT_PATH/OBSIDIAN_VAULT_NAME environment variables or automatic OS detection.
Allows for structured manipulation of Markdown documents within the vault, including parsing and updating frontmatter properties, as well as appending or prepending content to existing files.
Provides comprehensive access to Obsidian vaults, enabling AI agents to search notes, read and write content with frontmatter support, manage tags, analyze backlinks and outlinks, and traverse the link graph.
obsidian-mcp-pro
The most feature-complete MCP server for Obsidian vaults.
⭐ Please star us on GitHub — it helps us reach more users!
💙 Support this project — obsidian-mcp-pro is free and open-source. If it saves you time, consider buying me a coffee on Ko-fi.
Give AI assistants deep, structured access to your Obsidian knowledge base. Read, write, search, tag, analyze links, traverse graphs, manipulate canvases, query Bases, edit by heading or block reference, run semantic search, and pull binary attachments. All through the Model Context Protocol.
41 tools, 5 prompts, 3 resources. Every tool ships with rich descriptions, typed schemas, human-readable titles, and safety annotations (readOnlyHint, destructiveHint, idempotentHint) so your agent picks the right tool, passes the right arguments, and handles results correctly. The original 23 tools earned an average 4.40/5 score and all-A grades on Glama's quality index; the 18 newer ones follow the same authoring conventions documented in docs/TOOL_AUTHORING.md.
Contents
Features
Read & Search
Full-text search across all vault notes (cached: re-runs only re-read changed files)
Read individual notes whole, or as a fragment by heading path, block id, or line range
List and filter notes by folder, date, or pattern
Search by frontmatter fields and values
Retrieve daily notes automatically using the vault's configured filename format
get_recent_notesorders by mtime;get_vault_statsreports counts, words, tag coverage;resolve_aliastranslates a display name to a real note path
Write & Modify
Create new notes with frontmatter and content
Append or prepend content to existing notes
Update frontmatter properties programmatically (merge: unlisted keys are preserved)
Move and rename notes (rewrites every wikilink, markdown link, and canvas reference across the vault by default)
Delete notes safely; moved to the vault's
.trashfolder by default, with an optional permanent flag and elicitation-based confirmationSurgical edits by heading:
update_section,insert_at_section,list_sections, plus single-notereplace_in_note(regex with match-count guard) andedit_blockfor paragraphs tagged with^id
Tags
Build and query a complete tag index (incremental: cached across runs)
Search notes by single or multiple tags
rename_tagrewrites both inline#tagoccurrences and frontmattertags:arrays vault-wide; hierarchical mode also rebases nested sub-tags (project/alphafollowsproject)
Links & Graph
Get backlinks (what links to a note)
Get outlinks (what a note links to)
Find orphan notes with no inbound or outbound links
Detect broken links pointing to non-existent notes
Traverse graph neighbors to a configurable depth
Canvas
Read
.canvasfiles with full node and edge dataAdd new nodes (text, file, link, group) to canvases
Add edges between canvas nodes
List all canvases in the vault
Bases (Obsidian 1.10+)
list_basesenumerates.basefilesread_basereturns the parsed YAML (filters, properties, views)query_baseruns the filter DSL against the vault and returns matching notes; supportstaggedWith(),file.hasTag(),file.inFolder(), comparison operators, andand/or/notcombinators
Attachments
list_attachmentsenumerates every non-md/canvas/base file with a per-extension count summaryfind_unused_attachmentsflags assets no note references via embeds or markdown links; optional reclaimable-bytes reportget_attachmentreturns image / audio / blob bytes inline as MCP content blocks (5 MB default cap, 50 MB hard cap)
Semantic Search (optional, Ollama or OpenAI)
index_vaultchunks each note (heading-aware), embeds via the configured provider, persists vectors to<vault>/.obsidian/cache/, and incrementally re-embeds only changed notessearch_semanticranks notes by cosine similarity against an embedded queryfind_similar_notesreuses an existing note's embeddings to surface neighbors without a live API call
MCP Resources
obsidian://note/{path}reads any note by its vault-relative pathobsidian://tagsretrieves the full tag index as JSONobsidian://dailygets today's daily note content
MCP Prompts
The server exposes five starter prompts that clients (Claude Desktop, Cursor) surface in their slash-command palette:
daily-reviewwalks today's daily note, surfaces unchecked tasks, and proposes follow-upsweekly-rollupaggregates the last seven daily notes into themes / decisions / open tasksfind-stale-noteslocates untouched notes and clusters them as orphaned vs. broken-linked vs. still-linkedextract-action-itemspulls all- [ ] …lines from a note (or every note matching a tag) into a checklistbuild-mocgenerates a Map of Content (MOC) for a tag or folder
Operational features
Folder-scoped permissions:
OBSIDIAN_READ_PATHS/OBSIDIAN_WRITE_PATHSallowlists gate every tool at the path-resolution choke pointPersistent mtime cache at
<vault>/.obsidian/cache/mcp-pro-index-cache.jsonsurvives restarts; subsequent vault scans serve from cache after one stat-passProgress notifications (
notifications/progress) onrename_tag,find_unused_attachments, andindex_vaultwhen the client subscribes via_meta.progressTokenElicitation prompts the user to retype the note path on
delete_note(permanent: true)when the client supports it
Quick Start
Using Obsidian? There's also an Obsidian plugin that runs this server inside the app with a ribbon toggle and settings UI — no config-file editing. Recommended for most users.
One-Command Install (Claude Desktop / Cursor)
npx -y obsidian-mcp-pro installThis merges an entry into your claude_desktop_config.json (or ~/.cursor/mcp.json with --client=cursor), backs up the previous file, and prints next steps. Works on macOS, Windows, and Linux.
Pin a specific vault:
npx -y obsidian-mcp-pro install --vault /path/to/your/vaultManual Claude Desktop Config
Add this to your Claude Desktop configuration file (claude_desktop_config.json):
{
"mcpServers": {
"obsidian": {
"command": "npx",
"args": ["-y", "obsidian-mcp-pro"]
}
}
}If you have multiple vaults, specify which one:
{
"mcpServers": {
"obsidian": {
"command": "npx",
"args": ["-y", "obsidian-mcp-pro"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/vault"
}
}
}
}Claude Code
claude mcp add obsidian-mcp-pro -- npx -y obsidian-mcp-proHTTP Transport (Remote Clients, Cursor, ChatGPT, Web)
npx -y obsidian-mcp-pro --transport=http --port=3333Endpoint: http://127.0.0.1:3333/mcp (Streamable HTTP). Protect with a bearer token:
npx -y obsidian-mcp-pro --transport=http --token=your-secret
# or: MCP_HTTP_TOKEN=your-secret npx -y obsidian-mcp-pro --transport=httpThe HTTP server binds to 127.0.0.1 by default with DNS rebinding protection enabled.
Never bind --host=0.0.0.0 directly to the public internet. Doing so exposes your entire Obsidian vault to anyone who can reach the port. If you need remote access:
Put the server behind a reverse proxy (nginx, Caddy, Cloudflare Tunnel) that terminates TLS, and
Require
--token=<secret>(orMCP_HTTP_TOKEN), andRestrict
--allow-originto the specific origins you trust, andSet
--rate-limitto cap request volume per IP.
For local-only setups (same machine / VPN / SSH tunnel), keep the default 127.0.0.1 bind.
Additional hardening flags:
Flag | Purpose |
| Restrict CORS to an allowlist (e.g. |
| Cap requests per minute per client IP. |
Operational endpoints (no auth required):
Endpoint | Returns |
|
|
|
|
Structured logging is controlled by LOG_LEVEL (debug/info/warn/error/silent, default info) and LOG_FORMAT (text/json, default text). All logs go to stderr so the stdio transport on stdout is never polluted.
Usage
Once installed, the server exposes 23 tools and 3 resources to whichever MCP client you configured. Below is a transcript of a Claude Desktop conversation showing what day-to-day use looks like.
You: Find notes tagged
#projectI touched this week, then summarize the status of each and append today's date under a "Last reviewed" heading in each one.
Claude picks the right tools in order, with no guidance beyond the prompt:
🔧 search_by_tag(tag="project", includeContent=false)
→ 7 notes: "Atlas/overview.md", "Atlas/milestones.md", "Beacon/spec.md", ...
🔧 list_notes(folder="Atlas", limit=100)
→ filters to recent modifications via get_note stats
🔧 get_note(path="Atlas/overview.md")
→ reads content + frontmatter + tags
🔧 get_note(path="Atlas/milestones.md")
→ ...
🔧 append_to_note(
path="Atlas/overview.md",
content="\n## Last reviewed\n2026-04-21 — on track; waiting on design review."
)
→ ok
🔧 append_to_note(
path="Atlas/milestones.md",
content="\n## Last reviewed\n2026-04-21 — Q2 milestone at risk, see spec.md."
)
→ okClaude: I reviewed 7 project notes tagged
#project. Atlas is on track pending design review; the Q2 milestone is at risk — details inmilestones.md. Beacon's spec is complete but has 3 open questions in the frontmatter. I appended a "Last reviewed" section to each.
Other things the tool set lets agents do without hand-holding:
Research a topic across the vault.
search_notes→get_outlinks→get_graph_neighborswalks the graph todepth=2and surfaces related notes the user may have forgotten.Clean up dangling references after a rename.
move_note→find_broken_linksreturns every wikilink that now points nowhere, with source note and line number.Maintain a daily log.
get_daily_notereads today's note (using the vault's configured date format) andappend_to_noteadds the new entry — daily-note plugin config is honored, no manual date formatting.Canvas editing.
read_canvas→ agent reasons about the node graph →add_canvas_node+add_canvas_edgelays out new ideas on an existing board.
Tool descriptions + typed schemas + safety hints (readOnlyHint, destructiveHint) are what make this work reliably — the agent knows delete_note is destructive and asks first, knows search_notes is free to call speculatively, and knows the expected shape of every argument.
Configuration
The server locates your vault using the following priority:
Priority | Method | Description |
1 |
| Environment variable with the absolute path to your vault |
2 |
| Environment variable to select a vault by folder name when multiple vaults exist |
3 | Auto-detection | Reads Obsidian's global config ( |
Auto-detection works on macOS, Windows, and Linux by reading the platform-specific Obsidian configuration directory.
Daily-Note Filename Format
get_daily_note, create_daily_note, and the obsidian://daily resource render the note path using your vault's .obsidian/daily-notes.json format string. Moment.js-style tokens are supported:
Token | Example | Token | Example | |
|
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| |
| renders the bracket contents verbatim, e.g. |
Unrecognized tokens pass through unchanged. Local time is used (matching Obsidian's rendering).
Folder-Scoped Permissions
Restrict the tools' read/write surface to specific folders without exposing the rest of the vault:
Env var | Purpose |
| Comma- or colon-separated list of folders that read tools may access. Unset means unrestricted. Use |
| Same shape, but for mutations (create / append / update / delete / move / surgical edits). |
Read and write are independent, so an audit account can be read-only on most of the vault but write-only to a Drafts/ folder. The startup log line and --help advertise the active scope. The allowlist is enforced at a single path-resolution choke point so every tool inherits it.
Persistent Caches
Two caches live under <vault>/.obsidian/cache/:
File | Purpose |
| mtime-keyed snapshot of recently read notes. The next process start hydrates from this and stat-passes against the live filesystem; only changed notes are re-read. |
| Persisted embeddings for semantic search (only present once |
Both are vault-local, are excluded from vault scans (.obsidian/ is pruned), and can be deleted at any time. Persistence can be turned off entirely with OBSIDIAN_CACHE_DISABLED=1.
Semantic Search Provider
The semantic-search tools (index_vault, search_semantic, find_similar_notes) need an embedding provider. Configure via env:
Env var | Default | Notes |
|
|
|
|
| Provider-specific model identifier. |
|
| Base URL. |
|
| Required for hosted providers. |
For local Ollama: install Ollama, then ollama pull nomic-embed-text. The semantic tools register even when no provider is configured, so they're discoverable; calls return a configuration hint until set up.
Observability
Logs stream to stderr as either plain text (default) or single-line JSON, controlled by LOG_LEVEL (debug/info/warn/error/silent) and LOG_FORMAT (text/json).
The server also declares the MCP logging capability, so every log line is forwarded to the connected client as a notifications/message frame alongside tool responses. Clients that honor logging/setLevel can filter server-side logs at runtime without restarting. Claude Desktop surfaces these in its MCP DevTools pane; most other clients currently ignore them, so this is useful primarily for self-hosters and tooling authors.
Security
Vault boundary — every tool and resource routes through a single path resolver that rejects
..traversal, null-byte injection, and symlinks pointing outside the vault (ancestor-realpath check).Excluded directories —
.obsidian,.git, and.trashare pruned at traversal time and at resolution time, so nested occurrences never leak back to clients.HTTP transport — binds to
127.0.0.1by default with DNS rebinding protection (host-header allowlist). Optional--token=<secret>requiresAuthorization: Bearer <secret>on every/mcprequest; compared in constant time.Error sanitization — filesystem error messages are stripped of absolute host paths before being returned to MCP clients. Uncaught HTTP errors respond with a generic
Internal server errorbody; full detail stays in the server log.Atomic writes — every note write (
create_note,append,prepend,update_frontmatter, canvas mutations) stages content to a sibling temp file then renames onto the target, so a crash or kill mid-write never leaves a truncated file. Combined with per-path locks for the full read-modify-write cycle, concurrent callers can't lose each other's updates. Theinstallsubcommand uses the same pattern and keeps a backup of the previous config.Rate limiting + CORS allowlist — optional
--rate-limitcaps per-IP request volume;--allow-originrestricts browser-facing CORS./healthand/versionstay reachable under load for monitoring.Request timeout — HTTP POST requests are capped at 2 minutes of wall-clock time. Long-lived SSE GET streams are exempt so idle clients aren't reaped.
Process supervision —
uncaughtExceptionexits cleanly so systemd/Docker/npx supervisors can restart;unhandledRejectionlogs but doesn't kill the process.
Wikilink Resolution
[[Target]] resolves in the same order Obsidian does:
Exact relative-path match (case-insensitive).
Path-suffix match (e.g.
[[projects/foo]]pickswork/projects/foo.md).Basename match. When multiple notes share a basename, the one that shares the deepest directory prefix with the linking note wins; ties break on shortest overall path.
Frontmatter
aliases—[[Display Name]]resolves to a note whose frontmatter declares that alias.aliases,Aliases, andALIASESare all recognized.
Tag extraction is similarly case-tolerant: tags, Tags, TAGS, tag, and Tag frontmatter keys are all read.
Tool Reference
Read
Tool | Description | Key Parameters |
| Full-text search across all notes (cached) |
|
| Read a note whole, or by |
|
| List notes in the vault or a folder |
|
| Get today's (or a specific date's) daily note |
|
| Find notes by frontmatter property values |
|
| Notes sorted by mtime; optional ISO-or-relative |
|
| Vault counts, bytes, words, tag coverage, most-recent note |
|
| Translate frontmatter alias (or basename) to note path |
|
Write
Tool | Description | Key Parameters |
| Create a new note with content and frontmatter |
|
| Append content to an existing note |
|
| Prepend content after frontmatter |
|
| Update frontmatter properties on a note |
|
| Create today's daily note from template |
|
| Move or rename a note; rewrites references across the vault |
|
| Delete a note (trash by default); optional elicitation on permanent |
|
Section-level edits
Tool | Description | Key Parameters |
| Replace the body under a heading path (heading kept) |
|
| Insert at |
|
| Return the heading outline of a note as an indented tree |
|
| Find/replace within one note (literal or regex, with match-count guard) |
|
| Replace content of a paragraph tagged |
|
Tags
Tool | Description | Key Parameters |
| Get all tags and their usage counts |
|
| Find all notes with a specific tag |
|
| Rewrite inline + frontmatter occurrences vault-wide; hierarchical |
|
Links & graph
Tool | Description | Key Parameters |
| Get all notes that link to a given note |
|
| Get all links from a given note |
|
| Find notes with no links in or out |
|
| Detect links pointing to non-existent notes |
|
| Get notes connected within N link hops |
|
Canvas
Tool | Description | Key Parameters |
| List all | (none) |
| Read a |
|
| Add a node to a canvas |
|
| Add an edge between two canvas nodes |
|
Bases
Tool | Description | Key Parameters |
| Enumerate | (none) |
| Parse a Base file (filters, properties, views) |
|
| Run a Base's filter DSL against the vault |
|
Attachments
Tool | Description | Key Parameters |
| Enumerate every non-md/canvas/base file |
|
| Attachments not referenced via embeds or markdown links |
|
| Return image / audio / blob content (5 MB default cap) |
|
Semantic search
Tool | Description | Key Parameters |
| Build / refresh the embedding index (incremental, progress events) |
|
| Cosine search the embedding index for a natural-language query |
|
| Surface notes most similar to a source note (no live API call) |
|
MCP Resources
Resources provide a URI-based way to access vault data:
Resource URI | Description |
| Read any note by its vault-relative path |
| Full tag index with file lists (JSON) |
| Today's daily note content |
Troubleshooting
Tools Don't Show Up in Claude Desktop
MCP clients only re-read their config on startup. After editing claude_desktop_config.json (or running npx obsidian-mcp-pro install), fully quit Claude Desktop (⌘Q on macOS, tray → Quit on Windows) and relaunch. Hot-reloading the window is not enough.
"No Obsidian vault configured" on Startup
The server couldn't locate a vault. Resolution order is:
OBSIDIAN_VAULT_PATHenv var (absolute path) — always wins if set.OBSIDIAN_VAULT_NAMEenv var — picks a named vault from Obsidian's global config.Auto-detection — reads
obsidian.json(platform-specific) and uses the first valid vault found.
Fastest fix: set OBSIDIAN_VAULT_PATH in the env block of your MCP client's config. Auto-detection fails when Obsidian has never been launched, obsidian.json is missing/corrupt, or all registered vaults resolve to paths that no longer exist.
"Path traversal detected" Error on Tool Calls
All tool paths must be vault-relative (e.g. notes/hello.md), never absolute (/Users/me/vault/notes/hello.md) or containing ... The agent normally gets this right — if you see this error, check whether a custom instruction is asking it to use absolute paths.
HTTP Transport Returns 401 Unauthorized
The server was started with --token=<secret> (or MCP_HTTP_TOKEN is set in the environment) but the client isn't sending a matching Authorization: Bearer <secret> header. Verify the token value and that the header is present — comparison is case-sensitive and constant-time.
HTTP Transport Returns 429 Too Many Requests
--rate-limit=<n> is set and the client exceeded N requests in the last 60 seconds from that IP. Either raise the limit, drop it, or wait 60 seconds. /health and /version are exempt if you need to check liveness under load.
Daily-Note Path Is Wrong or Unresolved
The server reads .obsidian/daily-notes.json from the vault for the filename format and folder. If that file doesn't exist (the Daily Notes core plugin has never been configured), the server falls back to YYYY-MM-DD.md in the vault root. Configure the plugin once inside Obsidian and the server picks it up automatically.
npx obsidian-mcp-pro Silently Exits With Code 0
This was a bug in versions < 1.4.1 where the npx-symlinked CLI entry failed to detect itself as the entrypoint. Upgrade: npx -y obsidian-mcp-pro@latest install.
Windows: "EPERM: operation not permitted" During Writes
The server retries these transparently (Windows holds stricter file-sharing locks than POSIX) — if you still see the error, it usually means antivirus or a sync client (OneDrive, Dropbox) is holding the file. Exclude the vault folder from real-time antivirus scanning, or pause the sync client during heavy agent sessions.
Development
# Clone the repository
git clone https://github.com/rps321321/obsidian-mcp-pro.git
cd obsidian-mcp-pro
# Install dependencies
npm install
# Build
npm run build
# Run in development (watch mode)
npm run dev
# Start the server locally
OBSIDIAN_VAULT_PATH=/path/to/vault npm startProject Structure
src/
index.ts # Server entry, CLI parser, resource + prompt registration
config.ts # Vault detection, daily-notes config loader
http-server.ts # Streamable HTTP transport, Bearer auth, session TTL
install.ts # `install` subcommand (Claude Desktop / Cursor)
types.ts # Shared TypeScript interfaces
lib/
vault.ts # Core vault ops (read, search, list, per-file locks,
# symlink boundary, canvas + base + attachment round-trip)
permissions.ts # OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS allowlist
markdown.ts # Frontmatter, wikilinks, tags, alias-aware resolver
sections.ts # Heading parser, block-id parser, section bounds
tag-rewriter.ts # Vault-wide tag rewriting (inline + frontmatter)
link-rewriter.ts # Plan/apply edit pipeline used by move + delete
bases.ts # Bases YAML parser + filter DSL evaluator
chunker.ts # Heading-aware chunking for embeddings
embedding-providers.ts# Ollama + OpenAI providers
embedding-store.ts # Persistent vector index, cosine search
index-cache.ts # mtime-keyed content cache (in-memory + on-disk)
progress.ts # MCP progress-notification helper
mime.ts # extension -> MIME map for attachments
dates.ts # Moment-style date format for daily-note filenames
errors.ts # sanitizeError: strips absolute paths from fs errors
concurrency.ts # Bounded-concurrency fan-out helper
logger.ts # Leveled stderr logger (text + JSON modes)
tools/
read.ts # search, get, list, daily, frontmatter, recent, stats, alias
write.ts # create, append, prepend, update_frontmatter, move, delete
sections.ts # update_section, insert_at_section, list_sections,
# replace_in_note, edit_block
tags.ts # get_tags, search_by_tag, rename_tag
links.ts # backlinks, outlinks, orphans, broken, graph_neighbors
canvas.ts # list, read, add_node, add_edge
bases.ts # list_bases, read_base, query_base
attachments.ts # list_attachments, find_unused_attachments, get_attachment
semantic.ts # index_vault, search_semantic, find_similar_notes
prompts.ts # daily-review, weekly-rollup, find-stale-notes,
# extract-action-items, build-moc
__tests__/
vault.test.ts markdown.test.ts tools.test.ts
security.test.ts http-server.test.ts semantics.test.ts
logger.test.ts sections.test.ts tag-rewriter.test.ts
bases.test.ts permissions.test.ts index-cache.test.ts
chunker.test.ts embedding-store.test.ts errors.test.ts
link-rewriter.test.ts
handlers/
read.test.ts write.test.ts tags.test.ts
links.test.ts canvas.test.ts attachments.test.ts
semantic.test.ts harness.tsTesting
npm test438 tests covering vault operations, atomic writes + concurrent-mutation races, markdown parsing (frontmatter, wikilinks, tags, fenced + indented code blocks, multi-backtick inline code), section / block-id parsing, tag rewriting (inline + frontmatter, hierarchical sub-tags), Bases filter DSL, attachment classification, semantic chunking + cosine ranking + persistent embedding store, moment-token date formatting, canvas round-trip fidelity, HTTP transport (Bearer auth, oversize-body, CORS allowlist with Vary: Origin, per-IP rate limiting, /version), leveled logger (text + JSON output), folder-permission allowlist, mtime-cache rehydration across simulated restarts, vault-wide link rewriting on move_note and delete_note (TOCTOU correctness, control-char injection escape), and security regression guards (symlink escape, case-only rename, path-leak sanitization, cross-process exclusive-create). Handler tests exercise every tool through a real MCP client/server pair via InMemoryTransport.
npm run lint # eslint v9 + typescript-eslint v8 (flat config)
npm run lint:fix # auto-fixWhat's New
Unreleased brings the largest feature drop since v1.0:
Surgical edits by heading and block id.
update_section,insert_at_section,list_sections,replace_in_note,edit_block, plus fragment retrieval modes onget_note(section,block,lines).Bases support.
list_bases,read_base,query_basefor Obsidian's database-view files. First filesystem-only MCP server to ship native Bases.Semantic search.
index_vault,search_semantic,find_similar_notesbacked by Ollama (default) or OpenAI. Persistent vector index with content-hash incremental updates.Attachments.
list_attachments,find_unused_attachments,get_attachment(returns image / audio / blob bytes inline).Tag renames vault-wide.
rename_tagrewrites both inline#tagand frontmattertags:(hierarchical mode rebases nested sub-tags).Folder-scoped permissions.
OBSIDIAN_READ_PATHS/OBSIDIAN_WRITE_PATHSallowlists.Persistent mtime cache. Vault-wide scans (
get_tags,search_notes,search_by_tag) hydrate from<vault>/.obsidian/cache/mcp-pro-index-cache.jsonafter a restart and stat-pass against current state, only re-reading changed notes.Quick wins.
get_recent_notes,get_vault_stats,resolve_alias.MCP prompts.
daily-review,weekly-rollup,find-stale-notes,extract-action-items,build-moc.Progress notifications on
rename_tag,find_unused_attachments,index_vault.Elicitation on
delete_note(permanent: true)for clients that support it.eslint wired up with typescript-eslint flat config;
npm run lintandlint:fix.
v1.7.0 — delete_note reference handling:
delete_notecan strip references vault-wide whenpermanent: trueis paired withremoveReferences: true. Wikilinks fall back to alias-or-basename, markdown links fall back to visible text, embeds drop entirely, fragments are discarded. Trash-mode (default) leaves references intact since trashed files stay recoverable.Concurrent-safe rewrites —
move_note(withupdateLinks: true) anddelete_note(withremoveReferences: true) serialize per vault, removing the partial-failure mode for parallel rewrite-bearing operations.
v1.6.0 — Obsidian-parity link maintenance:
move_noterewrites references across the vault by default, matching Obsidian's "Automatically update internal links" behavior. Wikilinks (with aliases / fragments preserved), markdown links, and canvasnodes[].filefields all follow the moved file. Output form is preserved when possible.TOCTOU correctness — every edit's pre-edit content is verified before splicing, so a parallel
write_notebetween plan and apply is surfaced infailedReferrersrather than corrupting referrers silently.Control-char injection defense —
sanitizeErrorand the newescapeControlCharsstrip newlines/control bytes from any caller-controlled string before it reaches LLM context. Closes a prompt-injection vector via attacker-named filenames.
Full version history in CHANGELOG.md.
License
MIT
Contributing
Contributions welcome! Please open an issue first to discuss what you'd like to change. Pull requests without a corresponding issue may be closed.
If you're adding or editing a tool, read docs/TOOL_AUTHORING.md first — it documents the description, schema, and annotation conventions that keep every tool at A-grade quality.
Acknowledgments
Vault-wide link rewriting on
move_note(#3, #4) and thesanitizeErrordefense-in-depth hardening contributed by @brentkearney.
For the full list of everyone who's contributed, see the contributors page.
Maintenance
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/rps321321/obsidian-mcp-pro'
If you have feedback or need assistance with the MCP directory API, please join our Discord server