MCP server that exposes Obsidian Sync vaults as tools over bearer-token-protected HTTP, with support for OIDC delegation
Strong foundation with 12 well-named tools following verb_noun convention (list_, read_, create_, delete_, etc.). All tools have descriptions (avg ~150 chars, within 10-1024 baseline). Input schemas are present and typed for all tools. However, parameter descriptions are sparse or missing entirely for many inputs, e.g., list_notes has 'vault' and 'dir' but no type info visible in schema; read_note offset lacks range constraints. Output schemas are undocumented, LLMs cannot predict response structure. Error handling is implicit (no recovery guidance in descriptions). Security model (bearer token auth) is sound but not reflected in tool annotations. Composition is excellent: tools chain naturally (list_vaults → list_notes → read_note), and destructive operations (delete_note, restore_note) are properly separated.
Append content to a note, creating it if it does not exist.
Create a new note. Parent directories are created automatically; fails if the note already exists.
Delete a note. By default it is moved to the vault's .trash folder (recoverable with restore_note); set permanent to remove it outright.
Edit a note by replacing an exact text snippet. The snippet must occur exactly once unless replace_all is set; include surrounding lines to make it unique.
Read a Markdown heading section's body, including nested subsections but excluding its heading. heading_path is an exact case-sensitive suffix of the heading hierarchy (Markdown title text without heading markers); ambiguous matches fail. Only document-level headings count, not headings in code, quotes, lists, or YAML frontmatter. Returns at most 10240 characters; continue with next_offset.
Output schemas are completely undocumented. LLMs cannot predict response structure (fields, types, pagination). Descriptions mention 'Returns at most X characters' but do not specify response object shape, next_offset field presence, or error format.
Parameter descriptions lack type and constraint details. 'offset' appears in read_note and get_section but no description states it must be non-negative or what happens if it exceeds content length. 'recursive' in list_notes has no description at all.
No error recovery guidance. Descriptions do not explain what to do if a vault is not found, a note does not exist, or a heading_path is ambiguous. LLMs receive raw errors with no actionable next steps.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 65 | 2026-07-28+ | v2 |
List notes and directories in a vault. Hidden folders such as .obsidian and .trash are excluded, but passing dir ".trash" lists deleted notes explicitly.
List the Obsidian vaults available on this server.
Move or rename a note within a vault. Fails if the destination already exists.
Read a note from a vault. Returns at most 65536 characters per call; when the response is truncated, call again with offset set to next_offset to continue reading.
Replace a Markdown heading section's entire body, including nested subsections, while preserving its heading. content excludes the selected heading. heading_path is an exact case-sensitive suffix of the heading hierarchy; missing or ambiguous matches fail. The section ends at the next heading of equal or higher rank. Adds newline separation when needed before a following heading.
Restore (undelete) a note from the vault's .trash folder. Restores to the note's path inside .trash unless to is set; use list_notes with dir ".trash" to see what can be restored.
Full-text regex search across a vault (ripgrep syntax). Returns matching lines grouped by file, optionally with surrounding context lines. Case-insensitive unless case_sensitive is set.
Destructive operations (delete_note, replace_section, edit_note) lack confirmation or dry-run support. No tool annotation (destructiveHint) visible in code. Agents can permanently delete or overwrite content without safeguards.
Result limits are mentioned in descriptions (65536 chars for read_note, 10240 for get_section) but no pagination guidance for list_notes or search_notes. No total_count or next_cursor fields documented.