Reader¶
search¶
Search Vault. Read-only. Idempotent.
Search notes by keyword and meaning; returns notes ranked by score, each with its best-matching sections as snippets.
Use list_documents for a complete listing and read for a path you already know.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
query |
string |
required | Words to match or a natural-language question. |
limit |
integer |
10 |
Maximum notes to return (default 10). |
mode |
keyword \| semantic \| hybrid \| null |
null |
Omit for the best mode this vault serves. "keyword" suits exact terms, operators and filenames; "semantic" matches meaning only; "hybrid" combines both. "semantic" and "hybrid" need semantic_search_available from stats. |
folder |
string \| null |
null |
Only notes under this folder, a value from list_folders; "" for top-level notes only. |
filters |
object \| null |
null |
Frontmatter values to match, all of them, such as {"tags": "pacing"}; keys come from indexed_frontmatter_fields in stats, and a list field matches when it holds the value. On an OKF bundle, status (draft, stable or deprecated; stable includes notes with none), stale ("true" or "false") and trust_tier (unverified, machine-confirmed or human-reviewed) filter too. |
chunks_per_file |
integer \| null |
null |
Maximum sections per note, at least 1; omit for the server default. |
snippet_words |
integer \| null |
null |
Snippet width in words; omit for the server default, 0 for whole sections. read with section set to a result's heading returns that whole section. |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
List of result dicts ranked by file relevance. Each contains:
- path (str): Relative path of the document.
- title (str): Document title.
- folder (str): Parent folder path.
- score (float): File-level score = max(section.score). Higher is a better match. BM25 (keyword) or cosine (semantic/ hybrid); not comparable across modes.
search_type(str):"keyword","semantic", or"hybrid".- frontmatter (dict): Parsed YAML frontmatter of the document.
- okf (dict, optional): OKF read annotation: present only when
the vault is an active OKF bundle. Carries
type(when declared),status(defaults to"stable"),stale(bool,stale_afterreached),trust_tier("unverified"/"machine-confirmed"/"human-reviewed"), andsources_count(when the note cites sources). -
sections (list[dict]): Up to
chunks_per_filebest-matching sections, each with: -
heading (str | None): Section heading or null for intro.
- content (str): Matched snippet (or full chunk if
snippet_words=0). Call read(path, section=heading) for the full section text. - score (float): Chunk-level score for this section.
On an active OKF bundle, ranking demotes deprecated notes, stale notes less, and the reserved index.md and log.md below real notes.
An empty query returns an empty list in semantic and hybrid mode.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
Outcomes and errors
- EmbeddingsNotConfiguredError: If mode is
"semantic"or"hybrid"and no embedding provider is configured (aValueErrorsubclass). - InvalidRequestError: If
chunks_per_fileis below 1.
Find craft notes on a topic, two sections per note:
{"query": "character development techniques", "limit": 5, "filters": {"tags": "craft"}}
To read a hit in full, pass its path and a section heading to read: read(path=hit["path"], section=hit["sections"][0]["heading"]).
read¶
Read Note. Read-only. Idempotent.
Return a note's text, frontmatter and etag, or an attachment's bytes as base64.
Look paths up with search or list_documents first rather than guessing them.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
string |
required | Path in the vault, such as "Journal/note.md" or "assets/diagram.pdf"; case-sensitive. |
section |
string \| null |
null |
A heading, such as the heading field of a search result; returns that section and its sub-sections instead of the whole note. Notes only. |
revision |
string \| null |
null |
A commit SHA from get_history or from a write result's previous_revision; returns the note as it stood then, without an etag. Pass path as the note is named today. To restore that text, write it with the etag of a read without revision. |
Returns
For .md: dict with path, title, folder, content (the full raw
file including frontmatter, or the section text when section= is
given), frontmatter (dict:
empty {} when section= is provided; call read(path) without
section= to get the full document's frontmatter),
modified_at (Unix timestamp), etag (SHA-256 hex str or null).
On an active OKF bundle, whole-document reads also carry
an 'okf' dict (type, status, stale, trust_tier, and the note's
'sources' list when present); section reads omit it because they
carry no frontmatter to derive it from.
For attachments: dict with path, mime_type (str or null),
size_bytes (int), content_base64 (str), modified_at (Unix timestamp),
etag (SHA-256 hex str or null).
The 'etag' value can be passed as 'if_match' to write, edit,
delete, or rename to guard against concurrent modifications.
With revision=: dict with path, historical_path (the name the note
carried at that revision), revision, and content: the whole raw
file, or just one section's body when section= is also given. No
etag and no modified_at (both describe the note as it is now), and
no 'okf' block for the same reason.
Outcomes and errors
- ValueError: If no file exists at the given path, the extension is not in the attachment allowlist, the file exceeds
MARKDOWN_VAULT_MCP_MAX_ATTACHMENT_SIZE_MB, or the requested section heading is not found. A whole note over the size limit this server returns in one read (MARKDOWN_VAULT_MCP_MAX_NOTE_READ_BYTES) is refused; read it bysection. Withrevision: if the vault is not git-backed, the revision is unusable, the path is an attachment, or git's records do not show the note existing at that revision (a name later reused by a different note is refused rather than answered with the other note's content). - DocumentUnreadableError: If the file cannot be read or decoded, its frontmatter does not parse, or git stores it in LFS at that revision.
Read a note:
{"path": "Journal/note.md"}
returns
{
"path": "Journal/note.md",
"title": "My Note",
"folder": "Journal",
"content": "---\ntitle: My Note\ntags: [journal]\n---\n\nThe note body.\n",
"frontmatter": {"title": "My Note", "tags": ["journal"]},
"modified_at": 1791052994.65,
"etag": "1f196a744076635e77bc55e674dcdd69a29d9d32614c516a51ced986a51aaebe"
}
content is the raw file, frontmatter included. Pass etag as if_match to write, edit, delete or rename to change the note you read.
list_documents¶
List Documents. Read-only. Idempotent.
List notes, and optionally attachments, with path, title and frontmatter but no body text.
Use search to find notes by what they say.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
folder |
string \| null |
null |
Only notes in this folder and its sub-folders, such as "Journal"; "" for top-level notes only; omit for the whole vault. |
pattern |
string \| null |
null |
Glob matched against paths, such as "Journal/*.md" or "**/*meeting*.md". |
include_attachments |
boolean |
false |
Also list non-note files, marked kind="attachment" with their mime_type. Default false. |
filters |
object \| null |
null |
Frontmatter values to match, all of them, such as {"tags": "craft"}; any key works, a list field matches when it holds the value, and attachments never match. On an OKF bundle, status (draft, stable or deprecated; stable includes notes with none), stale ("true" or "false") and trust_tier (unverified, machine-confirmed or human-reviewed) filter too. |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
List of info dicts. Every entry has a 'kind' field.
Notes: path, title, folder, frontmatter, modified_at, kind="note",
and content_chars (int): body length in characters, frontmatter
excluded; 0 for a note indexed before the field existed.
Attachments (when include_attachments=True): path, folder,
mime_type, size_bytes, modified_at, kind="attachment".
Body content is not included in either case.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
Stale notes on an OKF bundle, for a triage pass:
{"folder": "Playbooks", "filters": {"stale": "true"}}
list_folders¶
List Folders. Read-only. Idempotent.
List every folder that holds notes; "" stands for the top level.
Pass one as the folder argument of search, list_documents and the other
folder-scoped tools.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
Sorted list of folder paths, such as ["", "Journal", "Projects"].
Pass any of these as the 'folder' argument to 'search' or
'list_documents'.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
list_tags¶
List Tags. Read-only. Idempotent.
List the distinct values one indexed frontmatter field takes across the vault.
Use the values in the filters argument of search.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
field |
string |
"tags" |
A field from indexed_frontmatter_fields in stats (default "tags"). |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
Sorted list of distinct string values, such as
["craft", "pacing", "worldbuilding"]. Use these as values in the
'filters' dict when calling 'search'.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
Outcomes and errors
- InvalidRequestError: If field is not an indexed frontmatter field; the message names the fields that are indexed.
stats¶
Vault Stats. Read-only. Idempotent.
Report the vault's size, link health and capabilities: the search modes it serves and the frontmatter fields search can filter on.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
Dict with the following fields:
document_count(int): Total number of indexed documents.chunk_count(int): Total number of indexed text chunks.folder_count(int): Total number of folders containing documents.semantic_search_available(bool): True if mode="semantic"or mode="hybrid"can be used in 'search'.indexed_frontmatter_fields(list[str]): Field names usable as 'filters' in 'search' and as 'field' in 'list_tags'.attachment_extensions(list[str]): Allowed non-.md extensions, or["*"]when any extension is allowed.link_count(int): Total number of indexed links. 0 may mean no links exist or link tracking not yet built (call 'reindex').broken_link_count(int): Links pointing to missing documents. Call 'get_broken_links' if non-zero.orphan_count(int): Notes with no inbound or outbound links. Call 'get_orphan_notes' if non-zero.- okf (dict, optional): Present only when the vault is an active
OKF (Open Knowledge Format) bundle. Carries mode,
declared_version, a per-typehistogram plusuntyped_count, status and trust-tier breakdowns, andstale_count. Those cover the note population 'okf_validate' audits; the reservedindex.md/log.mdfiles are counted apart asreserved_count.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
{"document_count": 42, "chunk_count": 156, "folder_count": 5, "semantic_search_available": true,
"indexed_frontmatter_fields": ["tags", "cluster"], "attachment_extensions": ["pdf", "png", "jpg"],
"link_count": 310, "broken_link_count": 3, "orphan_count": 7}
get_similar¶
Similar Notes. Read-only. Idempotent.
Find the notes closest in meaning to a given note; returns them ranked by similarity with their closest sections, the note itself excluded.
Needs semantic_search_available from stats. A note whose embeddings are not
built yet has no similar notes.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
string |
required | Path of the note to compare against, such as "notes/topic.md"; case-sensitive. |
limit |
integer |
10 |
Maximum notes to return (default 10). |
chunks_per_file |
integer \| null |
null |
Maximum sections per note, at least 1; omit for the server default. |
folder |
string \| null |
null |
Only notes in this folder or below, such as "3-Resources"; "" for top-level notes only. |
filters |
object \| null |
null |
Frontmatter values to match, all of them, such as {"type": "resource"}; any key works and a list field matches when it holds the value. On an OKF bundle, status (stable includes notes with none), stale ("true" or "false") and trust_tier filter too. |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
List of result dicts ranked by file similarity. Each contains:
- path (str): Relative path of the similar document.
- title (str): Document title.
- folder (str): Parent folder path.
- score (float): File-level cosine similarity (max of section scores), 0.0-1.0; higher = more similar.
search_type(str): Always"semantic".- frontmatter (dict): Parsed YAML frontmatter.
-
sections (list[dict]): Up to
chunks_per_filebest-matching sections, each with: -
heading (str | None): Section heading or null for intro.
- content (str): Matched chunk text.
- score (float): Chunk-level score for this section.
Index freshness is reported out-of-band in the response's
_meta.index_stale field: True when the IndexWriter had
pending or in-flight work at any of three observation points
(wait_for_pending_writes timing out, a write completing inside the
read window, or non-idle at response time), False otherwise.
Outcomes and errors
- DocumentNotFoundError: If no document exists at the given path.
- EmbeddingsNotConfiguredError: If the vault has no embeddings.
- InvalidRequestError: If
chunks_per_fileis below 1. - ToolError: If the index is busy or still building; retry shortly.
- IndexUnavailableError: If the index build failed or the index is broken;
get_index_statusreports the error.
{"path": "3-Resources/okf.md", "folder": "3-Resources", "filters": {"type": "resource"}, "chunks_per_file": 1}
get_toc¶
Table of Contents. Read-only. Idempotent.
Return the heading outline of a note, or of every note under a folder.
For a note: a list of {heading, level}, the title first as level 1. For a folder: {path, notes, truncated}, each note with its path, title and headings.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
string |
required | A note path ending in .md, such as "a/b.md", or a folder, such as "a/b". |
max_level |
integer \| null |
null |
Deepest heading level to keep, such as 2 for H1 and H2; omit for all. The title always stays. |
max_notes |
integer |
200 |
Folders only: notes to include, first by path (default 200); truncated is true when more exist. |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
Note mode: list of {heading (str), level (int)}.
Folder mode: {path (str), notes (list[{path, title, headings,
content_chars}]), truncated (bool)}. Empty/nonexistent folder → empty
'notes'. Each note's content_chars (int) is its body length in
characters, frontmatter excluded; 0 for a note indexed before the
field existed.
Index freshness is reported out-of-band in '_meta.index_stale'.
Outcomes and errors
- ValueError: Note path with no document; invalid folder path.
- ToolError: If the index is busy or still building; retry shortly.
- IndexUnavailableError: If the index build failed or the index is broken;
get_index_statusreports the error.
{"path": "1-Projects/export", "max_level": 2, "max_notes": 50}
returns
{"path": "1-Projects/export", "notes": [{"path": "1-Projects/export/plan.md", "title": "Plan", "headings": [{"heading": "Plan", "level": 1}, {"heading": "Scope", "level": 2}], "content_chars": 4120}], "truncated": false}
get_recent¶
Recent Notes. Read-only. Idempotent.
List the most recently modified notes, newest first.
Use it to pick up recent activity without a search query.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
limit |
integer |
20 |
Maximum notes to return (default 20). |
folder |
string \| null |
null |
Only notes in this folder and its sub-folders, such as "Journal"; "" for top-level notes only; omit for the whole vault. |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
One dict per note, each with: path, title, folder,
frontmatter, modified_at (Unix timestamp), kind ("note"), and
content_chars (int): body length in characters, frontmatter excluded;
0 for a note indexed before the field existed.
Index freshness rides in the response's _meta.index_stale
field: True when the IndexWriter was non-idle, a write completed
inside the read window, or wait_for_pending_writes timed out; False
otherwise.
get_context¶
Note Context. Read-only. Idempotent.
Return a note's metadata, backlinks, outlinks, similar notes, folder neighbours, indexed tags and applicable conventions in one call.
Use it instead of get_backlinks, get_outlinks and get_similar when you need more
than one of them.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
string |
required | Path of the note, such as "notes/topic.md"; case-sensitive. |
similar_limit |
integer |
5 |
Maximum similar notes (default 5); 0 skips them, which suits a vault where stats shows semantic_search_available false. |
link_limit |
integer |
10 |
Maximum backlinks, and separately outlinks (default 10). |
wait_for_pending_writes |
boolean |
false |
Wait for recent index writes. On timeout, answer from the current index with _meta.index_stale=true. Default false. |
Returns
Dict with the note context. Fields:
- path (str): Relative path of the document.
- title (str): Document title.
- folder (str): Parent folder path.
- frontmatter (dict): Parsed YAML frontmatter.
modified_at(float): Unix timestamp of last modification.-
backlinks (list): Documents linking to this note. List of dicts, each with:
-
source_path(str): Path of the document containing the link. source_title(str): Title of the source document.link_text(str): The clickable text of the link.link_type(str): One of"markdown","wikilink", or"reference".- fragment (str | None): Heading anchor (such as
"#section"), or null. -
raw_target(str): Literal link target as written in the source. -
outlinks (list): Links from this note. List of dicts, each with:
-
target_path(str): Path of the linked document. link_text(str): The clickable text of the link.link_type(str): One of"markdown","wikilink", or"reference".- fragment (str | None): Heading anchor (such as
"#section"), or null. raw_target(str): Literal link target as written in the source.-
exists (bool): True if the target document is indexed.
-
similar (list): Semantically similar notes, field-collapsed by file (
chunks_per_file=1 for compact dossiers). List of dicts, each with: -
path (str): Relative path of the similar document.
- title (str): Document title.
- folder (str): Parent folder path.
- score (float): File-level cosine similarity 0.0-1.0 = score of the best matching section.
search_type(str): Always"semantic".- frontmatter (dict): Parsed YAML frontmatter.
-
sections (list): Single best-matching section, each with heading (str|null), content (str), score (float). Call
get_similar(path,chunks_per_file=N) for more sections. -
folder_notes(list[str]): Paths of other notes in the same folder (up to 20). Plain strings, not dicts. - tags (dict[str, list[str]]): Indexed frontmatter field → distinct values for this note.
- conventions (list, optional): the user's authoring conventions for the note's folder (root-first list of {folder, path, content}). Present only when convention files apply. Honor them when writing to or proposing links involving this note; some folders are self-contained by design.
- okf (dict, optional): OKF read annotation for this note
(type, status, stale,
trust_tier,sources_count). Present only when the vault is an active OKF bundle.
Index freshness is reported out-of-band in the response's
_meta.index_stale field: True when the IndexWriter had
pending or in-flight work at any of three observation points
(wait_for_pending_writes timing out, a write completing inside the
read window, or non-idle at response time), False otherwise.
Outcomes and errors
- ValueError: If no document exists at the given path.
- ToolError: If the index is busy or still building; retry shortly.
- IndexUnavailableError: If the index build failed or the index is broken;
get_index_statusreports the error.
{"path": "3-Resources/okf.md", "similar_limit": 0, "link_limit": 5}
With similar_limit at 0 the similarity lookup is skipped, as for a vault without embeddings.
get_conventions¶
Folder Conventions. Read-only. Idempotent.
Return the vault owner's authoring conventions for a note or folder, vault root first and the most specific last.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
string |
"" |
A note or folder path, such as "3-Resources/topic.md" or "3-Resources"; a note takes its folder's conventions. "" (the default) returns the root conventions and lists every folder that has its own. |
Returns
Dict with:
- path (str): The path that was queried.
- conventions (list): Applicable convention entries, root-first.
Each has folder (str,
""for vault root), path (str, the convention file's own path), and content (str, its markdown body). convention_folders(list[str], discovery mode only): all folders carrying a convention file (""= vault root), included only when path is""; it requires a vault-wide folder walk, so a call with a path skips it.
Convention files are left out of search and listings but can be read and edited like any note. This tool reads them from disk, so it answers while the index is still building.
Outcomes and errors
- ValueError: If the path escapes the vault root.
{"path": "3-Resources/topic.md"}
returns the conventions that apply, root first:
{"path": "3-Resources/topic.md", "conventions": [{"folder": "", "path": "_conventions.md", "content": "…"}, {"folder": "3-Resources", "path": "3-Resources/_conventions.md", "content": "Keep notes self-contained; do not link out to project notes."}]}
okf_validate¶
Validate OKF Bundle. Read-only. Idempotent. Tags: okf.
Audit how far the vault conforms to the Open Knowledge Format, with example paths per rule; works on a vault not yet declared as a bundle.
Parameters
None.
Returns
Report dict. The audit reads the vault from disk, so it works before
the index is built, and it skips the vault's excluded paths. Every
rule except root_index_missing is a finding with count (int) and
up to 20 examples (list[str] of paths).
- mode (str),
declared_version(str | None), active (bool): the detection state. total_notes(int),conformant_notes(int): the progress ratio; the reserved index.md and log.md are not counted as notes.
Conformance rules, which the format requires:
missing_type: notes without a non-emptytype; the reserved index.md and log.md are exempt.unparseable_frontmatter: notes whose frontmatter does not parse.misplaced_okf_version:okf_versiondeclared anywhere but the root index.md.index_frontmatter: index.md files carrying frontmatter, any on a folder index and anything butokf_versionon the root, server-generated indexes included.
Advisory rules, tolerated but worth fixing:
unknown_status: astatusoutside draft, stable and deprecated.log_heading_shape: log.md files whose##headings are not YYYY-MM-DD dates.root_index_missing(bool): true when the root index.md is absent.
Informational rules, not deviations:
wikilink_files: notes containing wikilinks, which matter only when exporting.missing_recommended: notes without the recommendedtitleordescription.