Conceptual search via on-device embeddings (Apple's NLContextualEmbedding). Use when the user's question doesn't share keywords with the relevant notes — e.g. asking about “productivity” when the note actually says “flow state”.
Input
{ query: string, limit?: integer (default 10, max 50), vault?: string }
Output
{ query, total_count, returned_count,
results: [{ vault, vault_path, relative_path, filename, score, snippet }] }
score is cosine similarity (-1 to 1, higher is closer).
“More like this.” Reuses on-device embeddings to score every other note's chunks against the source's mean vector. Use when you have one note and want to surface adjacent thinking, related projects, or earlier passes at the same idea.
Input
{ relative_path: string, limit?: integer (default 10, max 50), vault?: string }
Output
{ vault, source, total_count, returned_count,
results: [{ vault, vault_path, relative_path, filename, score }] }
Full-text search with BM25 ranking and stemming. Supports quoted phrases for exact match. Use this for keyword targets and proper nouns; use semantic_search when the question is conceptual.
Operators inside the query string narrow without a schema change:
tag:foo — file must carry tag foo (case-insensitive). Repeat for AND.
path:notes/sub — file's vault-relative path must start with this prefix.
Input
{ query: string, limit?: integer (default 20, max 100) }
Output
{ query, total_count, returned_count, results: [...] }
Notes that link to a target via [[wiki-links]], plus “unlinked mentions” — places the target's filename appears as plain text without being wrapped.
Input
{ relative_path: string, vault?: string }
Output
{ vault, relative_path,
linked: [{ vault, relative_path, line_number, display_text, context }],
unlinked: [{ vault, relative_path, line_number, context_line }] }
Without tag: list every tag with file count (mode all). With tag: list every note carrying it (mode by_tag). Tags come from inline #hashtags and YAML frontmatter tags:.
Input
{ tag?: string }
Full content of a note plus metadata: content hash, byte size, modified timestamp, parsed frontmatter, headings, and tags. Optional 1-based line range.
Input
{ relative_path: string, start_line?: integer, end_line?: integer, vault?: string }
Walks the filesystem fresh every call — results always reflect current on-disk state. Optional subpath prefix.
Input
{ under?: string, vault?: string }
Heading outline (H1–H6) with level, text, and 1-based line number.
Parsed YAML frontmatter as a flat key-value map, plus a has_frontmatter boolean.
Create a new note. Parent folders are created automatically. Returns a note_exists error if the path is already taken.
Input
{ relative_path: string, content: string, vault?: string }
Rename or move a note within a vault, rewriting every inbound [[wiki-link]] to point at the new path. Preserves heading anchors and aliases. Index id is preserved across the move — existing backlink relationships survive without re-resolution.
Input
{ from_path: string, to_path: string, vault?: string }
Output
{ vault, from, to,
links_rewritten: [{ relative_path, count }] }
Update an existing note. replace overwrites the whole file. append adds to the end. prepend inserts after the YAML frontmatter block (or at the top if there is none).
Pass expected_content_hash (the value read_note returned) to opt into optimistic concurrency — the call is rejected with stale_content if the file changed since you last read it. The editor's save path goes through the same coordinated I/O, so a user typing in the editor and an MCP write to the same note can no longer drop each other's edits.
Input
{ relative_path: string, content: string, mode: "replace"|"append"|"prepend",
vault?: string, expected_content_hash?: string }