# rps321321/obsidian-mcp-pro [Health: Active]

**Category:** 🧠 Knowledge & Memory  
**Repository:** https://github.com/rps321321/obsidian-mcp-pro  
**GitHub Stars:** 33  
**npm Downloads (last month):** 2118  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/rps321321-obsidian-mcp-pro

## Description
Feature-complete Obsidian vault MCP server with 23 tools and 3 resources. Full-text search, note CRUD, frontmatter queries, tag management, backlinks, graph traversal (BFS up to 5 hops), orphan/broken link detection, and canvas support. Auto-detects vault, path traversal protection, MIT licensed.

## Tools
Capabilities this server exposes over MCP:

- **search_notes** — Full-text search across all notes in the vault. Ranks literal matches with title/path focus and repeated-line dampening, then returns matching note paths grouped with the line numbers and query-centered snippet content of each matching line. Use to locate notes containing a phrase, keyword, or code fragment; pair with get_note to retrieve full bodies.
- **get_note** — Read a note in full or as a fragment. With no fragment options, returns parsed frontmatter (as a labeled header), a flat list of inline #tags, and the body. With `section`, returns just the body under that heading (path-form like 'Tasks/Today' is supported). With `block`, returns the paragraph or block tagged `^id`. With `lines`, returns the inclusive 1-indexed line range. Fragment modes skip the frontmatter/tag header and return raw text — use them to keep token usage tight on long notes.
- **list_notes** — Enumerate every markdown note in the vault (or a single folder), returning a sorted list of relative paths along with the total count. Truncates output to `limit` entries but still reports the total. Use to browse vault structure, build a file picker, or enumerate targets for batch processing.
- **get_daily_note** — Read the daily note for today or for a specific date, resolved via the vault's configured daily-note folder and filename format. Returns the note path, parsed frontmatter (as a labeled header block), and body. Errors if no daily note exists for that date — use create_daily_note to create one.
- **search_by_frontmatter** — Find notes whose YAML frontmatter contains a given property/value pair. Property names and values are matched case-insensitively; for array-valued properties, a match is declared if any element matches. Returns matching note paths with their full frontmatter. Use to filter notes by metadata like status, type, or tags stored in frontmatter.
- **get_recent_notes** — List notes ordered by most-recently-modified first. Optional `since` filter accepts an ISO date (e.g. '2026-04-01') or a relative span ('7d', '24h', '2w'); only notes modified at or after that time are returned. Use to surface what you've been working on, build a 'what changed this week' digest, or pick targets for review.
- **get_vault_stats** — Return a quick health snapshot of the vault: note count, total bytes, total words, unique tag count, untagged-note count, and the most-recently-modified note. Useful for dashboards and 'is this vault healthy?' checks. Reads through the mtime cache so repeat calls are cheap.
- **resolve_alias** — Find every note whose frontmatter `aliases:` field contains the given name (case-insensitive). With `includeBasename: true`, also matches notes whose filename (without `.md`) equals the name — Obsidian's resolution fallback when no alias matches. Use to translate a human-friendly title like 'My Project' into the actual note path before calling get_note.
- **create_note** — Create a new markdown note at the given path with body content and optional YAML frontmatter. Fails (does not overwrite) if a note already exists at that path — use append_to_note, prepend_to_note, or update_frontmatter for existing notes. Missing directories are created automatically, and a .md extension is appended if omitted.
- **append_to_note** — Append text to the end of an existing note without altering prior content. By default, inserts a leading newline if the file does not already end in one, so appended content starts on its own line. Use for log entries, running lists, or adding new sections. Fails if the note does not exist — use create_note to make a new note first.
- **prepend_to_note** — Insert content at the top of an existing note's body, immediately after the YAML frontmatter block if one is present (so metadata stays at the top of the file). Use for adding new items to the front of a running list, pinning context, or inserting TL;DR sections. Fails if the note does not exist.
- **update_frontmatter** — Merge new key-value pairs into a note's YAML frontmatter, preserving any keys not mentioned and leaving the body content untouched. Keys in the payload overwrite existing values. Creates a frontmatter block if the note has none. Returns a count of properties written. Use to set status fields, tags arrays, or other metadata without rewriting the body.

