Obsidian Server MCP
Obsidian Server MCP provides 13 MCP stdio tools for filesystem and semantic access to an Obsidian Vault without Obsidian Desktop.
Discover/read:
vault_list,vault_read,vault_get_document_map,obsidian_help.Search/analyze:
search_query(JsonLogic over path/content/tags/frontmatter/stat),reference_query(file/heading/block references),tag_list(tags + parent counts).Mutate text:
vault_write,vault_append,vault_patch(heading/block/frontmatter; existing files requireifMatch).Manage files:
vault_move(optional overwrite),vault_delete(recoverable.trashby default or permanent).Read attachments:
vault_read_binaryfor images/non-PDF files: preview, link (requires deployment provider), or explicit bytes up to 4 MiB; PDFs unsupported.Constraints: Linux headless target; no auth/sync/remote transport, no Desktop link graph, no PDF reading; deployment filesystem permissions are authoritative; no automatic retries.
Provides filesystem-based access to an Obsidian vault, enabling listing, reading, searching, tagging, writing, appending, patching, moving, and deleting notes and attachments, with document maps, frontmatter/property edits, exact-byte version checks, and reference queries.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Obsidian Server MCPsearch my vault for meeting notes and show their headings"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Obsidian Server MCP
A lightweight, general Obsidian Server MCP for filesystem and semantic access to a Vault without a running Obsidian Desktop application. Common tools follow the pinned Local REST 5.3.1 contract as closely as the filesystem backend permits.
The current entry is stdio. Synchronization, remote transport/authentication and deployment configuration are external to this implementation. Vault files are the source of truth; the server sees changes once they reach its filesystem.
The supported deployment target is a Linux headless server/VPS. Windows can be used for local development, but is not a supported deployment platform.
Deployment filesystem permissions are authoritative for what the MCP process may read, write or delete. Configure access through the environment's user, group, ACL, mount or container settings. MCP contains no deployment authorization policy. Local tests use disposable fixtures; Linux filesystem and permissions validation remains a separate platform qualification.
Quick start
Install Node.js 22 or newer with npm on Linux. CI checks Node 22 and 24. Download and extract this repository's source archive, or clone its URL from the repository's Code menu. Open a terminal in the project folder:
npm ci
npm run buildKeep development dependencies installed while building; the TypeScript compiler
is a development dependency. sharp installs its native image library for the
current platform, so install dependencies on each host instead of copying
node_modules between Windows and Linux.
Start with an empty example Vault. In Linux bash or sh:
mkdir -p ./example-vault
printf '# Hello\n' > ./example-vault/Hello.md
OBSIDIAN_VAULT_ROOT="$PWD/example-vault" node ./dist/stdio-main.jsFor optional local development in Windows PowerShell:
New-Item -ItemType Directory -Force ./example-vault | Out-Null
Set-Content -LiteralPath ./example-vault/Hello.md -Value '# Hello' -Encoding utf8
$env:OBSIDIAN_VAULT_ROOT = (Resolve-Path ./example-vault).Path
node ./dist/stdio-main.jsA running stdio server waits for MCP messages on standard input; it does not open a web page or print a ready banner. Stop this manual check with Ctrl+C, then let your MCP client launch the process itself.
Connect an MCP client
For clients accepting a mcpServers JSON configuration, add this entry and
replace the two absolute paths with your project and Vault paths:
{
"mcpServers": {
"obsidian-server": {
"command": "node",
"args": ["/absolute/path/obsidian-server-mcp/dist/stdio-main.js"],
"env": {
"OBSIDIAN_VAULT_ROOT": "/absolute/path/example-vault"
}
}
}
}For local Windows development, forward-slash paths such as C:/Projects/obsidian-server-mcp/dist/stdio-main.js
and C:/Vaults/example-vault work in JSON. If your client does not inherit the
terminal's PATH, use the absolute Node executable as command (find it with
(Get-Command node).Source in PowerShell or command -v node on Linux).
Clients with form-based settings use the same command, argument and environment
variable. Launch node directly so the MCP protocol has exclusive use of stdout.
Reconnect the client and discover 13 tools. First call
obsidian_help({"topic":"read"}), then vault_list({"path":""}) and
vault_read({"path":"Hello.md"}) against the example Vault. A write-capable
client can modify files with this server; choose its Vault and filesystem
permissions accordingly.
If startup fails, check that npm run build created dist/stdio-main.js, the
Vault directory exists, and the client process receives OBSIDIAN_VAULT_ROOT.
No API key or Obsidian Desktop plugin is required for this local stdio entry.
HTTPS hosting, authentication, synchronization and signed attachment downloads
are supplied by a separate deployment adapter. See
binary integration for attachment delivery.
Related MCP server: vault-mcp-server
Architecture and compatibility reference
src/coreowns filesystem, path, exact-byte version, parser, query and mutation semantics.src/transportowns MCP schemas and error/result mapping; it never accesses files directly.Tests use disposable fixtures. No build or check connects to a real Vault.
This project references and adapts contracts and implementation patterns from
Obsidian Local REST API
by Adam Coddington. The reference is Local REST 5.3.1, peeled commit
17a9cfd9ff5dd0156b694bf9b13ab36c786b29da, not moving main.
See the pinned parity tables for source links,
operation/scope tables, exact dependency rationale, limits and deliberate differences.
This project is distributed under the MIT License. The upstream
copyright and complete MIT notice are retained in
third-party notices.
Implemented MCP tools
All tools have strict input/output schemas. Text-tool success payloads appear
once in structuredContent, with empty content. Attachment payloads appear once
in native MCP content, with only metadata in structuredContent. Known failures return compact
structured errors and a short text equivalent; unexpected failures reveal no
absolute filesystem paths or stacks.
Tool | Behavior |
| Topic index when |
| Sorted |
| Whole file or selected heading/block/frontmatter value, with exact-byte version; discover targets with |
| Image preview, signed download link or explicit bytes for non-PDF attachments; PDF is unsupported; see |
| Nested heading addresses, block IDs and frontmatter keys, including duplicate disambiguators |
| JsonLogic over note text, paths and properties, retaining truthy values in |
| Read-only references to a file/heading/block within explicit source and resolution scopes; matches and uncertainties with source versions |
| Direct tags and nested parents with per-file counts |
| Atomic text create/replace; existing files require |
| Atomic append; existing files require |
| Generic heading/block/frontmatter instruction; always requires |
| Move a file; destination suffix and optional |
| Recoverable Vault-local trash by default; |
The stdio entry exposes twelve Vault tools plus the static obsidian_help manual.
An embedded read-only composition exposes five text/discovery tools plus help,
can add the binary reader and reference query, and can omit the mutation store. There are no mutation stubs. search_simple and
its unused implementation are removed.
Properties use generic patching. Binary upload, copy and Desktop UI tools remain outside this surface.
Properties are edited through vault_patch(targetType=frontmatter); edits
preserve unrelated property text/comments, body, BOM and line endings. YAML
aliases, anchors, duplicate/complex keys and non-JSON values are refused.
Obsidian's Desktop link graph is unavailable and never fabricated. The separate
reference query implements the bounded filesystem reference contract.
JsonLogic
supports coercion, arithmetic, collections, defaults, glob and bounded regexp;
it is no longer predicate-only. There is no search database or whole-Vault snapshot.
Operational note: under the current server parser semantics, malformed or
unsupported frontmatter in a single note can make whole-Vault search_query
and tag_list fail explicitly.
On-demand help
Call obsidian_help({}) for a compact topic index, then, for example,
obsidian_help({"topic":"patch"}) for that section alone. Unknown topics return
a short error with the same topic index. Help reads no Vault data, makes no
network calls and performs no mutations.
The marked sections below are the single source for the bundled help text.
Edit them here, run npm run generate:help, and commit the generated module.
npm run check:help detects drift; builds also regenerate the module. Runtime
help uses those bundled strings, so a deployed package needs no README file.
Finding and reading notes
List the Vault root with vault_list({"path":""}), or omit path. Paths are
Vault-relative; / and . are not root aliases.
Whole-file reads return path, content, tags, parsed frontmatter,
filesystem stat, and SHA-256 version. Targeted reads return
{path,version,result}. vault_get_document_map returns the same version plus
heading/block/property addresses, without returning the note body.
maxBytes applies to the entire source document, not the selected target.
Targeted reads still read and parse the full source and return its exact-byte
version.
To read one section, first call vault_get_document_map({"path":"note.md"}).
For ## Setup inside # Guide, pass the full ancestor path to vault_read:
{"path":"note.md","targetType":"heading","target":["Guide","Setup"]}Copy every heading key from the returned tree unchanged, including any marker
used to distinguish repeated headings. Block targets use a reference ID without
^; frontmatter targets use the property name. scope selects part of a target
and requires targetType and target; it is not a whole-file field selector.
Targeted heading reads express levels relative to their scope. Use the map or a whole-file read to verify actual nesting after a structural edit.
Reading attachments
vault_read_binary({path, as?: "auto" | "bytes" | "link"}) accepts the same
Vault-relative paths and filesystem permissions as text reads. It performs no
OCR, upload or Vault mutation. MIME type is inferred from
the filename, with application/octet-stream for unknown extensions.
PDF is intentionally unsupported for both reading and delivery. PDF paths
(.pdf, case-insensitive) return vault_read_binary.unsupported_pdf in every
mode, including bytes, and through MCP resource reads. Use the client's native
file upload / attachment feature for PDFs; changing as does not enable them.
auto(default): PNG/JPEG/GIF/WebP become a native MCP image preview. The first frame is auto-oriented and resized without enlargement to at most 1568 pixels on either edge. The WebP preview is at most 1 MiB, with a 40-million input-pixel guard, 64 MiB source-byte cap and five-second processing timeout. Metadata marks it as a preview and reports whether only the first frame was returned. The original file is unchanged; usebytesfor its exact bytes.autofor other non-PDF files returns a signed HTTPS download link, even for small or empty files. SVG and other image formats also use this path; they are not rasterized. The original bytes travel over HTTPS rather than being embedded in the tool result. The client must fetch the URL to read them.Oversized or unavailable image previews also select a link.
as: "link"requests a download link directly, including for raster images.as: "bytes"returns original bytes as a binary resource, with an inclusive 4 MiB hard cap. It never converts, truncates or silently falls back to a link. This is an explicit low-level option for supported non-PDF attachments.
Payload appears once in MCP content (image, embedded resource or resource link);
structuredContent contains only delivery metadata. Inline results carry an
exact-byte source version. The bytes result's obsidian-vault://attachment/… URI
can be re-read through MCP resources with the same 4 MiB cap and version check;
it is not a browser/download URL. Resource reads do not enumerate attachments.
Links require a deployment-provided, short-lived HTTPS download URL. Stock
stdio has no link provider and returns vault_read_binary.link_unavailable
for non-PDF auto downloads, explicit links and image fallbacks. Links must
expire within 15 minutes and deliver the original file without a login page.
Non-preview auto and explicit link inspect the source without loading or
hashing its body, so no content version is claimed. An unversioned link refers
to the current file at download time; an image fallback with a source version
must deliver those exact bytes or reject a changed file. The download handler
must recheck path protection, current read access and the PDF exclusion,
including for previously issued links. No automatic retries occur.
Examples:
{"path":"Attachments/diagram.png"}
{"path":"Attachments/archive.zip"}
{"path":"Attachments/archive.zip","as":"bytes"}
{"path":"Attachments/recording.mp4","as":"link"}Searching notes
search_query can use these fields with JsonLogic var:
Field | Value |
| Vault-relative file path, such as |
| Complete Markdown text, including frontmatter |
| Direct frontmatter and inline tags, without |
| Parsed properties; use dot notation such as |
|
|
Optional scope limits the scan to a Vault-relative directory ("" is the
root). Both directory and recursive are required when scope is provided:
recursive: false scans only direct child files; true includes subdirectories.
Omitting scope keeps the recursive whole-Vault Markdown scan.
Budget parameters on search_query and tag_list are optional. Normally omit
them to use default limits; set them when you intentionally want custom hard
limits. For example, scan only projects/ and its subdirectories for needle,
choosing a limit of 50 matches:
{
"scope": {"directory": "projects", "recursive": true},
"query": {"in": ["needle", {"var": "content"}]},
"maxResults": 50
}Only scope limits which files the server scans. Query path/glob conditions
filter returned matches without pruning the scan; glob * also matches nested
directories. maxTotalBytes limits scanned bytes, not response size.
Exceeding a scan or result limit returns an error
instead of partial results. Each match contains filename, version and the
query's truthy result value; this example returns true, not a text snippet.
Results also have a fixed 4 MiB output budget, including conservative per-result
overhead. Overflow returns search_query.budget_exceeded with
budget: "maxOutputBytes"; this budget is not a configurable input parameter.
links, backlinks and unresolvedLinks are unavailable. To find possible
references, search content for literal link text, for example
{"query":{"in":["[[Note",{"var":"content"}]}}. Inspect candidates with
vault_get_document_map and targeted vault_read; a text match does not resolve
links and may miss other link spellings or match longer names.
JsonLogic supports comparisons, logic, string/collection/arithmetic operators,
plus glob and regexp. Unsafe prototype access and the log operator are
rejected. Malformed or unsupported frontmatter in any scanned note fails the
query explicitly.
An operator expression has exactly one key. Objects with multiple keys are
literal data in JsonLogic; for example, {"a":1,"b":2} is a truthy result for
every scanned note, not two conditions. Combine conditions with and or or.
Finding references to a target
reference_query is a separate read-only tool. Specify where to scan Markdown
bodies, whether to recurse, and the exact Vault-relative target file:
{
"scope": {"directory": "projects", "recursive": true},
"resolutionScope": {"directory": "", "recursive": true},
"target": {"path": "notes/Design.md"}
}resolutionScope inventories filenames, including attachments; it does not
read every note body. It defaults to scope. Bare wikilinks such as [[Design]]
need a recursive root inventory to establish uniqueness among accessible files.
A unique candidate in a partial inventory remains unknown; duplicate candidates
are ambiguous. Explicit paths to the requested target can resolve outside that
inventory. The target is inspected/read even when outside the source scope.
To query a section, use target: {"path":"notes/Design.md","heading":["Overview"]};
for a block, use target: {"path":"notes/Design.md","block":"decision"}. Do not
combine heading and block. Heading texts are case-sensitive, plain, consecutive
ancestor names; duplicate anchors are ambiguous, not selected by map suffixes.
matches contains confirmed references. uncertain contains ambiguous,
unresolved, unsupported or unknown occurrences across the source scope; these
may be unrelated to the target and are not inferred backlinks. Each occurrence
includes source path/version, raw link, parsed destination when available,
zero-based half-open UTF-16 offsets and one-based line/UTF-16 column.
target.fileExists describes the file; target.status separately describes the
requested file/heading/block. Target Markdown carries its exact-byte version.
Supports ordinary wikilinks and CommonMark inline/reference links, display aliases and embeds. Frontmatter aliases do not add filename candidates. Attachments are checked for existence only; page/time fragments are unsupported, and this does not enable PDF reading. Formatted heading anchors are conservative/unsupported. Frontmatter, code, comments, balanced math, HTML and external URLs are excluded.
Completeness covers only the declared scopes and supported syntax. Incoming
links outside the source scope remain unknown; this is not an atomic Vault
snapshot. Defaults/hard maxima: entries 20,000/200,000; inventoried files
2,000/10,000; per-file bytes 1/4 MiB; total read bytes 8/32 MiB; returned matches
plus uncertainties 1,000/10,000; JSON output 1/4 MiB. Override with maxEntries,
maxFiles, maxFileBytes, maxTotalBytes, maxResults, maxOutputBytes.
The final target recheck counts toward total read bytes. Parsing also has worker,
time and structural limits. Overflow, scan failure or detected namespace/target
change fails the call; no partial success, mutation, repair or automatic retry.
Listing tags
tag_list({}) returns tags from Markdown files with a count of files containing
each tag. Names omit #; repeated occurrences in one file count once. Nested
parents are included: a/b also counts toward a. By contrast, vault_read
and search_query expose direct tags without adding parents.
Tags come from frontmatter tags and inline hashtags. Inline recognition may
differ from Obsidian Desktop. Budget arguments are optional; normally omit them
to use defaults. maxTags counts unique names including parents. Scan or tag
limit overflow fails explicitly, without returning a truncated list. Malformed
or unsupported frontmatter also fails the scan.
Patching headings and properties
Call vault_get_document_map first to discover exact heading paths and obtain
the file's current exact-byte version for ifMatch. The map returns that
version without returning the whole note text. Replace <current version> in
each example below with the version from the latest map or read of note.md.
Use content for Markdown or label edits, value for frontmatter property
values, or destination for heading moves; do not combine these payloads.
delete takes no payload. With scope: "marker", supply only the new label,
without heading # markers. Conflicts and failures are not automatically retried.
These examples are independent. For a note with # Root, ## A and ## B,
replace the content of A while keeping its heading:
{
"path": "note.md",
"targetType": "heading",
"target": ["Root", "A"],
"operation": "replace",
"scope": "content",
"content": "New body.",
"ifMatch": "<current version>"
}Set the status property, creating it if missing. Use value, not content;
omit createTargetIfMissing when a missing property should be an error:
{
"path": "note.md",
"targetType": "frontmatter",
"target": "status",
"operation": "replace",
"value": "ready",
"createTargetIfMissing": true,
"ifMatch": "<current version>"
}When vault_patch targets a heading section, omit within. Heading markers in
content are relative to the selected heading and scope, not absolute Markdown
levels. within instead selects a body block for a block edit.
Scope and operation | Meaning of content starting with |
| A direct child of the selected heading |
| A sibling section before / after the selected section and its descendants |
For example, with # Root containing ## A and ## B, insert a new sibling
section immediately after A by calling vault_patch with:
{
"path": "note.md",
"targetType": "heading",
"target": ["Root", "A"],
"operation": "append",
"scope": "markerAndContent",
"content": "# Inserted",
"ifMatch": "<current version>"
}The stored order is ## A, ## Inserted, ## B. Use prepend to insert before
A. With the default content scope, # Inserted would instead become
### Inserted inside A; ## Inserted would become #### Inserted.
destination moves an existing heading section. For example, to move A
under B as its last child, use operation: "replace" and scope: "parent"
with a fresh version and no content:
{
"path": "note.md",
"targetType": "heading",
"target": ["Root", "A"],
"operation": "replace",
"scope": "parent",
"destination": {"parent": ["Root", "B"], "place": "last"},
"ifMatch": "<current version>"
}After a structural patch, check vault_get_document_map for actual nesting or
read the whole file with vault_read({"path":"note.md"}) for stored # levels.
Targeted heading reads normalize levels relative to the selected scope, so
their displayed # counts alone cannot confirm the stored hierarchy.
Writing and appending text
vault_write creates a UTF-8 text file or replaces its whole content.
vault_append adds text, creating the file if missing. Both create missing
parent directories. Binary file extensions, NUL and malformed text are refused.
For an existing file, obtain its latest version with vault_read or
vault_get_document_map and pass it as ifMatch; there is no force bypass.
For a new file omit ifMatch. A version conflict means the file changed:
reread, reconcile the intended edit, then decide whether to submit a new write.
No mutation is automatically retried on conflict or failure.
Append adds LF before the supplied text when an existing file does not end in LF, including an empty existing file. A missing file receives exactly the supplied content. Successful writes return a compact receipt with the new version, not the whole note. A successful receipt with a cleanup warning means the content was saved; inspect the warning instead of blindly appending again.
Paths and file limits
One shared sandbox rejects absolute/traversing/noncanonical paths, symbolic links, escape, reserved Windows names and replacement of the original Vault root. Dot-prefixed components are protected internals; embedders can protect additional internal-state subtrees. Discovery and direct tools use the same policy. These are generic containment and internal-state safeguards. Text access rejects binary extensions, NUL and malformed UTF-8/Unicode, while preserving BOM and original newlines. Reads and mutations default to 4 MiB with a 64 MiB hard cap.
The mutation path is deliberately small:
Serialize the relative path across store instances in this process; safely read existing bytes and require exact-byte
ifMatchfor existing write/append and all patches. Validate the prepared text before changing files.Create missing parent directories through the shared sandbox. Write a hidden
.obsidian-mcp-<random>.tmpbeside the target using exclusive creation. Normal OS creation defaults inherit directory permissions/default ACLs; MCP never calls chown/chmod/setfacl or runs a permissions hook.Flush the completed temporary file, close it, and revalidate parents, path, temporary identity and the original exact-byte version. No append/patch retry.
Atomically rename over an existing file. For a missing file, atomic hard-link publication refuses a concurrent new destination, then removes the temp name. Node rename has no NOREPLACE flag. No unlink-before-replace or copy fallback.
Temporary files are blocked by the same protected-path policy and omitted from list/search/tag discovery. Failed writes remove their exact temp name after identity checks. Unsafe/failed cleanup is reported; a successful create with a leftover temp returns an explicit saved-note warning, not a misleading failure. Missing parent directories can remain after a failed operation. No startup orphan sweeper, parent-directory fsync, durability modes or permission manager is included. A single file fsync is retained before publication; this is not a power-loss durability guarantee.
New file inodes inherit deployment permissions from the destination directory. MCP does not preserve/reassign per-file ownership or ACLs. Linux validation must verify permission inheritance and allowed/denied operations for the actual process identity and deployment filesystem, including directory permissions that govern rename and deletion. It must also qualify native symlink/race and rename behavior. Windows fixtures and injected faults do not validate POSIX ACLs.
Per-path locks are process-local. Final version checks are optimistic checkpoints, not cross-process filesystem CAS; Sync keeps its own conflict handling. Parent identities are revalidated, but native Node path calls do not lock directories against adversarial renames between syscalls. Directory ownership and access must keep the namespace trusted; the remaining platform behavior is qualified on each deployment's operating system and filesystem.
Stdio requires only OBSIDIAN_VAULT_ROOT; no staging-root or policy-module
configuration is needed. Protocol output uses stdout; diagnostics use stderr.
Write/append/patch success is a compact message: "OK" receipt with path,
exact-byte version, byte count, creation status and any warnings, without echoing
the note body.
Moving and deleting files
vault_move takes path, destination and optional allowOverwrite (false by
default), returning {message: "OK", oldPath, newPath}. Missing destination
parents are created. A trailing / retains the filename; an empty destination
moves to the Vault root. Desktop link rewriting and history updates are
unavailable, so referring notes are unchanged. Overwrites use atomic rename.
Without overwrite permission, atomic hard-link publication refuses a raced-in
destination, followed by source unlink. Both names briefly exist; a failed source
unlink removes only the newly created link. If safe cleanup fails, the error
names both relative paths for inspection. There is no copy fallback or retry.
vault_delete takes path and optional permanent (false by default).
Recoverable deletion renames into .trash/<unique-directory>/<filename> on the
same filesystem and returns message, path, permanent: false and trashPath.
Recovery uses filesystem access to that receipt path; .trash is protected from
ordinary MCP tools. permanent: true unlinks the file and returns message,
path and permanent: true. Trash failure never falls back to permanent deletion.
Both tools accept an optional SHA-256 ifMatch extension and share the mutation
locks and path checks. They can relocate/delete attachments without decoding or
transferring their bytes. Version checking is limited to 64 MiB; omitted tokens
retain Local REST's operation-on-current-path behavior. Operations on directories
and additional hard links are refused; directory deletion could contain protected
internal descendants. The exact Desktop differences are recorded in the parity table.
Requirements and checks
Node.js 22 or newer. Install with npm ci; npm run check verifies generated
help, typechecks, runs disposable-fixture tests and builds. Individual commands are
npm run typecheck, npm test and npm run build.
GitHub Actions runs the same check on Linux with Node 22 and 24. For ordinary
code changes, run the local check once; there is no required manual OS/Node
matrix. Additional Linux checks depend on the affected behavior or release needs.
The portable test runner discovers compiled test files explicitly and runs
them in separate processes, one file at a time. See contributing
for the development workflow.
Pinned parser/JSON/YAML/MIME dependencies are documented in the parity table.
sharp is the only additional dependency for bounded raster previews; it does
not render PDFs. See binary deployment integration
for the provider required by generic downloads and deployment acceptance steps.
Tests cover compact transport, targeted reads, frontmatter operations, JsonLogic
values and limits, shared path/text policy, concurrency, exact byte versions,
temp-file/publication ordering, hidden artifacts, races, cleanup and filesystem error propagation.
Binary tests cover PDF rejection across all modes/resources, generic download
links, explicit exact-byte transfer, previews, limits, resource versions,
link-provider boundaries, and a real stdio child process with the MCP SDK client.
Available Tools
13 toolsobsidian_helpBRead-onlyIdempotent
Usage manual; omit topic for the topic index.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds one behavioral trait beyond the annotations: that omitting topic yields a topic index. It discloses nothing about rate limits, output format, or failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short clauses, front-loaded with the tool's identity followed by the parameter instruction; no filler. It is arguably too terse for a help tool, but nothing in it is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only one optional parameter and an output schema present, return-value detail is not required, and the annotations carry the safety profile. Still, the definition gives the agent no sense of what topics are available or what the manual covers, leaving discovery entirely to trial calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the single parameter, so the description must carry the meaning. It does explain the optionality semantics — omitting topic returns the topic index, implying topic selects a specific entry — but it never says what valid topic values look like or how to discover them, so the compensation is partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (a usage manual / help documentation), which is clearly distinct from the vault-operation siblings like vault_read and vault_write. It stops short of stating an explicit verb or the scope of the manual, but an agent can identify it as the documentation tool without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied — the agent is expected to infer that this is the tool to call when it needs documentation. The clause 'omit topic for the topic index' does give one concrete invocation instruction, but there is no explicit when-to-use vs alternatives guidance beyond that.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reference_queryARead-onlyIdempotent
Find references to a file/heading/block within explicit source and resolution scopes. Read-only; returns matches plus uncertainties and exact source versions. Outside-scope incoming links remain unknown. See help topic references.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | Yes | ||
| target | Yes | ||
| maxFiles | No | ||
| maxEntries | No | ||
| maxResults | No | ||
| maxFileBytes | No | ||
| maxTotalBytes | No | ||
| maxOutputBytes | No | ||
| resolutionScope | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| scope | Yes | |
| target | Yes | |
| matches | Yes | |
| coverage | Yes | |
| uncertain | Yes | |
| resolutionScope | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety is covered. The description adds genuinely useful behavioral context beyond that: it returns matches plus uncertainties and exact source versions, and it explicitly warns that outside-scope incoming links remain unknown, which is a completeness limitation an agent must know about.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core action and followed by the return/limitation caveat and a doc pointer. No filler, though 'See help topic references' shifts work to an external document rather than resolving it inline.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is read-only with an output schema, so return values need not be spelled out, and the description still usefully flags uncertainties and version reporting. The gap is the parameter side: with 9 params, nested objects and 0% schema coverage, the undocumented max* limits leave an agent guessing about throttling and truncation behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 9 parameters, so the description must carry the load. It partially does: 'source and resolution scopes' maps to scope/resolutionScope, and 'file/heading/block' maps to the target object. But the seven max* limit parameters (maxFiles, maxEntries, maxResults, maxFileBytes, maxTotalBytes, maxOutputBytes) get no mention at all, leaving a large documentation gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Find references to a file/heading/block'), which tells an agent this is a backlink/reference lookup rather than a content search. It does not explicitly distinguish itself from the nearest sibling, search_query, leaving the agent to infer the split between 'what links here' and 'find text'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'within explicit source and resolution scopes' and the caveat about outside-scope links, which hints at the scoping model an agent must set up. However, there is no explicit when-to-use-vs-alternatives guidance (e.g. versus search_query), only a pointer to 'help topic references' that defers the decision to external docs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_queryARead-onlyIdempotent
Query Markdown with JsonLogic over path, content, tags, frontmatter and stat. Returns truthy values. Only scope limits the scan; query path/glob conditions only filter results. Overflow errors, never truncation. No link graph.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| scope | No | Optional scan scope; omit for a recursive whole-Vault scan. directory "" is root; recursive=false scans only direct child files. | |
| maxFiles | No | Optional scanned-file cap; omit for defaults. | |
| maxEntries | No | Optional scanned-entry cap; omit for defaults. | |
| maxResults | No | Optional match cap, not truncation; omit for defaults. | |
| maxFileBytes | No | Optional per-file byte cap; omit for defaults. | |
| maxTotalBytes | No | Optional scanned-byte cap, not response size; omit for defaults. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds real behavioral context beyond that: query results are evaluated for truthy values, only scope limits the scan while path/glob conditions merely filter, and overflow produces errors rather than truncation. That is meaningful semantics the schema and annotations do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five short sentences, each carrying a distinct fact, with the core purpose front-loaded. No filler, no repetition of schema or annotation content, and the important overflow-vs-truncation guarantee is stated tersely.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex JsonLogic query tool with an output schema present, the description covers purpose, evaluation semantics, scope behavior, overflow handling, and the link-graph exclusion. The only meaningful gap is the absence of an explicit pointer to reference_query as the alternative for link queries, which would complete the routing picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 86%, so the schema already documents scope, the max* caps, and the query object. The description still adds value by enumerating the queryable domains (path, content, tags, frontmatter, stat) that the bare 'query: object' schema does not reveal, and by clarifying that path conditions inside the query filter rather than limit scanning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: query Markdown via JsonLogic over path, content, tags, frontmatter and stat. This clearly identifies what the tool does and its query domain. However, it never names the closest sibling (reference_query) even though the 'No link graph' clause hints at the boundary between them, so differentiation is only implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit 'use this when' statement or named alternative. The clause 'No link graph' implicitly steers link-oriented queries toward reference_query, and the scope/path-filter clarification implies when scanning vs filtering applies, but an agent must infer the routing rather than read it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tag_listARead-onlyIdempotent
List tags and parent tags with per-file counts; names omit #. Scan/result limits fail explicitly. Inline recognition may differ from Obsidian Desktop.
| Name | Required | Description | Default |
|---|---|---|---|
| maxTags | No | Optional unique-tag cap including parents; omit for defaults. | |
| maxFiles | No | Optional scanned-file cap; omit for defaults. | |
| maxEntries | No | Optional scanned-entry cap; omit for defaults. | |
| maxFileBytes | No | Optional per-file byte cap; omit for defaults. | |
| maxTotalBytes | No | Optional scanned-byte cap, not response size; omit for defaults. |
Output Schema
| Name | Required | Description |
|---|---|---|
| tags | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, so the bar is lower, yet the description adds real behavioral context: limits 'fail explicitly' (i.e., errors instead of silent truncation) and inline recognition 'may differ from Obsidian Desktop'. Those caveats are not derivable from the annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight clauses, no filler, with the core purpose front-loaded before the two caveats. Nothing redundant is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values needn't be described, annotations cover the safety profile, and the schema documents all five caps. The description covers the surprising edge cases; only the when-to-use gap keeps it from being fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every cap parameter is self-documented in the schema, so the baseline of 3 applies. The description adds no syntax or default guidance beyond the schema's 'omit for defaults'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'List tags and parent tags with per-file counts', and adds a concrete output detail ('names omit #'). It is clearly distinguishable from vault_list and search_query by resource, though it never explicitly contrasts itself with those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to reach for tag_list versus search_query or vault_list, nor does it state any prerequisites. Usage is only implied by the word 'List'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_appendA
Append UTF-8 text; creates missing files. Existing files require ifMatch; missing final LF is added first. Binary/NUL refused; no automatic retry.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| content | Yes | ||
| ifMatch | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| created | Yes | |
| message | Yes | |
| version | Yes | |
| warnings | No | |
| sizeBytes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only declaring the generic safety flags, the description carries substantial extra load: it discloses upsert semantics, optimistic-concurrency requirements for existing files, a silent side effect (missing final LF is added), input rejection rules (binary/NUL refused), and retry behavior ('no automatic retry'). These are exactly the traits an agent cannot infer from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four compact clauses, no filler, and the primary action is front-loaded before the caveats. Every clause adds a distinct operational fact, so nothing could be cut without losing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description covers creation, concurrency, encoding, and retry behavior. Remaining gaps are minor: no mention of the content size cap enforced by maxLength, no path-format guidance, and no note on permissions or failure modes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does for two of three params: ifMatch's conditional requirement and content's UTF-8/text-only constraint. It says nothing about the path parameter (format, vault-relative vs absolute), leaving one gap, and the sha256: prefix format is only conveyed by the schema pattern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Append UTF-8 text') plus upsert behavior ('creates missing files'), which cleanly separates it from vault_write and vault_patch without naming them. Sibling differentiation is implied by the verb rather than stated explicitly, so it falls just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives one real conditional rule ('Existing files require ifMatch'), which tells the agent when a parameter becomes mandatory. However, it never says when to choose vault_append over vault_write or vault_patch, nor any preconditions such as vault availability or path scoping, so usage is only partially covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_deleteADestructive
Delete a file to recoverable Vault .trash; permanent=true is irreversible. ifMatch checks source. No automatic retry or permanent fallback.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| ifMatch | No | ||
| permanent | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, it discloses that the default path is recoverable via .trash, that permanent=true is irreversible, that ifMatch guards against source changes, and that there is no automatic retry or permanent fallback. These are exactly the operational traits an agent needs to avoid data loss and to handle retries itself.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the default (recoverable) behavior before the irreversible flag, with zero filler. Every clause carries distinct operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and annotations cover the safety profile. The description supplies the remaining behavioral essentials, though it omits edge cases such as missing paths or directory handling that a mutation tool could clarify.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description must carry the parameter burden, and it explains the two non-obvious ones: permanent controls irreversibility and ifMatch validates the source. Only 'path' is left undocumented, though its meaning is self-evident from the name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (Delete) and resource (a file in the Vault), and its default semantics ('to recoverable Vault .trash') immediately distinguish it from the read/write/append/patch siblings, which cannot destroy data. An agent can identify this as the sole deletion tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the deletion context and warns that permanent=true is irreversible, but never states when to prefer this tool over alternatives or what prerequisites apply (e.g. whether the file must exist). Usage is inferable rather than explicit, which matches a 3.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_get_document_mapBRead-onlyIdempotent
Get heading paths, block IDs, property names and exact-byte version. Copy returned keys unchanged for targeted reads/patches.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| maxBytes | No | ||
| maxHeadings | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| blocks | Yes | |
| version | Yes | |
| headings | Yes | |
| frontmatterFields | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description does add real value beyond that by introducing the 'exact-byte version' token and warning that returned keys must be copied unchanged. It nonetheless omits truncation behavior despite bounds on maxBytes/maxHeadings, which is a material behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, with the payload contents front-loaded and the operational caveat second. Nothing is redundant with the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value structure need not be explained, and the description rightly focuses on how to consume the result. Still, with three parameters at 0% schema coverage and no note about what happens when maxBytes or maxHeadings are hit, an agent cannot fully predict the call's behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the full burden of explaining path, maxBytes and maxHeadings. It explains none of them: maxBytes and maxHeadings in particular are opaque limit parameters whose truncation semantics are left entirely undefined, and even 'path' is not clarified as a vault-relative path or a folder path.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and enumerates what the map contains (heading paths, block IDs, property names, version), which is far more informative than the name alone. It hints at its role relative to siblings by pointing to 'targeted reads/patches', though it never names vault_read or vault_patch explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Copy returned keys unchanged for targeted reads/patches' implies a workflow (map first, then targeted read/patch), which is genuinely useful routing guidance. However, it never states when to choose this tool instead of vault_read or the other read siblings, nor any preconditions, so the guidance remains implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_listARead-onlyIdempotent
List a Vault directory; omit path or use "" for root. Directory names end in /. Protected/symlink entries are omitted; overflow errors, never truncation.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | ||
| maxEntries | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| files | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and closed-world, so the safety profile is covered. The description adds real behavior beyond that: trailing '/' on directory names, omission of protected/symlink entries, and a failure mode where overflow errors rather than truncates. That error-over-truncation guarantee is exactly the kind of context an agent needs and could not get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence pair: the core action and root-addressing rule come first, then the behavioral caveats. No filler, no repetition of the schema, and the most decision-relevant constraint (root path) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return-shape explanation is unnecessary, and the annotations carry the safety profile. The description adds the filtering rules and the error-not-truncation contract, which is most of what an agent needs; only the maxEntries semantics remain undocumented in prose.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description has to carry both parameters. It explains path well (omitting it or passing "" selects root), and 'overflow errors, never truncation' indirectly implies maxEntries caps results and errors when exceeded, but maxEntries is never named or bounded in prose. Partial compensation for a coverage gap, hence a mid score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource ('List a Vault directory') and immediately pins down the scope ('omit path or use "" for root'), which is enough for an agent to distinguish it from vault_read, vault_get_document_map, and search_query without opening a schema. It stops short of naming a sibling alternative explicitly, so it falls just below the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent how to address the root directory ('omit path or use ""'), which is useful invocation guidance, but it never states when to choose vault_list over search_query or tag_list, nor any exclusions or prerequisites. Usage is implied by the name rather than argued.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_moveADestructive
Move a file; no link/history updates. Creates parents; trailing / retains filename. Overwrite requires allowOverwrite. ifMatch checks source only. No retry or cross-filesystem fallback.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| ifMatch | No | ||
| destination | Yes | ||
| allowOverwrite | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| newPath | Yes | |
| oldPath | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the destructive/idempotent annotations, disclosing that links and history are NOT updated, that parent directories are created, that overwrite requires allowOverwrite, that ifMatch validates the source only, and that there is no retry or cross-filesystem fallback. These are exactly the side-effect and failure-mode details an agent needs before a destructive move.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five dense clauses, each conveying a distinct constraint, with the core action front-loaded and no filler. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation. For a destructive move tool the description covers side effects, overwrite conditions, precondition checking, and failure behavior, leaving nothing critical unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the parameters. It explains allowOverwrite (required for overwriting), ifMatch (validates source only), and destination semantics via the trailing-slash rule; only the plain path/destination roles are left implicit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Move a file'), which is immediately distinguishable from read/list siblings. It does not explicitly contrast with vault_write + vault_delete, the plausible alternative, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The use case (moving a file) is implied clearly, but there is no explicit when-to-use versus siblings such as delete-then-write, and no preconditions stated beyond the conditional overwrite rule. It gives conditional mechanics rather than selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_patchBDestructive
Patch a heading/block/property with exact-byte ifMatch from a read/map. Copy map keys unchanged. Heading content uses relative levels. No automatic retry.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| scope | No | ||
| value | No | ||
| target | Yes | ||
| within | No | ||
| content | No | Heading target without within: # is a child in content scope, a sibling with markerAndContent prepend/append. | |
| ifMatch | Yes | ||
| operation | Yes | ||
| targetType | Yes | ||
| destination | No | Heading move only: operation=replace, scope=parent; omit content. | |
| createTargetIfMissing | No | ||
| rejectIfContentPreexists | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| created | Yes | |
| message | Yes | |
| version | Yes | |
| warnings | No | |
| sizeBytes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true, idempotent=false, readOnly=false, so the safety profile is covered. The description adds genuine value beyond that: the exact-byte ifMatch precondition (optimistic concurrency) and "No automatic retry" — a non-obvious behavioral trait an agent must handle itself. It stops short of describing auth needs or what a failed ifMatch returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four terse sentences, front-loaded with the core action and the ifMatch precondition, with no filler. It is dense but every clause carries information; it is arguably too compressed given the tool's complexity rather than padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter, nested-object, destructive mutation with 17% schema coverage, a four-sentence description is thin. Output schema existing means return values need not be explained, but the mutation semantics, parameter behavior, and sibling routing are largely absent, leaving real gaps an agent would hit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 17% across 12 parameters with nested objects, so the description must compensate heavily but only touches ifMatch, map-key copying, and heading relative levels. It says nothing about operation, scope, targetType, destination, createTargetIfMissing, or rejectIfContentPreexists, leaving most parameters documented only by their bare enum values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (patch) and concrete resources (heading/block/property), and the ifMatch phrasing signals a conditional partial update distinct from a full write. It is clear on its own but never names or contrasts with siblings like vault_write, vault_append, or vault_move, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"with exact-byte ifMatch from a read/map" implies the prerequisite workflow (obtain the token from vault_read/vault_get_document_map before calling), which is useful implied guidance. However, there is no explicit when-to-use-vs-alternative statement, no when-not guidance, and no routing against the other mutation siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_readARead-onlyIdempotent
Read a Vault text file or target with its version. Discover targets via vault_get_document_map; targeted heading levels are relative. No link graph.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| scope | No | Requires a target; defaults to content. | |
| target | No | Pair with targetType. Heading: full map path, e.g. ["Root","Child"]; block: ID without ^; property: key. | |
| maxBytes | No | ||
| targetType | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered. The description still adds real behavioral context: results carry a version, targeted heading levels are resolved relative to a base, and the read does not traverse a link graph.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short clauses, front-loaded with the core action and free of filler. It is terse to the point of leaving some parameter behavior unexplained, but every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and annotations cover the safety profile. The gaps are the undocumented maxBytes/targetType parameters and the interplay of scope with target, which the description does not clarify.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 40%, with maxBytes and targetType carrying no descriptions at all. The description partially compensates by explaining target discovery and the relative nature of heading targets, but it says nothing about maxBytes truncation or targetType values, leaving half the parameters undocumented in both places.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read a Vault text file or target') and adds scope qualifiers ('with its version', 'No link graph') that separate it from graph-oriented siblings. It does not explicitly contrast with vault_read_binary, but the 'text file' framing implies the distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Points the agent to vault_get_document_map for discovering targets, which is genuine routing guidance. However, it never states when to choose this over vault_read_binary or other read siblings, and gives no prerequisites or exclusions beyond that one pointer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_read_binaryARead-onlyIdempotent
Read images and non-PDF attachments. auto: raster preview or signed HTTPS download link. bytes: original data up to 4 MiB. PDF is unsupported in every mode; use the client's native file upload/attachments.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | ||
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower, and the description adds real value beyond them: a 4 MiB cap in bytes mode, a signed HTTPS link in auto mode, and a hard PDF exclusion. It does not mention whether signed links expire or require auth, which is the one notable gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scope statement, then mode behaviors, then the exclusion. Every clause carries information and there is no filler, though the telegraphic style trades a little readability for density.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation. The description covers the supported content types, all three modes at least in outline, the size cap, and the PDF exclusion — enough for correct invocation, with only link-mode details and path semantics left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the parameters. It explains the 'auto' and 'bytes' enum values and implies 'link' via the signed-URL mention, but the third enum value is never described on its own and 'path' is undocumented. Partial compensation for a 2-param tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Read images and non-PDF attachments'), which implicitly scopes it away from the text-reading sibling vault_read. It does not name vault_read explicitly, so the sibling differentiation is inferable rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the negative case ('PDF is unsupported in every mode') and routes PDFs to an alternative ('use the client's native file upload/attachments'), and it describes each 'as' mode. It never says when to prefer auto vs bytes vs link, leaving that inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vault_writeADestructiveIdempotent
Create or replace UTF-8 text. Existing files require ifMatch; no force bypass. Creates parents. Binary/NUL refused; no automatic retry.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| content | Yes | ||
| ifMatch | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| created | Yes | |
| message | Yes | |
| version | Yes | |
| warnings | No | |
| sizeBytes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint, idempotentHint, and readOnlyHint=false, so the safety profile is covered. The description adds real value beyond them: parent directories are created, binary/NUL content is refused, there is no automatic retry, and no force-override exists for existing files. It stops short of noting permission/auth requirements or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four terse clauses, front-loaded with the core action before constraints. Every sentence carries a distinct behavioral fact with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. For a mutating tool the description covers the crucial mechanics (ifMatch gating, parent creation, refusal rules, retry behavior), leaving only path semantics and content limits unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the load. It meaningfully explains ifMatch's purpose (required for existing files, no force bypass), but says nothing about path format constraints or the content size limit that the schema enforces. It compensates for one of three parameters only.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Create or replace UTF-8 text'), which is far more precise than the bare name vault_write. It implicitly differentiates from siblings vault_append/vault_patch by emphasizing replace semantics, though it never names them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a conditional rule ('Existing files require ifMatch; no force bypass') which implies when the tool is applicable, but never states when to choose it over vault_append or vault_patch, nor what happens on a first-time create vs overwrite beyond the ifMatch hint. Usage is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
- Changed
search_query1 field changed- added
Input schema / properties / scopeAdded value: +{ + "additionalProperties": false, + "description": "Optional scan scope; omit for a recursive whole-Vault scan. directory \"\" is root; recursive=false scans only direct child files.", + "properties": { + "directory": { + "type": "string" + }, + "recursive": { + "type": "boolean" + } + }, + "required": [ + "directory", + "recursive" + ], + "type": "object" +}
13 tool updates
v0.1.0- First observed
obsidian_help - First observed
reference_query - First observed
search_query - First observed
tag_list - First observed
vault_append - First observed
vault_delete - First observed
vault_get_document_map - First observed
vault_list - First observed
vault_move - First observed
vault_patch - First observed
vault_read - First observed
vault_read_binary - First observed
vault_write
TDQS
Scored across 13 tools
The vault_* tools carve out distinct operations (read vs write vs append vs patch vs move vs delete), and search_query vs reference_query serve different purposes. Minor overlap between vault_read/vault_get_document_map and vault_read vs vault_read_binary could cause slight confusion, but descriptions clarify.
The vault_* family is consistently verb-suffixed (vault_list, vault_read, vault_write), but other tools mix conventions (search_query, reference_query, tag_list, obsidian_help). Readable overall but not a single predictable pattern.
13 tools is well-scoped for an Obsidian vault server, covering the essential file, query, tag, and reference operations without bloat.
Strong lifecycle coverage: read, write, append, patch, move, delete, list, search, references, tags, and document mapping. Notable gap is no binary write (only vault_read_binary) and no copy operation, but these are minor workarounds.
Maintenance
Related MCP Connectors
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
Search, read, and safely update Markdown notes in your connected Phasoric knowledge vaults.
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server for managing an Obsidian vault with CAS-based write, note listing, reading, writing, patching, and searching via ripgrep.310 npmMIT
- FlicenseCqualityCmaintenanceMCP server to query and modify an Obsidian vault or any folder of markdown files. It provides search, tag filtering, backlinks, and CRUD operations on notes, with path traversal protection.11-
- AlicenseAqualityBmaintenanceEnables MCP clients to safely read, search, create, edit, delete, and move notes in an Obsidian vault, with automatic link repair and reversible deletes.103,458 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables MCP clients to search, read, list, and append to markdown notes in a local Obsidian vault or folder of .md files.-