Kybase
Kybase’s MCP server lets agents read, search, and maintain a self-hosted Markdown knowledge base.
Search notes with hybrid keyword/semantic/text search, including places inside one note.
Read notes by ID or title, paged or by section, with optional wikilink resolution.
Create, update, append to, and exact-text replace note content.
Soft-delete, restore, and list trashed notes.
Organize notes with folders and tags; create, rename, move, and delete folders.
Explore
[[wikilinks]]via backlinks, neighbors, and graph views.Check semantic indexing status and the active embedding model.
List notes by recency, folder, tag, or date to see what is new or recently changed.
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., "@Kybasesearch my notes about meeting notes"
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.
Kybase gives Claude, ChatGPT, Cursor and any other MCP-speaking agent a long-term memory you own: one Markdown knowledge base, running on your own machine, that every agent can search, read and update — and that you can open in a browser and edit by hand.
Self-hosted. Private by default. Plain Markdown. Yours.
The problem · Quick start · Connect your agent · What you get · Settings · Sharing · Backups · Upgrading
The problem
You tell your agent how the staging deploy works. It helps, and the session ends.
Tomorrow you open a new one:
You: what did we decide about the staging database?
Agent: I don't have that context — could you tell me again?
So you explain it again. Then you switch editors, and explain it there too.
With Kybase, the knowledge lives outside the agent:
You: what did we decide about the staging database?
Agent: (searches Kybase) You moved staging to its own Postgres instance so migrations could be tested against real data first — that's in "Staging environment", under "Database".
New session, same memory. Different tool, same memory.
Related MCP server: Cairn MCP Server
Quick start
One local agent
Nothing to install, no Docker, no database to run:
{
"mcpServers": {
"kybase": {
"command": "npx",
"args": ["-y", "kybase-mcp"]
}
}
}Put that in your client's MCP config and restart it. Your notes live under
~/.kybase, and kybase-mcp export vault.zip gets them back out as plain
Markdown at any time.
The full app
For the web UI, the graph view, share links, and several agents against one knowledge base:
macOS and Linux
git clone https://github.com/Kyrzin/kybase.git
cd kybase
cp .env.example .env
sed -i.bak "s/^KYBASE_SECRET=$/KYBASE_SECRET=$(openssl rand -hex 32)/" .env
sed -i.bak "s/^POSTGRES_PASSWORD=$/POSTGRES_PASSWORD=$(openssl rand -hex 16)/" .env
rm -f .env.bak
docker compose pull && docker compose up -dWindows (PowerShell) — no openssl or sed there, so the secrets are
generated by .NET instead:
git clone https://github.com/Kyrzin/kybase.git
cd kybase
Copy-Item .env.example .env
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$b = New-Object byte[] 32; $rng.GetBytes($b)
$secret = ($b | ForEach-Object { $_.ToString('x2') }) -join ''
$b = New-Object byte[] 16; $rng.GetBytes($b)
$pass = ($b | ForEach-Object { $_.ToString('x2') }) -join ''
(Get-Content .env) -replace '^KYBASE_SECRET=$', "KYBASE_SECRET=$secret" -replace '^POSTGRES_PASSWORD=$', "POSTGRES_PASSWORD=$pass" | Set-Content .env
docker compose pull
docker compose up -dEither block generates the only two secrets you need and starts the stack.
Open http://localhost:3000, log in with your KYBASE_SECRET — grep KYBASE_SECRET .env shows it, or Select-String KYBASE_SECRET .env on
Windows — then connect an agent.
That installs the app and its database — around 1 GB. Notes and text search work right away.
Semantic search needs an embedding provider. Open Settings and pick one:
Google or OpenAI — paste an API key and you are done.
Ollama, on your own machine — start it once, then pick a model in Settings:
docker compose --profile ollama up -dIt is not in the default install because its image carries NVIDIA and AMD GPU runtimes whatever your hardware is — about 4 GB that someone using a cloud provider would never run. Starting it later touches nothing else: the app keeps running and no note is affected.
Connect your agent
Kybase speaks MCP over Streamable HTTP at /api/mcp. A client that supports
OAuth signs in once in your browser and gets its own token — listed under
Settings → Access and revocable on its own — so your KYBASE_SECRET
never goes into its config.
Claude Code — add it once for all your projects:
claude mcp add --transport http --scope user kybase https://your-domain/api/mcpThen run /mcp in Claude Code, pick kybase → Authenticate, and enter
your KYBASE_SECRET on the page that opens.
Moving from a secret in the config to this sign-in? Remove the old kybase
entry from the project's .mcp.json first: Claude Code prefers it to the
one above and never uses the sign-in. If that file was committed with the
secret in it, change the secret (see SECURITY.md).
That's it — the agent can now search your notes, read them, write new ones, update existing ones and link them together.
Claude Desktop and claude.ai — Customize → Connectors → Add custom
connector, same URL, then Connect and sign in. Claude connects from
Anthropic's servers, so the instance has to be reachable over HTTPS from the
internet. In Claude Desktop, remote servers go here, not in
claude_desktop_config.json.
ChatGPT — Settings → Plugins → Add → Add MCP server, type Streamable HTTP, same URL. ChatGPT then opens the Kybase sign-in page. It connects from its own servers too, so the same HTTPS requirement applies.
Cursor — ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
{
"mcpServers": {
"kybase": {
"url": "https://your-domain/api/mcp"
}
}
}Then connect kybase under Customize → MCPs and sign in.
Devin Desktop (formerly Windsurf) — ~/.config/devin/mcp_config.json
(%APPDATA%\devin\mcp_config.json on Windows), with serverUrl instead of
url:
{
"mcpServers": {
"kybase": {
"serverUrl": "https://your-domain/api/mcp",
"headers": {
"Authorization": "Bearer <KYBASE_SECRET>"
}
}
}
}That header carries your KYBASE_SECRET, which is full access to the whole
instance: use it only for a client without OAuth, and keep it in your own
config — never in a file you commit.
Clients that only speak stdio use the npx -y kybase-mcp block from
Quick start, in the same file.
What you get
Markdown, not an opaque memory blob — every note is plain Markdown that you read and edit in the browser and your agents read and edit through MCP
One knowledge base, every agent — Claude, ChatGPT, Cursor and the web UI all look at the same notes
Hybrid search — full-text and meaning-based search fused into one ranked result, so an agent finds the note whether it knows the exact wording or not
Section-level reads and writes — an agent reads or edits the part of a note it needs, not the whole file
Backlinks and a knowledge graph —
[[wikilinks]]connect related notes automaticallyYours to take — Settings → Export .zip gives plain Markdown with folders as directories, readable by any editor, Obsidian included. Import .zip merges one back.
Obsidian and Notion are built for a person reading and writing. Kybase is built for the loop between you ↔ your knowledge ↔ your agent: you edit in the browser, an agent searches and updates over MCP, and both are looking at the same Markdown. If the agent remembered something wrong, you open the note and fix the sentence.
Private by default
Kybase runs on your infrastructure. No SaaS account, no external memory service, no cloud database — your own Postgres, local embeddings through Ollama, and a secret you generate.
Cloud embedding providers are optional. Choosing one sends your notes' full text to that provider to compute embeddings; Ollama keeps everything on your machine.
How agents use it
search_notes("deployment steps for staging")
→ hit includes section: "Rollback"
→ get_note(section: "Rollback")
→ agent reads just that section, not the whole note
→ append_to_note(section: "Rollback", text: "...")Search says which section of a note matched, not just which note. On a long note that can mean reading a fraction of the content — cheaper for every step after the first search, and it is how the agent writes back too.
The server ships with instructions that teach the agent to search before
writing and to add [[wikilinks]] to related notes, so the graph grows as
the agent works instead of filling up with orphans.
Settings
Everything else goes in .env, copied from .env.example, which documents
each option. Only KYBASE_SECRET and POSTGRES_PASSWORD are required;
KYBASE_PORT changes the host port, KYBASE_BIND=0.0.0.0 opens it to other
devices on your network (by default only this machine can connect),
KYBASE_PUBLIC_URL sets the address behind your HTTPS proxy, and
KYBASE_TAG pins a version (e.g. 1.4) instead of tracking latest.
Embedding provider. Open Settings in the web UI, pick a provider (Ollama, Google or OpenAI), choose a model, add an API key if it needs one, and click Save & Apply. Switching re-embeds every note, and the database adapts to the new model's vector size on its own.
Ollama keeps everything on your machine. Google and OpenAI are convenience options: picking either sends your notes' full text to that provider.
Reranker (optional). A cross-encoder can re-order the top search
results. It is not in the default install: it needs about 800 MB of RAM
and adds a few seconds to each search on a CPU. Start it with
docker compose --profile rerank up -d; Kybase picks it up on its own,
and a switch in Settings turns it off. Without it, search works as before.
Sharing notes
The Share button on a note creates a public read-only link — rendered Markdown, no login, wikilinks shown as plain text so nothing else in your vault is reachable. The link is the access: revoke links you no longer need under Settings → Active share links.
Backups
Everything lives in one Postgres volume, so a nightly pg_dump is one line.
Full recipe including cron and restore: docs/backup.md.
Upgrading
# prebuilt image
docker compose pull && docker compose up -d
# or rebuild from source
git pull && docker compose up -d --buildMigrations apply automatically on startup. Details: docs/upgrading.md.
More documentation
SECURITY.md (threat model) · CONTRIBUTING.md (running it locally, opening a PR) · docs/backup.md · docs/upgrading.md · packages/kybase-mcp (the standalone stdio package)
License
AGPL-3.0 — free to use, modify, and self-host. If you run a modified version as a network service, you must make its source available to your users under the same license.
For a commercial license (e.g. embedding Kybase in a closed-source product or service), contact the author.
Copyright © Denis Kurzin (https://github.com/Kyrzin)
Available Tools
18 toolsappend_to_noteA
Add text to a note without resending the rest — prefer it over update_note for journals, logs and running lists. A blank line separates your text from what was there. The note is locked for the read-modify-write, so two sessions appending at the same moment keep both additions instead of the later one overwriting the earlier. Re-embeds in the background like any content change.
| Name | Required | Description | Default |
|---|---|---|---|
| at | No | Where the text lands. Defaults to section_end when section is given, else note_end. note_end: the very end. note_start: above the first heading nested under the opening one — NOT offset 0, except on a note with no headings at all, where it is; on a note whose only heading is the opening one it falls to the end instead. before_section: above the section's own heading line. section_start: directly under that heading line, above the section's body. section_end: after the section and everything nested inside it. after_section: the same position as section_end. The four section-relative values require `section` and are refused without it. | |
| id | No | The note's UUID. Alternative to title | |
| title | No | Alternative to id; resolved like get_note | |
| content | Yes | Text to add. Trailing whitespace is trimmed and a blank line is inserted before it, so the addition never runs into the preceding paragraph | |
| section | No | Target this section (heading text or slug) instead of the whole note. Valid values come from a search hit's `section`, get_note's `headings`, or a heading line in the note's own text — the slug form is only needed when two headings share a text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the blank-line separator that gets inserted, the per-note lock during read-modify-write and the concurrency outcome (both appends survive), and background re-embedding. It leaves out return value and any permission/authorization requirements.
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 sentences, front-loaded with the core distinction and preferred-use case, then concurrency and indexing behavior. No wasted framing or restatement of the tool name; each sentence delivers a distinct fact.
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 mutation tool with no annotations and no output schema, the description covers insertion semantics, concurrency, and side effects well. It stops short of saying what the call returns or whether the note must be unlocked/owned, which is the remaining gap an agent would want.
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%, including a detailed enum description for `at`, so the schema does the heavy lifting and baseline 3 applies. The description only adds the blank-line/trailing-whitespace behavior for `content`, which is already partly in the schema, and says nothing extra about `section` or `title` resolution beyond what the schema states.
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 ('Add text to a note') plus the defining constraint ('without resending the rest'), and explicitly distinguishes itself from update_note. An agent can tell append apart from update_note or replace_in_note 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?
Names the alternative it beats and the scenarios that select it ('journals, logs and running lists'). It does not name replace_in_note, which is the other plausible sibling for modifying existing note text, nor state an explicit when-not-to-use condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_folderB
Create a new folder. Optionally nested under a parent.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Folder name. Unique among its siblings — the same name under a different parent is fine | |
| parent_id | No | Parent folder UUID. Omit or pass null to create it at the top level |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden for a mutation tool. It states that a folder is created but does not disclose permissions, duplicate-name behavior, what the operation returns, or other side effects. The uniqueness constraint appears only in the schema, not in the description.
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?
The description is two short sentences with no wasted wording. The core purpose is front-loaded, and the optional nesting note follows immediately.
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 simple and the schema fully documents both parameters, so an agent can invoke it correctly from the provided structured data. However, with no annotations and no output schema, the description could have said more about return values or error behavior for this mutation.
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 100%, so both parameters are already documented in detail, including the uniqueness rule and top-level behavior. The description adds only the high-level note that nesting is optional, which is already covered by the parent_id schema description.
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: "Create a new folder." It also clarifies the optional nesting behavior. It is clear enough to distinguish from siblings like create_note, but does not explicitly differentiate from update_folder or delete_folder.
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 phrase "Optionally nested under a parent" implies that parent_id can be supplied to create a child folder, which is a useful usage condition. However, there is no explicit guidance on when to use this tool versus alternatives, nor any exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_noteA
Create a new note. Embedding is generated automatically in the background. The server instructions' wikilink and tag rules apply: search_notes for the topic first and link the related notes it finds, and call list_tags before coining a new tag.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Tags for the new note: lowercase, kebab-case, in the language already in use. Call list_tags first and reuse an existing tag where one fits | |
| title | Yes | Unique across live notes, case-insensitively; a clash is refused rather than merged. This is the string other notes link to as [[Title]] | |
| content | No | Markdown body. Empty by default, so a note can be created first and filled with append_to_note | |
| folder_id | No | Folder UUID. Omit or pass null for the vault root; use folder_path instead when you have the path rather than the id | |
| folder_path | No | Folder path (e.g. "Projects/Kybase") as alternative to folder_id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses that embeddings are generated in the background and that wikilink/tag rules apply, but it does not cover permissions, failure modes, or other side effects beyond the basic create operation.
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?
The description is front-loaded with the core action and contains no obvious filler. The third sentence is dense and references external server instructions, but it still earns its place by conveying required workflow rules.
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 create tool with a fully described five-parameter schema and no output schema, the description supplies the essential behavioral context: note creation, background embedding, and tag/link workflow. It is not fully comprehensive on failure or permission behavior, but it is sufficient for correct invocation.
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 100%, so the parameters are already well documented. The description adds little parameter-specific detail beyond process guidance around tags, which the schema also covers.
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 clear verb and resource: "Create a new note." It is immediately understandable, but it does not explicitly differentiate itself from nearby sibling tools such as append_to_note or update_note, 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?
It gives explicit prerequisite behavior: search_notes first and call list_tags before inventing a new tag. That is useful usage context, though it does not state when to choose create_note over alternatives like append_to_note or create_folder.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_folderA
Delete a folder and its full subtree of child folders (cascade). Every note inside — including notes in nested subfolders — is soft-deleted into the trash along with it (see delete_note), recoverable via restore_note within the retention window. To preserve organization instead, move notes/subfolders out first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | UUID of the folder to delete along with its subfolders. Notes inside are moved to the trash, not destroyed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does well: it discloses cascade deletion, soft-deletion into trash, recoverability via restore_note, and a retention window. It leaves some gaps around exact retention duration, permission requirements, and the response after deletion, but the core destructive semantics are unusually well explained.
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?
The description is two tightly written sentences with the cascade scope front-loaded, followed by the recovery and alternative-action context. Every sentence adds useful information without repetition or 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?
For a destructive single-parameter tool with no annotations and no output schema, the description covers the essential behavior: what is deleted, the cascade effect, trash semantics, recovery, and a preservation alternative. It could be slightly more complete with retention specifics or post-delete response expectations, but nothing critical is missing for correct invocation.
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% for the single id parameter, and the schema itself already explains that the UUID deletes the folder along with subfolders and that notes are moved to trash. The description reinforces the same cascade/soft-delete meaning but does not add syntax, format, or selection guidance beyond what the schema already provides, so baseline 3 is appropriate.
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 (delete) and resource (folder) with important scope: the full subtree of child folders (cascade). It distinguishes the operation from sibling delete_note by explaining that every contained note is also affected, so an agent can tell what this tool does and does not target.
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 clear when-to-use context and a concrete alternative path: to preserve organization, move notes/subfolders out first. It also names delete_note and restore_note for related behavior, but it does not explicitly compare itself to every plausible sibling (e.g., update_folder for reorganization), so it stops just short of full 5-level guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_noteA
Soft-delete a note by id — it disappears from list_notes/search/get_note/the graph, but is recoverable with restore_note for 30 days before being purged for good. Use list_notes with trashed:true to see what's currently in the trash.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The note's UUID. An unknown or already-trashed id is refused rather than reported as deleted |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the soft-delete semantics, the 30-day recovery window, eventual permanent purge, and the downstream visibility effects across four read surfaces. It also reinforces that unknown or already-trashed ids are refused rather than silently reported as deleted.
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 with no waste. The lifecycle consequence (soft delete, recoverable, then purged) is front-loaded, and the trash-inspection tip follows as supporting detail.
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 single-parameter mutation with no annotations and no output schema, the description supplies everything an agent needs: mutability model, reversibility window, postconditions, and where to verify state afterward.
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 the id parameter's description already documents UUID format plus the refusal behavior for unknown/already-trashed ids. The prose only adds 'by id', so the schema is doing the heavy lifting; baseline 3 is appropriate.
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 ('Soft-delete a note by id') and immediately disambiguates from hard deletion by naming the surfaces it disappears from (list_notes/search/get_note/the graph). An agent can distinguish it from delete_folder or a permanent purge without opening a 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?
Explicitly names the recovery alternative ('restore_note for 30 days') and the inspection alternative ('list_notes with trashed:true'), covering both when to use this tool and where to go next. No inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_backlinksA
Notes that link to this one via [[Title]] wikilinks, by id or title. Each comes back as id/title/folder_path plus a snippet around the link; include_content:true returns their full text instead, which is expensive when many notes link here — prefer get_note on the ids you actually want. offset and limit count notes, not characters.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | UUID of the note whose incoming links you want | |
| limit | No | Linking notes per page. Several links from the same note count as one | |
| title | No | Alternative to id; resolved like get_note (exact, then prefix, then substring) | |
| offset | No | Skip this many linking notes — pass back next_offset from the previous page | |
| include_content | No | Return each linking note's full text instead of a snippet around the link. Expensive when many notes link here |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the return shape (id/title/folder_path plus a snippet), the cost profile of include_content, and that pagination counts notes rather than characters. Missing are ordering guarantees and permission prerequisites, but the mutation-free nature is clear from the read verb.
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 dense sentences, front-loaded with the identity of the tool before the cost caveat and pagination note. Nothing is redundant, though the em-dash clause makes the second sentence long enough to slow scanning slightly.
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 five-parameter read tool with no output schema and no annotations, the description supplies what an agent actually needs: what comes back, what the expensive flag does, and how paging units behave. The schema already covers type and range constraints, so nothing critical is left 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 coverage is 100%, so the baseline is 3, but the description earns extra by clarifying that offset and limit count notes, not characters, and that include_content swaps snippets for full text. The id-vs-title alternative is restated with the actual resolution order being left to the schema, which is fine.
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 precise verb+resource: notes that link to this one via [[Title]] wikilinks, resolved by id or title. It is specific about the linking mechanism (wikilinks), which distinguishes it from a generic search. It never names the closest sibling, get_neighbors, so an agent must infer the boundary itself.
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 a concrete when-not plus an alternative: include_content:true is expensive when many notes link here, so prefer get_note on the ids you actually want. That is actionable routing guidance. It does not address when to use this versus get_neighbors or get_graph, which is the one remaining selection ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_graphA
Many notes at once and the edges between them — the heavy graph tool, and the only one that reaches for the whole vault. For one note's surroundings use get_neighbors; for who links to it, get_backlinks.
Nodes are {t} (t = title). Edges reference nodes BY POSITION in the nodes array: edges[0] = [2, 5] means nodes[2] links to nodes[5]. semantic_edges are undirected and come from embedding similarity rather than written links, with the cosine as a third number. unresolved_links are [[wikilink]] targets matching no note title — dangling, so they have no node index.
Unscoped this reaches for the ENTIRE vault and stops at max_nodes: truncated: true means you hold a recency-ordered prefix, NOT the shape of the vault. Scope with folder_id or root_title+depth rather than raising the cap.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | Hop count for root_title; ignored without it | |
| folder_id | No | Restrict to notes in this folder and its descendant folders | |
| max_nodes | No | Ceiling on nodes returned, most recently edited first. The reply says `truncated: true` when it applies — scope with folder_id or root_title instead of raising this | |
| min_score | No | Cosine floor for semantic_edges — lower to see more (noisier) edges | |
| root_title | No | Keep only nodes within `depth` wikilink-hops of this note — resolved like get_note: exact, then unique prefix, then unique substring, case-insensitive | |
| unresolved_only | No | If true, return only { unresolved_links } without nodes and edges (fast check for broken links) | |
| include_semantic | No | Include semantic_edges at all |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden, and it discloses the critical operational traits: the unscoped call hits the whole vault, hits max_nodes, and returns a recency-ordered prefix indicated by `truncated: true`, not the vault's true shape. It also describes edge positional indexing, semantic-edge direction and cosine source, and dangling unresolved links with no node index.
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 tool's identity and its sibling alternatives, then structured paragraphs for node/edge shape, semantic edges, unresolved links, and truncation behavior. Dense but 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?
With seven optional parameters, no annotations, and no output schema, the description compensates well: it documents the returned nodes, positional edge references, semantic edges with cosine values, unresolved_links, and the truncated flag. An agent has what it needs to scope the call and interpret the graph without surprises.
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%, so the baseline is 3; the description adds real value beyond it by explaining how root_title + depth scope the graph and by advising folder_id/root_title over raising max_nodes. It does not add much to min_score, include_semantic, or unresolved_only beyond what the schema already says.
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 ('Many notes at once and the edges between them') and immediately distinguishes itself from the sibling tools get_neighbors and get_backlinks, making selection unambiguous without opening a 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?
Explicitly names the alternatives and their conditions ('For one note's surroundings use get_neighbors; for who links to it, get_backlinks') and gives a scoping strategy (folder_id or root_title+depth) rather than raising the cap. When-to-use and how-to-scope guidance is complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_neighborsA
What is around ONE note in the [[wikilink]] graph, out to depth hops: a flat list of titles, no node indices to decode and no whole-vault payload. For the shape of that neighbourhood — which of them link to each other — use get_graph with root_title instead.
Traversal is undirected: a note linking HERE counts as much as one linked FROM here. links_out/links_in describe the direct relation and appear only at depth 1 — two hops out, "which way does the arrow point" has no answer. Each note appears once, at the shortest depth that reaches it.
These are links people wrote, not similarity: a note on the same subject that nobody linked is not here, and an empty result is a fact about the writing rather than about the topic. Rows carry the title, which is what get_note, get_backlinks and this tool all take.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | UUID of the note whose surroundings you want | |
| depth | No | Hops to walk. 1 = directly linked notes; each extra hop widens the set fast | |
| limit | No | Maximum neighbours to return, nearest depth first. `total` still counts them all | |
| title | No | Alternative to id; resolved like get_note (exact, then prefix, then substring) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden and does so: it discloses undirected traversal, deduplication at shortest depth, that links_out/links_in appear only at depth 1, that results are links people wrote rather than similarity, and that an empty result reflects the writing, not the topic. These are behavioral facts an agent cannot get from the 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?
Front-loaded with the one-line answer, then progressive detail in short paragraphs, and the sibling routing appears in the first sentence where it is most useful. It runs slightly long, with the closing paragraph's remark about the title convention being borderline expendable, but no sentence is 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?
With no output schema and no annotations, the description supplies exactly what's missing: return shape (flat list of titles), row content (title, usable by the other title-taking tools), dedup rule, and the meaning of an empty result. Nothing an agent needs to call this correctly is absent.
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%, so the baseline is 3, but the description adds real meaning beyond it: `depth` is characterized as undirected hops where direction becomes meaningless past depth 1, and `title` is framed as the shared identifier convention used by get_note, get_backlinks and here. It does not discuss `limit`/`total` interaction, which the schema already covers.
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?
Opens with a concrete verb+resource+scope: what is around ONE note in the [[wikilink]] graph, out to `depth` hops, returned as a flat title list. It also states what the tool is not ('no node indices to decode and no whole-vault payload') and names the sibling get_graph as the different capability. An agent can distinguish it from get_graph, get_backlinks and search_notes without opening a 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?
Explicitly routes the neighbour-shape case to get_graph with root_title, which is a real when-to-use/alternative rule. It also implies the depth-1 incoming-link case via the links_in remark, but never names get_backlinks as the cheaper alternative for pure backlink lookups, leaving one sibling comparison to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_noteA
Read one note, by id or title.
Long notes come back windowed — 20000 chars by default: check
content_truncatedand passnext_offsetback asoffsetfor the rest. A windowed reply carriesheadings— the H1–H3 outline with character offsets — so name one insectionto get that heading and its body alone instead of paging through the note.resolve_links:truealso returns the notes this one links to, id/title only unless you add include_content:true, whose text is capped at 4000 chars — call get_note on an id for the whole of one. Targets that match no note are listed as unresolved.Pass the
updated_atyou read back asexpected_updated_atwhen you write.content_updated_atis the one that moves only on a real edit to this note: a rename elsewhere rewriting a [[link]] inside it touchesupdated_atbut not that.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The note's UUID. Live notes only — a trashed note is not found until restore_note brings it back | |
| limit | No | Max characters of content to return | |
| title | No | Alternative to id: exact match first, then unique prefix, then unique substring. An ambiguous title comes back as the candidate list to retry with | |
| offset | No | Character offset into content to start from | |
| section | No | Return only this section (heading text or slug, case-insensitive) and its body | |
| resolve_links | No | Also resolve [[wikilinks]] inside the note one level deep | |
| include_content | No | With resolve_links: include full text of linked notes, not just id/title/folder_path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description still discloses non-obvious behavior: the 20000-character default window, content_truncated/next_offset paging, the headings outline, resolve_links depth and 4000-character cap, unresolved targets, and the distinction between updated_at and content_updated_at. It does not cover permissions or rate limits, but for a read tool this is strong behavioral context.
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?
The description is front-loaded with a one-line purpose and then uses focused bullets for pagination, sections, link resolution, and timestamps. It is dense but every bullet addresses behavior that affects invocation.
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?
There is no output schema, but the description explains the key return-control fields and truncation/link-resolution behavior. Some return-shape and error details are left to the schema or inference, so it is strong but not 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 description coverage is 100%, so the baseline is 3; the description adds useful relationships such as passing next_offset back as offset, using headings to choose section, and the include_content cap with resolve_links. It also references expected_updated_at, a write-side parameter not present in this schema, which is cross-tool context rather than local parameter documentation.
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 opening sentence gives a specific verb and resource ('Read one note') and restricts scope to id or title, clearly separating it from list_notes and search_notes. An agent can identify the tool's purpose without opening the 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?
It explains operational choices for paging versus section retrieval and for including linked-note content. However, it does not explicitly route between sibling retrieval tools such as search_notes or list_notes when the id or exact title is unknown.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
indexing_statusA
Semantic index progress: total/indexed/pending, complete=true when pending is 0. Pending notes are still found by text search; ones never embedded stay out of semantic results until the background pass reaches them.
Also names the active embedding model and the configured similarity cutoff (semantic_min_similarity, null when there is none — the default, meaning nothing is refused for being too dissimilar). Cosines are not comparable between models, which is why the model is named rather than left to be guessed from a score.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it explains that pending notes remain text-searchable but are excluded from semantic results until the background pass embeds them, and it clarifies the cutoff default and model-comparability caveat. It stops short of explicitly stating that the tool is read-only and has no side effects.
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?
The core status fields are front-loaded in the first sentence, followed by useful behavioral context. The second paragraph is dense but relevant; it could be tightened slightly, but every element contributes to interpreting the index state and cutoff.
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?
There is no output schema and no annotations, so the description must define what the tool returns. It covers progress counts, the complete flag, model identity, and the similarity cutoff with its null/default meaning, giving an agent enough to interpret the status correctly.
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?
The tool has zero parameters, so baseline is 4. The description appropriately focuses on output semantics rather than adding parameter meaning that does not exist.
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 precise resource and reporting scope: semantic index progress with total/indexed/pending counts, a complete flag, the active embedding model, and the configured similarity cutoff. It is clearly a status-reporting tool, distinct from the sibling CRUD, search, and graph tools.
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 tool is used to inspect indexing health and explains what pending entries mean for search behavior, but it never explicitly says when to call this versus alternatives or when not to call it. Usage is inferable from the name and content, but not directly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_foldersA
List folders with the full path already resolved — no need to walk parent_id yourself. Pass a folder's own id as parent_id to create_folder/update_folder to nest under it. Sorted by path, so a page is a contiguous slice of the tree read top to bottom; the reply is {folders, has_more, next_offset?}.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Folders per page | |
| offset | No | Skip this many folders — pass back next_offset from the previous page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose meaningful behavior: results are sorted by path so a page is a contiguous tree slice, and the reply shape is `{folders, has_more, next_offset?}`. It still omits permission/auth requirements and whether this covers all folders or a scoped subtree.
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 with zero filler: the resolved-path benefit is front-loaded, the create/update nesting trick follows, and the pagination contract closes it out. 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?
No output schema exists, and the description compensates by naming the exact response fields and the has_more/next_offset paging contract. Combined with the ordering guarantee, an agent can call and page through this correctly without further information.
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%, so the baseline is 3, but the description adds real semantics: sorting by path makes offset paging a stable contiguous slice, which explains why passing back next_offset is safe. That is value beyond the schema's mechanical 'Skip this many folders'.
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 folders') plus the key differentiator that the full path is already resolved, so the agent knows it needn't chase parent_id chains. It never names a sibling tool by comparison, but the resource split from list_notes/search_notes is unambiguous.
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 concrete cross-tool guidance: a folder's own id from this listing is what you pass as parent_id to create_folder/update_folder to nest. That tells the agent when this tool is a prerequisite for others; it stops short of explicit when-not-to-use or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_notesA
List notes newest first, filtered by folder, tag or date. This is the tool for "what is new" and "what changed lately": search_notes ranks by relevance and never by recency.
created_* is when a note was made, updated_* when its own text last changed — a rename elsewhere rewriting a [[link]] inside it does not count as an edit here. Each row carries content_length, so you can tell a long note from a short one before spending a get_note call. With trashed:true the other filters are ignored.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Filter by tag | |
| sort | No | Which date drives the ordering | updated |
| limit | No | Maximum notes to return per page. Applies in trashed mode too | |
| offset | No | Skip this many notes — pass back next_offset from the previous page | |
| trashed | No | List soft-deleted notes instead of live ones | |
| folder_id | No | Filter by folder UUID — that folder itself, not its subfolders | |
| folder_path | No | Same filter by path (e.g. "Projects/Kybase") instead of UUID — that folder itself, not its subfolders | |
| created_after | No | ISO timestamp — only notes created at or after this | |
| updated_after | No | ISO timestamp — only notes whose own content actually changed at or after this | |
| created_before | No | ISO timestamp — only notes created at or before this | |
| updated_before | No | ISO timestamp — only notes whose own content actually changed at or before this |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does well: it clarifies created_* versus updated_* semantics, including that link rewrites do not count as edits, and warns that trashed:true ignores other filters. It does not discuss pagination behavior or return shape beyond content_length, so it is strong but not exhaustive.
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?
It is front-loaded with the core behavior and sibling distinction, then adds only high-value clarifications about date semantics, content_length, and trashed mode. 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?
For an 11-parameter read tool with no annotations and no output schema, the description covers the essential selection, filtering, and semantic details. It is not fully complete on pagination or return shape, but the schema handles most parameter mechanics and the description handles the important ambiguities.
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 already 100%, so the baseline is 3. The description adds real meaning beyond schema text by explaining the distinction between created_* and updated_* timestamps and by noting that content_length helps decide whether to call get_note.
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 notes — plus ordering and filter scope. It explicitly distinguishes itself from search_notes by recency versus relevance, so an agent can choose it without opening the 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?
Explicitly says this is the tool for "what is new" and "what changed lately" and names search_notes as the alternative for relevance-ranked results. It also explains the practical value of content_length before spending a get_note call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tagsA
Tags in use with the number of notes carrying each, most-used first. The default limit cuts off the one-off tail — a tag used once is not one worth reusing — so raise it to see those.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max tags to return, most-used first |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and usefully discloses sort order, count inclusion, and default truncation behavior. It does not cover read-only status, permissions, or empty-result behavior, but the core behavioral traits for a simple list operation are present.
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 tightly written sentences, front-loaded with the core return behavior and followed by the relevant limit caveat. No wasted wording.
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 simple, one-parameter read tool with full schema coverage and no output schema, the description is complete enough: it explains what is returned, how it is ordered, and how the limit truncates results.
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%, so the parameter is already documented. The description adds semantic value by explaining the practical effect of the default limit: it cuts off the one-off tail, and raising it reveals those tags.
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 clearly states the resource (tags in use), the returned data (number of notes per tag), and the sort order (most-used first). It is distinguishable from sibling note/folder tools by resource, though it does not explicitly name an alternative.
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 useful guidance on when to raise the limit to see one-off tags, implying the default is for reusable tags. However, it does not explicitly state when to use this tool versus alternatives or provide exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
replace_in_noteA
Replace exact text in a note without resending the rest. Either find/replace or old_string/new_string — the same pair, either spelling.
For several replacements pass edits rather than the singular fields (one lock and one re-embed for the batch, not one per call); the two forms cannot be combined in one call. Edits apply in order, and each find is matched against the note as the edits before it already changed it — an earlier edit can create the text a later one needs, or destroy it, so sequence them. If any step's count is wrong the whole batch is refused and the note is left untouched, and the error names the failing index.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The note's UUID. Alternative to title | |
| find | No | Text to replace. Alias: old_string | |
| edits | No | Multiple find/replace steps applied in order in a single call — see main description. | |
| title | No | Alternative to id; resolved like get_note | |
| replace | No | Replacement text. Alias: new_string | |
| new_string | No | Alias for replace | |
| old_string | No | Alias for find | |
| expected_count | No | How many times `find` is expected to occur (default 1). The edit is refused if the real count differs, so a loose `find` cannot quietly rewrite more than intended | |
| expected_updated_at | No | ISO updated_at from when you read the note; refuses the write if it changed since |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses ordering semantics between edits, that earlier edits can create or destroy later match text, and atomic all-or-nothing failure with the failing index named in the error. It omits what a successful call returns and any permission/authorization expectations.
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 tight paragraphs, purpose and pairing rule front-loaded, batch guidance second. The parenthetical about lock/embed count is the only flourish and it earns its place by justifying the batch form.
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 9-parameter mutation tool with no annotations and no output schema, the key semantics (atomicity, ordering, count validation, form exclusivity) are covered. The main gap is that without an output schema the description never says what a successful call returns.
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%, so baseline is 3, but the description adds constraints not expressible in the schema — notably that `edits` and the singular fields cannot be combined, and that each `find` in a batch is evaluated against the progressively modified note. The alias equivalence it repeats is already in the schema descriptions.
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 ('Replace exact text in a note') and immediately scopes it against the obvious alternative behaviour ('without resending the rest'), which implicitly distinguishes it from update_note/append_to_note. An agent can tell what this does without opening the 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?
Explicit routing between the singular find/replace form and the batched `edits` form, including that the two cannot be combined, plus the efficiency rationale (one lock, one re-embed). It stops short of naming when to reach for this tool versus update_note or append_to_note.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_noteA
Undo delete_note: brings a soft-deleted note back. Errors if the note isn't in the trash (never deleted, already restored, or purged past the retention window), or if a live note has since taken the same title (rename one of them first, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | UUID of a note currently in the trash — the same id delete_note was given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses soft-delete semantics, a retention window past which restore fails, and a title-collision failure mode with a fix. It omits permissions/auth needs and what is returned on success, so it is strong but not exhaustive.
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, front-loaded with the inverse-of-delete framing, then a dense list of failure conditions and their fixes. Every clause 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?
Preconditions, error states, and remediation are covered thoroughly for a one-parameter mutation. The only gap is that with no output schema it leaves the success return value 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 coverage is 100% and the single id parameter is already documented as the trash UUID also passed to delete_note, so the schema does the heavy lifting. The description adds no format or constraint information about the id beyond that baseline.
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 ('Undo delete_note: brings a soft-deleted note back') and explicitly ties itself to the delete_note sibling, making the inverse relationship unmistakable among the many note tools.
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 'Undo delete_note' framing makes the when-to-use case clear, and it gives explicit remediation for the title-collision case ('rename one of them first, then retry'). It stops short of stating alternatives for notes that were never soft-deleted, though those are handled as error cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_notesA
Search notes: hybrid (keyword + meaning) by default. Returns ranked excerpts, not whole notes.
Use type="text" for an exact identifier, filename, code symbol or quoted phrase; "hybrid" for questions and topics.
READ THE SECTION, NOT THE NOTE. A hit's
sectionis the heading its excerpt came from — pass that string to get_note'ssectionto get that part alone. If a long hit has nosection, get_note with limit:1000 returns itsheadingsoutline; pick one and re-read withsection. For prose without headings, a hit'sexcerpt_offsetgoes to get_note asoffset.A hit is a candidate, not an answer.
relevanceis relative to the best hit in this response, so the top result always reads 1.0 — an ordering, not a verdict;best_scoreis that hit's own raw similarity.matched_bysays which arms found it: semantic_score alone means "about something similar", never that it confirms your question. Quote the excerpt or open the note — a score is never evidence.exact:truemeans the query occurs verbatim in that note;text_tierof "or" or "substring" means the strict words missed and a looser pass filled in — recall, not confirmation.A long note such as a book comes back as one hit with one excerpt. To find more places in it, search again with its
note_id: results are then places inside that note, best first.Dates here filter, they do not rank. For "what changed lately" use list_notes, which sorts by recency; it is also how you browse by folder or tag, since a query is required here.
has_morewithnext_offsetpages the results.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Restrict to notes with this tag | |
| type | No | "hybrid" fuses keyword and meaning-based matching and is the right default; "text" is keyword-only and exact; "semantic" is meaning-only | hybrid |
| limit | No | Hits per page. Prefer has_more with offset over asking for one large page | |
| query | Yes | What to look for: words or a question for hybrid/semantic, an exact identifier, path or phrase for type "text" | |
| offset | No | Skip this many hits — with has_more in the response, how you read past the first page | |
| rerank | No | Set false to skip the cross-encoder and answer from the fused order — several times faster, and not measurably worse. Applies to type "hybrid" only: text and semantic never rerank, and this flag changes nothing there | |
| explain | No | Include raw per-arm scores and created_at for debugging ranking | |
| note_id | No | Search inside this one note: results are places in it, best first, instead of one hit per note. Not combinable with folder, tag or date filters | |
| folder_id | No | Restrict to notes in this folder itself, not its subfolders | |
| folder_path | No | Same restriction by path (e.g. "Projects/Kybase") instead of UUID — that folder itself, not its subfolders | |
| created_after | No | ISO timestamp — only notes created at or after this | |
| updated_after | No | ISO timestamp — only notes whose own content actually changed at or after this | |
| created_before | No | ISO timestamp — only notes created at or before this | |
| updated_before | No | ISO timestamp — only notes whose own content actually changed at or before this |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does: it discloses that relevance is normalized to the top hit (always 1.0) and is an ordering not a verdict, what best_score/matched_by/exact/text_tier actually mean, that long notes collapse to one hit, that dates filter and do not rank, and that has_more/next_offset paginate. These are non-obvious failure modes an agent would otherwise misread as confirmation.
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 one-line definition and the mode rule, then organized into bullets that each address a distinct decision. It is dense and longer than most definitions, but nearly every clause prevents a concrete misuse; a small amount of the ranking-metric explanation could be tightened.
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 14 parameters, no annotations, and no output schema, the description compensates by documenting the response fields (relevance, best_score, matched_by, exact, text_tier, section, excerpt_offset, has_more) and the paging contract. An agent has everything needed to call it and interpret what comes back correctly.
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%, so the baseline is 3, but the description adds genuine interpretation beyond the schema: note_id turns results into places-inside-a-note and is not combinable with folder/tag/date filters, dates do not affect ranking, and section/offset are meant to be forwarded to get_note. Only gap is the naming drift between the schema's `offset` and the description's `next_offset`, which could momentarily confuse pagination.
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?
Opens with a specific verb+resource ("Search notes") and immediately states the default mode (hybrid) and the return shape ("ranked excerpts, not whole notes"). That return-shape statement alone distinguishes it from get_note (whole notes) and list_notes (browsing), so an agent can pick correctly without opening a 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?
Gives explicit mode-selection rules (text for identifiers/filenames/quoted phrases, hybrid for questions and topics) and an explicit alternative for a different need ("For 'what changed lately' use list_notes... it is also how you browse by folder or tag, since a query is required here"). It also prescribes a follow-up workflow (read the section, not the note; pass section/offset to get_note) rather than leaving it to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_folderA
Rename a folder and/or move it under a different parent (set parent_id to null for top level). Provide at least one of name/parent_id. The response includes the resolved path so a rename or move can be confirmed without a follow-up list_folders call.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | UUID of the folder to rename or move | |
| name | No | New name. Must stay unique among this folder's siblings | |
| parent_id | No | New parent folder UUID; null moves it to the top level. Moving a folder into its own descendant is refused |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry behavioral disclosure. It usefully says the response includes the resolved path for confirmation, but omits permissions, reversibility, effects on descendants, and broader error behavior; schema covers uniqueness and descendant-move refusal.
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 compact sentences: purpose first, input constraint second, response benefit third. No filler, and the important constraints are 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?
For a 3-parameter mutation tool with rich schema coverage but no annotations or output schema, the description covers purpose, minimum required inputs, null-parent semantics, and response confirmation. It still leaves permission and error-handling context 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 100%, so baseline is 3. The description adds a meaningful validation rule not expressible in the schema alone—provide at least one of name/parent_id—and reinforces null parent_id as top level.
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: rename and/or move a folder. This clearly distinguishes it from siblings like create_folder, delete_folder, and list_folders.
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?
Explains that at least one of name/parent_id must be provided and that null parent_id means top level, and notes avoiding a follow-up list_folders call. However, it does not explicitly say when to use this instead of sibling tools such as create_folder or delete_folder.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_noteA
Update note fields. Re-embeds if title or content changed. Updates wikilinks if title changed. The server instructions' wikilink and tag rules apply when substantially rewriting — in particular, call list_tags before coining a new tag. Pass expected_updated_at (the updated_at you read) to be refused instead of overwriting a change made in between.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The note's UUID. Live notes only; a note in the trash has to be restored before it can be edited | |
| tags | No | Replaces the entire tag list — anything left out is removed. To add one tag, send the existing tags plus the new one | |
| title | No | New title. Renaming rewrites every [[link]] pointing here in other notes | |
| content | No | Replaces the whole body. To add to a note use append_to_note, to change part of one use replace_in_note — both leave the rest untouched | |
| folder_id | No | Move the note to this folder; null moves it to the vault root. Omit to leave it where it is | |
| expected_updated_at | No | ISO updated_at from when you read the note; refuses the write if it changed since |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does a good job: it discloses re-embedding on title/content changes, wikilink updates on rename, and optimistic concurrency refusal via expected_updated_at. It does not mention permission requirements or explicitly warn that tags and content are replaced wholesale, though those details are in the 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?
The description is front-loaded and compact, covering purpose first and then side effects, tag rules, and concurrency guidance. Every sentence adds useful information 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?
For a six-parameter mutation tool with no annotations and no output schema, the description covers the key behavioral consequences and a critical concurrency safeguard. It relies on the rich schema for per-parameter replacement semantics, which is reasonable, though it could more explicitly warn about destructive replacement of content or tags.
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 100%, so the schema already documents all six parameters thoroughly. The description adds some context around expected_updated_at and title/content side effects, but most parameter meaning is already in the schema; baseline 3 is appropriate.
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 opens with a clear verb and resource: 'Update note fields.' It also clarifies important side effects, such as re-embedding and wikilink rewriting, but it does not explicitly distinguish this tool from append_to_note or replace_in_note in the description itself.
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 conditional guidance for tag creation and concurrency control, notably calling list_tags before coining a new tag and passing expected_updated_at to avoid overwrites. However, it does not state when to choose update_note over sibling tools like append_to_note, replace_in_note, or delete_note, leaving that inference to the schema.
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.
16 tool updates
v1.3.1- Changed
append_to_note5 fields changed- changed
Input schema / properties / at / descriptionPrevious value: -"Default section_end if section given, else note_end. note_start is after the H1/intro, before its first nested heading — not offset 0."New value: +"Where the text lands. Defaults to section_end when section is given, else note_end. note_end: the very end. note_start: above the first heading nested under the opening one — NOT offset 0, except on a note with no headings at all, where it is; on a note whose only heading is the opening one it falls to the end instead. before_section: above the section's own heading line. section_start: directly under that heading line, above the section's body. section_end: after the section and everything nested inside it. after_section: the same position as section_end. The four section-relative values require `section` and are refused without it." - added
Input schema / properties / content / descriptionAdded value: +"Text to add. Trailing whitespace is trimmed and a blank line is inserted before it, so the addition never runs into the preceding paragraph" - added
Input schema / properties / id / descriptionAdded value: +"The note's UUID. Alternative to title" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - changed
Input schema / properties / section / descriptionPrevious value: -"Target this section (heading text or slug) instead of the whole note"New value: +"Target this section (heading text or slug) instead of the whole note. Valid values come from a search hit's `section`, get_note's `headings`, or a heading line in the note's own text — the slug form is only needed when two headings share a text"
- Changed
create_folder3 fields changed- added
Input schema / properties / name / descriptionAdded value: +"Folder name. Unique among its siblings — the same name under a different parent is fine" - changed
Input schema / properties / parent_id / anyOfPrevious value: -[ - { - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / parent_id / descriptionAdded value: +"Parent folder UUID. Omit or pass null to create it at the top level"
- Changed
create_note5 fields changed- added
Input schema / properties / content / descriptionAdded value: +"Markdown body. Empty by default, so a note can be created first and filled with append_to_note" - changed
Input schema / properties / folder_id / anyOfPrevious value: -[ - { - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / folder_id / descriptionAdded value: +"Folder UUID. Omit or pass null for the vault root; use folder_path instead when you have the path rather than the id" - added
Input schema / properties / tags / descriptionAdded value: +"Tags for the new note: lowercase, kebab-case, in the language already in use. Call list_tags first and reuse an existing tag where one fits" - added
Input schema / properties / title / descriptionAdded value: +"Unique across live notes, case-insensitively; a clash is refused rather than merged. This is the string other notes link to as [[Title]]"
- Changed
delete_folder2 fields changed- added
Input schema / properties / id / descriptionAdded value: +"UUID of the folder to delete along with its subfolders. Notes inside are moved to the trash, not destroyed" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
- Changed
delete_note2 fields changed- added
Input schema / properties / id / descriptionAdded value: +"The note's UUID. An unknown or already-trashed id is refused rather than reported as deleted" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
- Changed
get_backlinks7 fields changed- added
Input schema / anyOfAdded value: +[ + { + "required": [ + "id" + ] + }, + { + "required": [ + "title" + ] + } +] - added
Input schema / properties / id / descriptionAdded value: +"UUID of the note whose incoming links you want" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / include_content / descriptionAdded value: +"Return each linking note's full text instead of a snippet around the link. Expensive when many notes link here" - added
Input schema / properties / limit / descriptionAdded value: +"Linking notes per page. Several links from the same note count as one" - added
Input schema / properties / offset / descriptionAdded value: +"Skip this many linking notes — pass back next_offset from the previous page" - added
Input schema / properties / title / descriptionAdded value: +"Alternative to id; resolved like get_note (exact, then prefix, then substring)"
- Changed
get_graph3 fields changed- removed
Input schema / properties / folder_id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / max_nodesAdded value: +{ + "default": 500, + "description": "Ceiling on nodes returned, most recently edited first. The reply says `truncated: true` when it applies — scope with folder_id or root_title instead of raising this", + "maximum": 5000, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / root_title / descriptionPrevious value: -"Keep only nodes within `depth` wikilink-hops of this note (case-insensitive)"New value: +"Keep only nodes within `depth` wikilink-hops of this note — resolved like get_note: exact, then unique prefix, then unique substring, case-insensitive"
- Changed
get_neighbors5 fields changed- added
Input schema / anyOfAdded value: +[ + { + "required": [ + "id" + ] + }, + { + "required": [ + "title" + ] + } +] - added
Input schema / properties / id / descriptionAdded value: +"UUID of the note whose surroundings you want" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / limitAdded value: +{ + "default": 100, + "description": "Maximum neighbours to return, nearest depth first. `total` still counts them all", + "maximum": 500, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / title / descriptionAdded value: +"Alternative to id; resolved like get_note (exact, then prefix, then substring)"
- Changed
get_note4 fields changed- added
Input schema / anyOfAdded value: +[ + { + "required": [ + "id" + ] + }, + { + "required": [ + "title" + ] + } +] - added
Input schema / properties / id / descriptionAdded value: +"The note's UUID. Live notes only — a trashed note is not found until restore_note brings it back" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / title / descriptionAdded value: +"Alternative to id: exact match first, then unique prefix, then unique substring. An ambiguous title comes back as the candidate list to retry with"
- Changed
list_folders2 fields changed- added
Input schema / properties / limitAdded value: +{ + "default": 200, + "description": "Folders per page", + "maximum": 1000, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "Skip this many folders — pass back next_offset from the previous page", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +}
- Changed
list_notes5 fields changed- changed
Input schema / properties / folder_id / descriptionPrevious value: -"Filter by folder UUID"New value: +"Filter by folder UUID — that folder itself, not its subfolders" - removed
Input schema / properties / folder_id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / folder_pathAdded value: +{ + "description": "Same filter by path (e.g. \"Projects/Kybase\") instead of UUID — that folder itself, not its subfolders", + "type": "string" +} - added
Input schema / properties / limit / descriptionAdded value: +"Maximum notes to return per page. Applies in trashed mode too" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "Skip this many notes — pass back next_offset from the previous page", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +}
- Changed
replace_in_note4 fields changed- added
Input schema / allOfAdded value: +[ + { + "anyOf": [ + { + "required": [ + "id" + ] + }, + { + "required": [ + "title" + ] + } + ] + }, + { + "anyOf": [ + { + "required": [ + "edits" + ] + }, + { + "required": [ + "find" + ] + }, + { + "required": [ + "old_string" + ] + } + ] + } +] - added
Input schema / properties / expected_count / descriptionAdded value: +"How many times `find` is expected to occur (default 1). The edit is refused if the real count differs, so a loose `find` cannot quietly rewrite more than intended" - added
Input schema / properties / id / descriptionAdded value: +"The note's UUID. Alternative to title" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
- Changed
restore_note2 fields changed- added
Input schema / properties / id / descriptionAdded value: +"UUID of a note currently in the trash — the same id delete_note was given" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
- Changed
search_notes7 fields changed- changed
Input schema / properties / folder_id / descriptionPrevious value: -"Restrict to notes in this folder"New value: +"Restrict to notes in this folder itself, not its subfolders" - removed
Input schema / properties / folder_id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / limit / descriptionAdded value: +"Hits per page. Prefer has_more with offset over asking for one large page" - added
Input schema / properties / note_idAdded value: +{ + "description": "Search inside this one note: results are places in it, best first, instead of one hit per note. Not combinable with folder, tag or date filters", + "format": "uuid", + "type": "string" +} - added
Input schema / properties / query / descriptionAdded value: +"What to look for: words or a question for hybrid/semantic, an exact identifier, path or phrase for type \"text\"" - changed
Input schema / properties / rerank / descriptionPrevious value: -"Set false to skip the cross-encoder and answer from the fused order — several times faster, and not measurably worse"New value: +"Set false to skip the cross-encoder and answer from the fused order — several times faster, and not measurably worse. Applies to type \"hybrid\" only: text and semantic never rerank, and this flag changes nothing there" - added
Input schema / properties / type / descriptionAdded value: +"\"hybrid\" fuses keyword and meaning-based matching and is the right default; \"text\" is keyword-only and exact; \"semantic\" is meaning-only"
- Changed
update_folder5 fields changed- added
Input schema / properties / id / descriptionAdded value: +"UUID of the folder to rename or move" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / name / descriptionAdded value: +"New name. Must stay unique among this folder's siblings" - changed
Input schema / properties / parent_id / anyOfPrevious value: -[ - { - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / parent_id / descriptionAdded value: +"New parent folder UUID; null moves it to the top level. Moving a folder into its own descendant is refused"
- Changed
update_note7 fields changed- added
Input schema / properties / content / descriptionAdded value: +"Replaces the whole body. To add to a note use append_to_note, to change part of one use replace_in_note — both leave the rest untouched" - changed
Input schema / properties / folder_id / anyOfPrevious value: -[ - { - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / folder_id / descriptionAdded value: +"Move the note to this folder; null moves it to the vault root. Omit to leave it where it is" - added
Input schema / properties / id / descriptionAdded value: +"The note's UUID. Live notes only; a note in the trash has to be restored before it can be edited" - removed
Input schema / properties / id / patternRemoved value: -"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - added
Input schema / properties / tags / descriptionAdded value: +"Replaces the entire tag list — anything left out is removed. To add one tag, send the existing tags plus the new one" - added
Input schema / properties / title / descriptionAdded value: +"New title. Renaming rewrites every [[link]] pointing here in other notes"
18 tool updates
v1.3.0- First observed
append_to_note - First observed
create_folder - First observed
create_note - First observed
delete_folder - First observed
delete_note - First observed
get_backlinks - First observed
get_graph - First observed
get_neighbors - First observed
get_note - First observed
indexing_status - First observed
list_folders - First observed
list_notes - First observed
list_tags - First observed
replace_in_note - First observed
restore_note - First observed
search_notes - First observed
update_folder - First observed
update_note
TDQS
Scored across 18 tools
Each tool targets a distinct verb+resource, and the descriptions actively route between the close pairs (list_notes vs search_notes, append_to_note vs update_note vs replace_in_note, get_backlinks vs get_neighbors vs get_graph). No two tools appear to do the same thing, and the explicit 'use X instead of Y' guidance removes the residual overlap.
Nearly everything is a clean verb_noun pattern (create_note, list_folders, get_backlinks, restore_note), with consistent pluralization for collections. The one outlier is indexing_status, which is a noun phrase with no verb prefix and breaks the pattern.
18 tools is on the heavier side but each maps to a real operation in a notes+folders+graph domain; nothing feels like filler. A slightly tighter surface (e.g. folding indexing_status into a broader status call) would make it ideal.
Note lifecycle is fully covered (create/read/list/update/append/replace/soft-delete/restore, search, backlinks, graph), and folders have full CRUD with cascade delete. Minor gaps remain: no tag management beyond list_tags (no rename/merge/delete of tags), no permanent purge, and no dedicated trash-listing tool (deferred to list_notes trashed:true).
Maintenance
Related MCP Connectors
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Self-hosted AI workspace: semantic RAG document search, long-term memory, and AI chat via MCP.
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
A second brain for your AI agent. Shared memory for your team's AI agents, plus public and private knowledge bases — works with ChatGPT, Claude, Cursor and any MCP client.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceA self-hosted Markdown knowledge base and Agent Harness with an MCP server that enables AI agents to read and write notes, providing persistent memory and a shared workspace for multi-agent collaboration.2MIT
- AlicenseNot gradedqualityFmaintenanceA self-hosted persistent memory platform for AI agents and humans offering tools for memory storage, search, beliefs, work management, and code intelligence via MCP.7GPL 3.0
- AlicenseNot gradedqualityDmaintenanceSelf-hosted personal knowledge base with semantic search, enabling AI agents to capture, search, and manage thoughts using PostgreSQL with pgvector.7 npmISC
- AlicenseNot gradedqualityCmaintenanceSelf-hosted, local-first knowledge graph and memory server for AI agents. Enables agents to persist, recall, and organize knowledge through MCP with automatic distillation, deduplication, and cross-linking.MIT