MCP server that exposes Obsidian vault operations (list, read, search, write, edit, delete, move, copy files) with full-text search powered by ripgrep and atomic file writes
vault-sync demonstrates solid definition quality with consistent naming patterns, comprehensive descriptions, and explicit JSON Schema support. All 8 tools follow verb_noun conventions (vault_list, vault_read, vault_write, etc.). Descriptions are detailed and contextual (avg ~180 chars), exceeding the 10-1024 char baseline and well within the 194-char production average. All parameters are typed and described. However, output schemas are not explicitly documented in the source, the tool handlers return results but response structures are inferred from struct definitions rather than formally declared. Error handling is present but could be more granular. Security practices are strong (path restrictions on .obsidian/, atomic writes, permission logging), but some parameter constraints (e.g., line limit ranges for vault_read) could be formalized in schema enums.
Copy a file within the vault. Creates destination parent directories automatically. Refuses to overwrite existing files. Uses atomic write. Cannot copy directories or .obsidian/ paths.
Delete one or more files from the vault. Accepts an array of paths. Best-effort: each file is attempted independently, failures are reported per-item. Cannot delete directories or .obsidian/ paths.
Find-and-replace edit on an existing file. The old_text must appear exactly once. Uses atomic write. Same semantics as str_replace.
List vault contents. Without a path: returns every file with metadata (path, size, modified, tags). With a path: lists one folder level deep, showing files with size/modified and folders with child counts.
Move or rename a file within the vault. Creates destination parent directories automatically. Refuses to overwrite existing files. Cannot move directories or .obsidian/ paths.
Output schemas not formally documented. Tool handlers return structured results (listResult, searchResult, etc.) inferred from Go struct definitions, but no explicit response schema documentation visible in tool registration. LLMs cannot verify expected output fields without reading implementation code.
Parameter constraints not formalized as enums or min/max bounds. vault_read accepts 'offset' and 'limit' integers but does not declare min=1 or max bounds; vault_search max_results lacks explicit bounds (defaults to 20 but no stated max). LLMs may pass absurd values (negative offsets, 10000-line limits) without validation feedback.
Error guidance is minimal. Tools guard against .obsidian/ and non-file targets, but error messages are not shown in source. Handlers should return structured errors like 'Invalid path: xyz is a directory. Use vault_list to browse directories.' instead of generic failures.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 69 | <=2025-11-25 | v2 |
| 2026-03-09 | D | 57 | - | v1 |
Read file content with optional line-range pagination. Lines are 1-indexed. Large files are auto-truncated at 200 lines unless a limit is specified.
Full-text search across file names, frontmatter tags, and file content. Case-insensitive. Returns matching files with context snippets and line numbers. Content search powered by ripgrep (fast literal pattern matching) or built-in Go implementation (literal pattern matching).
Create a new file or fully replace an existing file. Uses atomic write. Cannot write to .obsidian/ directory.
No idempotency guarantees declared. vault_write and vault_edit claim 'atomic write' but do not state whether they are idempotent (safe to retry) or what happens if called twice with same input. Agents need to know whether repeating a call produces duplicates or overwrites.