Note: The YAML block is regenerated on each update — comments, custom quoting, multi-line scalar style, blank lines, and key ordering inside the block are normalized. Key *presence and values* are preserved; formatting is not.
- **create_daily_note** — Create a daily note for today (or a specific date) in the vault's configured daily-note folder using its configured filename format. Optionally seed the note from a template file with Obsidian-style placeholder substitution: {{date}} and {{title}} → the formatted date; {{time}} → local HH:mm; {{date:FORMAT}} / {{time:FORMAT}} → custom moment-style format. Fails if the daily note already exists.
- **move_note** — Move or rename a note within the vault, preserving its full content. Parent folders at the destination are created as needed. By default, wikilinks and file references are updated, matching Obsidian's "Automatically update internal links" behavior; this rewrite requires `confirmPath` to match the destination path after .md normalization. Pass `updateLinks: false` to skip the rewrite scan (faster on large vaults; pair with `find_broken_links` if you need to audit afterward). A .md extension is added automatically if omitted from either path.
- **delete_note** — Delete a note. By default the file is moved to the vault's .trash folder (recoverable inside Obsidian); pass permanent=true to unlink it from disk immediately. When permanent=true, you can additionally pass removeReferences=true to strip wikilinks and markdown links to the deleted file across the vault (embeds are removed entirely; plain links fall back to their visible text). References are never rewritten when the file moves to .trash, since trashed files are recoverable.
- **list_tags** — Enumerate every unique tag used across the vault along with the number of notes each tag appears in. Detects tags from both inline #hashtags and YAML frontmatter, normalizes them case-insensitively, and returns a sorted list plus the total unique tag count. Use to build a tag cloud, pick categories, audit taxonomy, or discover available tags before calling search_by_tag.
- **search_by_tag** — Find all notes tagged with a specific tag, including nested sub-tags (searching 'project' matches both #project and #project/alpha). Detects tags from both inline #hashtags and YAML frontmatter. Returns matching note paths with optional content previews. Use to collect notes belonging to a topic, area, or workflow stage.
- **rename_tag** — Rename a tag everywhere it appears across the vault, in both inline #tags and frontmatter `tags:` fields. Non-dry-run rewrites require `confirmTag` to match the new tag name. With `hierarchical: true` (default), nested tags also rebase: renaming `project` to `client` also renames `project/alpha` → `client/alpha`. With `dryRun: true`, returns the planned counts without writing. Strip the leading `#` from oldName/newName — they're tag names, not tag tokens.
- **get_backlinks** — List all notes that contain a wikilink pointing to the target note. Each result includes the source note path, line number, and the surrounding line text for context. Use to understand which notes reference a topic, or to assess the impact of renaming or deleting a note. Accepts paths with or without .md extension; falls back to basename matching if exact match fails.
- **get_outlinks** — List every outgoing wikilink from a note, partitioned into valid links (resolve to an existing note), broken links (target not found), and file embeds (![[...]]). Returns the raw link text and resolved paths. Use to audit a note's references, detect broken links, or follow downstream dependencies.
- **find_orphans** — Identify disconnected notes in the vault's link graph, classified into three groups: fully isolated (no links in or out), no-backlinks (nothing links to them), and no-outlinks (they link to nothing). Returns counts per category and an example list per category, capped by maxResults. Use to surface abandoned notes, missing hub pages, or candidates for archiving.
- **find_broken_links** — Scan notes for wikilinks ([[target]]) whose target does not resolve to any existing note in the vault. Returns a per-source report grouping each note with its broken link text and line numbers, plus a total count. Use after renaming, moving, or deleting notes to catch dangling references. Resolution uses the whole vault even when scanning a single folder, so only truly unresolvable links are reported.
- **get_graph_neighbors** — Traverse the wikilink graph outward from a starting note and return every note reachable within N hops, grouped by depth level with an indented tree visualization. Each neighbor is tagged with its hop distance and direction (inbound = reached via backlink, outbound = reached via outlink). Use to explore a topic cluster, map a note's local neighborhood, or find related notes beyond direct links. Accepts paths with or without .md extension.
- **list_canvases** — Enumerate every Obsidian canvas file (.canvas) anywhere in the vault, returning a numbered list of relative paths and the total count. Takes no parameters — scans the entire vault. Use to discover available canvases before calling read_canvas, add_canvas_node, or add_canvas_edge.
- **read_canvas** — Read an Obsidian canvas file (.canvas, JSON format) and return a bounded human-readable summary of its structure: total node/edge counts, up to 200 nodes with id/type/position/size/content preview, and up to 200 edges with source/target node ids plus optional label. Use to inspect or navigate a canvas before calling add_canvas_node or add_canvas_edge.
- **add_canvas_node** — Add a new node to an Obsidian canvas and persist the updated file. Supports four node types: 'text' (markdown block), 'file' (embedded vault note reference), 'link' (external URL), and 'group' (labeled container). Returns the generated node UUID, needed to connect nodes via add_canvas_edge. When neither x nor y is supplied, the new node is auto-positioned at (50 * existing_count, 50 * existing_count) to avoid stacking multiple defaulted nodes at the origin. Supplying an explicit x or y always overrides this stagger.
- **add_canvas_edge** — Create a directed edge connecting two existing canvas nodes. Both fromNode and toNode must already exist on the canvas (use read_canvas to list node ids, or capture the id returned by add_canvas_node). Optional fromSide/toSide control which face of each node the edge anchors to. Returns the generated edge UUID.
- **update_section** — Replace the body of a specific section (everything between a heading and the next heading at any level). The heading line itself is preserved. `section` is a heading path: `'Tasks'`, `'Project A/Status'`, etc. - case-insensitive and whitespace-tolerant. Use this instead of rewriting the whole file when you only need to update one section.
- **insert_at_section** — Insert content into a specific section without replacing it. `position` controls where: 'before' inserts above the heading, 'after-heading' inserts immediately under the heading line (at the top of the section body), 'append' inserts at the end of the section's body just before the next heading. Use to add a new bullet or paragraph without rewriting the section.
- **list_sections** — List all headings in a note as a tree of paths (with depth). Useful for discovering valid `section` arguments before calling get_note, update_section, or insert_at_section.
- **replace_in_note** — Search-and-replace within a single note. Supports literal strings or regex patterns. With `expectedCount`, the operation refuses to commit unless that many matches are present, guarding against accidental over-replacement when an LLM drafts a pattern that's too broad. Returns the count of replacements made.
- **edit_block** — Replace the content of a block tagged with `^id`. The trailing `^id` anchor is preserved on the last line of the new content so existing transclusions (`![[note#^id]]`) keep working. Use to update a single paragraph or list item that other notes reference.
- **list_bases** — Enumerate every Obsidian Bases (`.base`) file in the vault. Bases are YAML-defined database views over notes (filters, properties, table/calendar/kanban views). Returns a sorted list of relative paths plus the total count. Pair with read_base or query_base.
- **read_base** — Return the parsed contents of a Base file: filters, properties, view definitions, and any unrecognized fields. Use to discover what queries a Base supports before calling query_base.
- **query_base** — Run a Base file's filters against the vault and return matching note paths. Optionally pick a named view to apply that view's filters and ordering on top of the base-level filters. Supported filter syntax (subset of Obsidian's full DSL): chained methods `file.hasTag("tag")`, `file.hasProperty("key")`, `file.inFolder("path")`, `file.linksTo("target")`, `file.name.contains("x")`/`.startsWith`/`.endsWith`/`.equals`, plus `.isEmpty`/`.isNotEmpty` on any value; legacy function form `taggedWith(file, "tag")`; comparisons `key == "val"`, `key != x`, `key contains x`, `>=`, `<=`, `>`, `<`; combinators `and:`, `or:`, `not:`. Recognized file properties: file.name, file.basename, file.folder, file.ext, file.path, file.size, file.ctime, file.mtime, file.tags, file.properties, file.links, file.embeds, file.backlinks. Unsupported clauses are reported as warnings and treated as no-match.
- **list_attachments** — Enumerate every non-markdown file in the vault — images, PDFs, audio/video clips, anything pasted in beyond notes/canvases/Bases. Returns a sorted list of relative paths plus a per-extension count summary. Use to audit assets, find duplicates by name, or pick targets for find_unused_attachments.
- **find_unused_attachments** — Locate attachments that no note references — neither via `![[file]]` embeds nor `[text](file)` markdown links. Useful for vault hygiene before archiving or before running a sync. Pair the output with `delete` operations from your shell, since this tool deliberately doesn't unlink files.
- **get_attachment** — Read an attachment file and return its bytes to the client. Images come back as `image` content blocks (rendered inline by Claude / Cursor), audio as `audio` blocks, everything else as a base64 `resource` block with a vault:// URI. Caps at 5 MB by default to keep token usage sane; raise via `maxBytes` up to 50 MB. The attachment must be inside the vault — markdown notes (.md), canvases (.canvas), and Bases (.base) are deliberately rejected so callers don't accidentally pull text-format files through this binary path; use get_note / read_canvas / read_base instead.
- **index_vault** — Build or refresh the embedding index used by `search_semantic` and `find_similar_notes`. Splits readable notes into heading-aware chunks, sends those chunks to the configured embedding provider (Ollama by default, OpenAI optional), and persists the index to `<vault>/.obsidian/cache/mcp-pro-embeddings.json`. Requires `confirm: "send-vault-text-to-embedding-provider"` so callers explicitly acknowledge that vault text will leave this tool boundary. Incremental: notes whose content hash matches the prior pass are skipped. Use `force: true` to re-embed everything (e.g., after switching models). Emits progress notifications when the client subscribes.
- **search_semantic** — Search notes by meaning rather than keywords. Embeds the query with the configured provider, scores every chunk in the persisted index by cosine similarity, ranks one result per note using the best chunk plus a small top-chunk focus signal, and returns the best chunk as the snippet source. Run `index_vault` first to populate the index — this tool does not auto-index because the user should know they're paying the embedding cost. Pair with `get_note` to retrieve full bodies after picking a hit.
- **find_similar_notes** — Given a note path, return the K most semantically similar notes from the index (excluding the source note). Uses the source note's existing chunk embeddings and anchors the source query to chunks aligned with the note's opening topic — no live API call to the embedding provider, so this is fast and free. Run `index_vault` first to populate embeddings for both the source and the candidates.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "obsidian-mcp-pro": {
    "command": "npx",
    "args": ["-y","obsidian-mcp-pro"],
    "env": {
      "OBSIDIAN_VAULT_PATH": "",
      "OBSIDIAN_READ_PATHS": "",
      "OBSIDIAN_WRITE_PATHS": ""
    }
  }
}
```

**Requires environment variables:** `OBSIDIAN_VAULT_PATH`, `OBSIDIAN_READ_PATHS`, `OBSIDIAN_WRITE_PATHS` — the values above are empty placeholders; fill in real credentials before running (see the repository for what each one is for).

## Documentation

## What rps321321/obsidian-mcp-pro does

rps321321/obsidian-mcp-pro gives MCP clients access to an Obsidian vault as a structured knowledge and memory system. It covers note discovery, full-text search, frontmatter filtering, aliases, daily notes, recent-file views, vault statistics, and focused content retrieval. Agents can create, append to, prepend, move, rename, and delete notes, as well as update metadata without replacing the note body.

The server also exposes Obsidian’s relationship-oriented features. It can inspect backlinks and outlinks, find isolated or unreferenced notes, detect broken wikilinks, and traverse nearby notes in the vault graph. Canvas files can be listed, summarized, and modified with nodes and directed edges.

## How it works

Tools operate against paths relative to the configured vault. Search results include matching paths, line numbers, and snippets, while note reads can be narrowed to a heading path, block reference, or inclusive line range to reduce returned content. Frontmatter and inline tags are parsed for metadata queries and tag operations.

Move operations can update wikilinks, Markdown links, and canvas references across the vault. Deletions go to Obsidian’s `.trash` folder by default, with a separate permanent-delete option. Bulk or destructive operations use confirmation values such as `confirmPath`, `confirmTag`, or a deletion confirmation.

Optional semantic indexing chunks notes, creates embeddings through Ollama or OpenAI, and stores vectors in the vault’s Obsidian cache directory. Indexing requires the explicit confirmation string `send-vault-text-to-embedding-provider` because readable note content is sent to the selected embedding service.

## Setup and configuration

The package can be launched with `npx -y obsidian-mcp-pro`, which installs the latest published npm release. The runtime requirement is Node.js 24 or newer. The server needs access to an Obsidian vault and can automatically detect the vault in supported configurations.

Folder-scoped access can be restricted with `OBSIDIAN_READ_PATHS` and `OBSIDIAN_WRITE_PATHS`. These allowlists are applied during path resolution and can limit which locations tools may read or modify. An Obsidian plugin is also available for running the server inside the app with a settings interface.

## Tools and capabilities

- Search notes with ranked, query-centered snippets and line numbers.
- Read full notes or selected sections, blocks, and line ranges.
- Filter notes by frontmatter, tags, aliases, modification time, or folder.
- Create notes, update sections, edit blocks, and merge frontmatter values.
- Create and retrieve daily notes using the vault’s date configuration and templates.
- Rename tags across inline hashtags and YAML tag fields, including nested tags.
- Inspect backlinks, outlinks, orphan notes, broken links, and graph neighbors.
- Read canvases and add text, file, link, or group nodes plus edges.
- Use MCP resources for notes, tags, and the daily note, along with starter prompts for reviews, rollups, action extraction, and Maps of Content.

## Limitations and notes

Frontmatter updates preserve keys and values but normalize formatting inside the YAML block, including ordering, comments, quoting, and multiline style. Fragment reads return raw text without the normal frontmatter and tag header. Semantic search is optional and requires an embedding provider; its indexing workflow sends readable note chunks outside the local process. Large canvas responses are bounded, and attachment retrieval has a default 5 MB limit with a 50 MB hard cap.

_Full upstream README: https://allmcps.com/mcp/rps321321-obsidian-mcp-pro/readme_

