MCP server for managing a knowledge base of markdown notes with full-text search, tagging, and multi-vault support
Strong foundation with 10 well-named tools following verb_noun convention (get_, list_, create_, update_, search_, append_, edit_). All tools have detailed descriptions (100-300 chars, well above 20-char minimum). Input schemas are comprehensive with type definitions and parameter descriptions. However, output schemas are not explicitly documented in the visible code, responses are inferred from implementation. Error handling is present but recovery guidance is minimal. No tool annotations (readOnlyHint/destructiveHint) despite clear risk stratification (5 READ_ONLY, 5 WRITE). Missing pagination documentation for list_notes and list_todos despite accepting optional limit params.
Append text to a note's body, optionally within a named section (heading). If section is omitted, appends to the end of the body. If section is passed, appends after the section's heading (before any subsections). Returns the full written note (raw markdown).
Create a new note. Slug is auto-generated from the title (slugified) unless you pass an explicit slug. Frontmatter fields (title, tags, related, and custom extras) can be passed as separate params or embedded in the content as YAML frontmatter — explicit params take precedence. The note is written to the default vault unless you pass vault. Returns the full written note (raw markdown).
Surgically edit a note's frontmatter (tags, related, and custom fields). Supports set (overlay scalar fields), addTags, removeTags, addRelated, removeRelated. List operations are idempotent (re-adding an existing tag is a no-op; removing an absent one is a no-op). Returns the full written note (raw markdown) on success, or an error if the operation is incoherent (e.g. adding and removing the same tag).
Surgically edit a note's body by finding and replacing text. Supports regex patterns (pass regex: true). Returns the full written note (raw markdown) on success, or an error if the pattern is not found or matches multiple times.
Fetch a single note by slug. Returns the full raw markdown (frontmatter + body). Slug is a relative path without the .md extension (e.g. "projects/my-project" for notes/projects/my-project.md). By default searches all vaults; pass vault to scope to a specific one. If the slug exists in multiple vaults, an error lists all matches — you must disambiguate by passing vault.
Output schemas not documented. Tool descriptions state what is returned (e.g., 'Returns the full written note (raw markdown)') but formal output schema definitions are absent from visible code. LLMs cannot plan downstream tool chains without knowing response field names and types.
No tool annotations despite clear risk stratification. 5 tools are READ_ONLY (get_vault_context, list_notes, get_note, search_notes, list_todos); 5 are WRITE (create_note, update_note, append_to_section, edit_note, edit_frontmatter). Annotations (readOnlyHint, destructiveHint, idempotentHint) enable agents to reason about safety and retry semantics.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 64 | 2026-07-28+ | v2 |
Fetch the vault bootstrap document (profile.md) from the vault root. Read this first to orient yourself to the vault — its structure, contents, and how to navigate it effectively. Load this silently for context; do not summarize or recite its contents unless the user explicitly asks.
List notes in the knowledge base, sorted by date (newest first). Optionally filter by slug prefix to scope results to a folder. By default spans all configured vaults; each result carries a `vault` field naming its source vault. Notes tagged with the vault's default-excluded tags (e.g. archived, historical) are omitted by default; pass exclude_tags: [] to include them, or a custom list to override the default. If you haven't already, call get_vault_context first to orient yourself to this vault.
Extract and list all todos (lines starting with `- [ ]`) from notes in the knowledge base, sorted by date (newest first). Optionally filter by slug prefix to scope results to a folder. By default spans all configured vaults; each result carries a `vault` field naming its source vault. Notes tagged with the vault's default-excluded tags are omitted by default; pass exclude_tags: [] to include them, or a custom list to override the default.
Full-text search across the knowledge base using BM25 ranking. Returns results sorted by relevance, with excerpts highlighting the matched terms. By default spans all vaults; pass vault to scope to a specific one. Notes tagged with the vault's default-excluded tags are omitted by default; pass exclude_tags: [] to include them, or a custom list to override the default.
Update an existing note's content and/or frontmatter. Slug must exist. Frontmatter fields (title, tags, related, and custom extras) can be passed as separate params or embedded in the content as YAML frontmatter — explicit params take precedence. Omitted fields are preserved (tags/related default to empty if the note has none). The note is updated in the vault where it was found (or the specified vault if passed). Returns the full written note (raw markdown).
Pagination not documented for list_notes and list_todos. Both accept optional 'limit' parameter but no mention of total count, next_cursor, or offset. Large vaults could return unbounded results, exhausting context windows.
Error recovery guidance is minimal. Error responses (e.g., 'Unknown vault', 'Invalid slug') state the problem but rarely suggest next steps. Pattern: 'User not found. Try search_users() with a partial name.' is absent.
Frontmatter parameter handling is complex. create_note and update_note accept 'frontmatter' as an object plus separate 'tags', 'related', 'title' params, with a note that 'explicit params override embedded values'. This dual-input pattern is error-prone; simplify to a single frontmatter object or separate params, not both.