obsidian-mcp-pro (rps321321/obsidian-mcp-pro) is an MCP server listed on the M8ven Trust Index. It scores 64 out of 100, grade C. It declares 41 tools. No publisher has claimed this listing.

C
Caution
64/100

obsidian-mcp-pro

The most feature-complete MCP server for Obsidian vaults. 23 tools and 3 resources for search, read, write, tags, link analysis, graph traversal, and canvas support.

Caution. Specific findings reduced this grade. They are listed on the page. Grades reflect the full trust pyramid: code, verification depth, and reputation. New projects cap at C until adoption is earned.

How we verified

⚡ Live Monitored: not connected

Verified is a snapshot. Live keeps it current, and builds your track record.

⚡ Connect GitHub → continuous verification on every pushwhy connect →

Who stands behind it

rps321321

Source: Glama

Is this your MCP?

Claim it to get a verified publisher badge, a free copy of our full audit findings, and direct contact for any high-priority issues we find. Or connect your repo for our deepest verification, Live Monitored: read-only, revoke anytime. What we access →

Install from

The grade above is for the source repository. Registries can serve a different version, so we mark the ones we were not able to read.

// key findings
⚠️
Tool annotations don’t match behaviour
1 read-only tool performs write/delete/exec — get_note (line 55: /^(\d+)(?:-(\d+))?$/.exec(value))
⚠️
Tool descriptions don’t match what handlers do
1 tool describes read intent but its handler mutates — get_note (line 55: /^(\d+)(?:-(\d+))?$/.exec(value))
No credential exfiltration, no sensitive file access, no obfuscation
Static analysis found nothing flowing your secrets to unexpected places.
Open source with a license and README
Anyone can audit the code, the license is declared, and the publisher documents what it does.
🔐
You'll be asked for 3 credentials: MCP_HTTP_TOKEN, OBSIDIAN_EMBEDDING_API_KEY, OPENAI_API_KEY
These are read from process.env at runtime. Make sure you trust where they’ll be sent.
// tools this server exposes41 tools

These names and descriptions are the publisher's own, read from the source code. We print them as written. Our assessment is the findings above, not this list.

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 `maxByte

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")

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 canv

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 nei

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 generate

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 withou

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 a

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

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 exp

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

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 bl

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 sta

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

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 Proj

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 w

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

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 replacemen

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.

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-embedding

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 `inde

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

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,

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, ar

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` → `

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 ext

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 cre

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 a

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

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 de

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 va

// environment variables
To run this server yourself, you supply these values. They go in your own MCP client configuration and stay on your machine. The secret label means the value is sensitive, not that the server mishandles it.
configLOG_FORMAT
configLOG_LEVEL
🔐 secretMCP_HTTP_TOKENyour-secret npx -y obsidian-mcp-pro --transport=http --port=3333
configOBSIDIAN_CACHE_DISABLEDThe embedding cache is vault-local, excluded from vault scans (.obsidian/ is pruned), and can be deleted at any time. Persistence can be turned off with =1.
🔐 secretOBSIDIAN_EMBEDDING_API_KEYOPENAI_API_KEY falls back if unset or blank Required for hosted providers.
configOBSIDIAN_EMBEDDING_MODELnomic-embed-text (Ollama), text-embedding-3-small (OpenAI) if unset or blank Provider-specific model identifier.
configOBSIDIAN_EMBEDDING_PROVIDERollama if unset or blank ollama, openai, or none to disable.
configOBSIDIAN_EMBEDDING_URL
configOBSIDIAN_READ_PATHSFolder-scoped permissions: / OBSIDIAN_WRITE_PATHS allowlists gate every tool at the path-resolution choke point
configOBSIDIAN_VAULT_NAME2 Environment variable to select a vault by folder name when multiple vaults exist
configOBSIDIAN_VAULT_PATH"": "/path/to/your/vault"
configOBSIDIAN_WRITE_PATHSFolder-scoped permissions: OBSIDIAN_READ_PATHS / allowlists gate every tool at the path-resolution choke point
🔐 secretOPENAI_API_KEYOBSIDIAN_EMBEDDING_API_KEY falls back if unset or blank Required for hosted providers.
configXDG_CONFIG_HOME
// quality suggestions

All four hints declared on every tool

26/41 tools missing one or more hints — list_attachments (missing: destructiveHint); find_unused_attachments (missing: destructiveHint); get_attachment (missing: destructiveHint), +23 more. OpenAI's directory rejects tools where any of the four hints are missing or non-boolean.

For every tool, set all four hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) to explicit true/false values that match the handler’s actual behaviour.

Tool annotations match behaviour

1 read-only tool performs write/delete/exec — get_note (line 55: /^(\d+)(?:-(\d+))?$/.exec(value))

Either remove the readOnlyHint:true annotation, or remove the write/delete call from the tool handler.

Descriptions match behaviour

1 tool describes read intent but its handler mutates — get_note (line 55: /^(\d+)(?:-(\d+))?$/.exec(value))

Rename the tool, rewrite the description, or move the side-effect into a separate clearly-named tool.

Tool inputs are validated

39/41 tool handlers declare input schemas (95%)

Declare an inputSchema with zod/joi/yup on every tool definition.

Shell command execution

7 child_process calls — runs shell commands

Prefer library functions over shell-outs. If you must shell out, ensure all inputs are properly escaped.

Dependency freshness

1/4 production deps stale: gray-matter@2023-07-12 (2.9y)

Tool description accuracy

get_note: description implies read-only but handler writes/deletes/executes

Update tool descriptions to accurately reflect all capabilities — especially write, delete, or execute operations.

Claim the listing to review these findings one by one and send us a correction where you disagree, straight to the team. Claiming also means we tell you when the grade moves, and reach you first if we find anything urgent.

// full audit trail
The findings above are the summary. The full trail, every check we ran, each deduction, the network hosts observed and the dependency advisories, goes to verified publishers, along with an alert whenever a new one lands. Verified publishers can also review each finding and dispute it in one click. Publisher corrections have sharpened several of our checks this month, because the maintainer knows the codebase better than any scanner.
// improvement guidance — verified publishers only
We have 6 concrete improvements we can share with the publisher of this MCP. Each comes with specific guidance to raise the trust score.
// embed badge in your README
[![M8ven Verified](https://m8ven.ai/badge/mcp/rps321321/obsidian-mcp-pro?variant=verified)](https://m8ven.ai/mcp/rps321321/obsidian-mcp-pro)
Shows verification status without the grade. Want the grade badge instead? Remove ?variant=verified from the URL.
commit: cc1eef18d6f4059b59478e982cc1ee39ca99dd0d
code hash: 966de90cfc30b66feb19e05049cd4b941a7a82a2805305f480711c7b8894940b
view raw JSON →
Check MCPs from inside your assistant
Tool Check · MCP

Vetting this one by hand? Tool Check is an MCP that scores other MCPs. Add it once and ask Claude, ChatGPT, or any MCP client to grade a server, surface CVEs, check the publisher, and suggest safer alternatives — before you install.

https://m8ven.ai/api/mcp/tool-check
check_toolsearch_toolscompare_toolsrecommend_alternativescheck_publisherreport_concern
How to add it →Free · no account needed · works in any MCP client