Skip to main content
Glama

Kybase is self-hosted, long-term memory for AI agents. Any MCP-speaking agent — Claude, Cursor, Windsurf — can search, read, and update a persistent Markdown knowledge base through MCP, while you keep full control in the browser: read every note, edit anything, revoke access anytime. Hybrid search finds the right note, section-level reads avoid loading entire documents into context, and [[wikilinks]] keep the knowledge connected as it grows.

PostgreSQL + pgvector + Ollama, one docker compose up. No SaaS, no accounts, private by default — cloud embeddings (Google, OpenAI) are optional, not required (see Switching Embedding Providers for the trade-off).

Why Kybase? · How agents use it · Quick Start · Environment variables · Connect an MCP Client · Stack · Switching Embedding Providers · Export & Import · Sharing · Backups · Upgrading · Local development · More documentation · License

Why Kybase?

Giving an agent persistent memory usually means assembling it yourself: a notes app, an MCP bridge, an embedding pipeline, and sync between them. Kybase is that whole stack as one docker compose up:

  • Markdown, not an opaque memory blob — every note is a plain .md file with frontmatter; read it, edit it, grep it, back it up with cp

  • MCP-native reads and writes — an agent searches, reads, and updates notes directly through MCP tools, not through a side-channel it can't use

  • Hybrid search — full-text and semantic search fused into one ranked result, so an agent finds the right 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 actually needs, not the whole file

  • Backlinks and a knowledge graph[[wikilinks]] connect related notes automatically; explicit and semantic edges are both visible in the graph view

  • Self-hosted, private by default — your own Postgres, your own Ollama; nothing leaves your machine unless you opt into a cloud embedding provider

Related MCP server: Cairn MCP Server

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 returns which section of a note matched, not just which note. For a long note, reading one section instead of the whole file can mean reading a fraction of the content — cheaper for every step after the first search, and it's how the agent writes back too.

Quick Start (Docker)

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 -d

That generates both required secrets in place (the sed -i.bak form works on both Linux and macOS) — nothing else in .env needs to change to get started.

This pulls the prebuilt multi-arch image (ghcr.io/kyrzin/kybase, linux/amd64 + linux/arm64) from GitHub Packages, tagged latest. To build from source instead, run docker compose up -d --build.

Open http://localhost:3000 and log in with your KYBASE_SECRET — then jump to Connect an MCP Client to point an agent at it.

That's it. On startup the app applies db/migrations/*.sql automatically (tracked in the schema_migrations table) and Ollama downloads the embedding model (embeddinggemma, ~620 MB, one time). Change the host port with KYBASE_PORT in .env.

NOTE

Notes and text search work immediately. Semantic search and semantic graph edges activate once Ollama finishes pulling the model and notes get indexed (automatic, in the background).

Environment variables

Everything below goes in .env (copied from .env.example). KYBASE_SECRET and POSTGRES_PASSWORD are required — the rest have working defaults.

Variable

Default

Notes

KYBASE_SECRET

(required)

UI login password and MCP/API bearer token. Generate with openssl rand -hex 32.

KYBASE_OAUTH_REDIRECT_URIS

claude.ai's connector callback

Comma-separated extra OAuth redirect_uri values, matched in full — give the whole URL, not just a host. Loopback addresses are always allowed. Only relevant if an MCP client does its own hosted OAuth instead of a static Bearer token.

KYBASE_PORT

3000

Host port the app is exposed on.

POSTGRES_PASSWORD

(required)

Postgres is only reachable inside the compose network, but docker compose up refuses to start without one — no silent weak default. Generate with openssl rand -hex 16.

KYBASE_TAG

latest

Prebuilt image tag from ghcr.io/kyrzin/kybase. latest always tracks the newest release tag; pin to a specific version (e.g. v1.3.0) if you want upgrades to be a deliberate step.

EMBEDDING_PROVIDER

ollama

ollama, google, or openai — see Switching Embedding Providers.

OLLAMA_URL

http://ollama:11434

Point at an external Ollama instance instead of the bundled container.

OLLAMA_MODEL

embeddinggemma

Or nomic-embed-text.

GOOGLE_API_KEY / GOOGLE_MODEL

(empty) / text-embedding-004

Only used when EMBEDDING_PROVIDER=google.

OPENAI_API_KEY

(empty)

Only used when EMBEDDING_PROVIDER=openai.

DATABASE_URL isn't something you set for the Docker path — compose derives it from POSTGRES_PASSWORD automatically. It's only relevant for local development running the app directly on the host.

Connect an MCP Client

The app exposes a Streamable HTTP MCP endpoint at /api/mcp. Any MCP client that speaks Streamable HTTP can connect — not just Claude. Clients that only speak stdio have a local entrypoint instead.

Claude Code — add to .mcp.json (or claude mcp add):

{
  "mcpServers": {
    "kybase": {
      "type": "http",
      "url": "https://your-domain/api/mcp",
      "headers": {
        "Authorization": "Bearer <KYBASE_SECRET>"
      }
    }
  }
}

Claude Desktop — same JSON shape, in claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json).

claude.ai — Settings → Connectors → Add custom connector, same URL (requires the instance to be reachable over HTTPS). No key to paste: the connector registers itself (RFC 7591), sends you to your own instance to enter the key once, and gets its own revocable OAuth token — see Settings → Connected clients in the web UI. A connector can only be sent back to a callback this server accepts, so registration cannot point one somewhere else.

Cursor — add to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "kybase": {
      "url": "https://your-domain/api/mcp",
      "headers": {
        "Authorization": "Bearer <KYBASE_SECRET>"
      }
    }
  }
}

Windsurf — add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "kybase": {
      "serverUrl": "https://your-domain/api/mcp",
      "headers": {
        "Authorization": "Bearer <KYBASE_SECRET>"
      }
    }
  }
}

stdio (local process) — for clients that can't speak HTTP, run the server as a child process against the database directly. Needs a checkout and the same DATABASE_URL the app uses; there is no bearer token, since access is whatever the process itself can reach.

{
  "mcpServers": {
    "kybase": {
      "command": "npx",
      "args": ["tsx", "scripts/mcp-stdio.ts"],
      "cwd": "/path/to/kybase",
      "env": {
        "DATABASE_URL": "postgres://kybase:kybase@localhost:5432/kybase"
      }
    }
  }
}

Or npm run mcp:stdio from the checkout. The HTTP endpoint is the better choice whenever it's an option — it's the one with authentication, revocable tokens, and no local checkout to keep in sync.

MCP tools (18)

Tool

Category

What it does for the agent

search_notes

Search

Hybrid RRF search (pgvector + bilingual FTS); exact flags a literal substring match, matched_by shows which arms found it, section names which part of a long note matched

get_note

Read

Fetch a note by id or fuzzy title; windowed for large notes, with a heading outline. resolve_links:true also resolves every [[wikilink]] inside it, one level deep, in the same round-trip

list_notes

Read

Newest-first listing, filterable by folder/tag/updated date

list_tags

Read

All tags in use with counts, so the agent reuses existing tags instead of coining duplicates

list_folders

Read

Flat folder list for reconstructing the tree

get_backlinks

Graph

Notes that link to a given note via [[wikilinks]]

get_neighbors

Graph

What one note is connected to in the [[wikilink]] graph, out to depth hops — a flat list of titles, no whole-vault payload

get_graph

Graph

The knowledge graph — wikilink edges plus semantic edges — scoped by folder or by hop count from a root note

create_note

Write

Create a note; embedding is generated automatically in the background

update_note

Write

Update fields; supports expected_updated_at to refuse a stale overwrite instead of silently clobbering a concurrent edit

append_to_note

Write

Insert text at a note/section boundary (at: note/section start or end) without resending the rest — safe under concurrent writers (row-locked)

replace_in_note

Write

Find-and-replace exact text; refuses unless the match count equals expected_count, so a loose find can't silently rewrite more than intended

delete_note

Write

Soft-delete; recoverable with restore_note before it ages out of the trash

restore_note

Write

Undo delete_note

create_folder

Organize

Create a folder, optionally nested

update_folder

Organize

Rename or move a folder; refuses a move that would create a cycle

delete_folder

Organize

Delete a folder and its subtree; every note inside is soft-deleted along with it

indexing_status

Diagnostics

How many notes are embedded vs. still pending, to tell "still indexing" from "done"

The server ships with MCP instructions that teach the agent to search before writing and to add [[wikilinks]] to related notes — so the knowledge graph grows as the agent uses it, instead of accumulating orphan notes.

How search works, in plain terms. search_notes has three modes: text (exact words, filenames, identifiers), semantic (meaning, via embeddings), and hybrid (both, fused into one ranked list — the default, and usually the right choice). A few fields on each hit mean something narrower than they sound:

  • exact: true means the query is a literal, contiguous substring of the note — good for finding a specific compound identifier or filename, not a signal that "this is the right answer."

  • relevance ranks hits within this one response, relative to its own best hit — it's not a confidence score or a probability.

  • A hit found only by the semantic arm means "similar topic," not "confirms this fact." Read the excerpt before trusting it.

  • coverage measures how much of the query is literally present in a hit — a low or zero value doesn't mean the hit is wrong, since a cross-language or paraphrased match can legitimately share no words with the question.

  • Semantic search returns candidates by default, not verdicts — nothing is filtered out for being "too dissimilar" unless you configure a minimum similarity yourself (see Switching Embedding Providers); an empty result means the index found nothing at all.

When a hit's section is set, get_note(section:) reads just that part instead of the whole note.

Stack

Layer

Tech

Frontend

Next.js App Router, React 19

Database

PostgreSQL 16 + pgvector (direct pg connection)

Embeddings

Ollama embeddinggemma (default, multilingual) / Google / OpenAI

Search

RRF hybrid: pgvector HNSW cosine + bilingual FTS

MCP

@modelcontextprotocol/sdk Streamable HTTP

Auth

KYBASE_SECRET env var + revocable per-client OAuth tokens (MCP)


Switching Embedding Providers

You can switch the embedding provider (between local Ollama, Google, or OpenAI) and trigger re-indexing directly in the browser:

  1. Open the settings modal in the web UI.

  2. Select your provider, add the API key if needed, and click Save & Apply (switching the provider automatically re-indexes every note).

  3. Reindex only catches notes that were never embedded. After anything else that changes how embeddings are computed (e.g. an update to the embedding logic itself), use Reindex all to force-recompute every note.

All supported providers use 768-dimensional embeddings, so switching does not require any database schema changes.

IMPORTANT

Ollama keeps everything on your machine — no note content leaves it. Google and OpenAI are convenience options: picking either sends your notes' full text to that provider's API to compute the embedding.

Local model choice. The default local model is embeddinggemma (multilingual) — for multilingual vaults (e.g. Russian/German) it separates relevant from irrelevant notes far better than English-centric models. nomic-embed-text is a smaller, English-leaning alternative.

Semantic search returns candidates, not verdicts. Kybase does not reject a semantic match for being "too dissimilar" — there is no built-in similarity cutoff, and an empty result means the index found nothing, not that something was filtered out. That is deliberate: a shipped per-model cutoff was measured and withdrawn, because it removed real answers (a cross-language match shares no words, so nothing else finds it) without reliably stopping confident near-misses. Each hit instead carries what you need to judge it — which arm found it, how much of your query literally appears in it, and the matching excerpt.

If you have a homogeneous corpus and have measured your own model, you can set a minimum similarity as precision tuning; indexing_status reports whether one is in force. See lib/embeddings.ts for the measurements and the reasoning.

TIP

Already run Ollama? On a host that already has an Ollama instance (e.g. a GPU one), skip the bundled CPU container: set OLLAMA_URL in .env to your instance (pull OLLAMA_MODEL there first) and start with the override file — docker compose -f docker-compose.yml -f docker-compose.external-ollama.yml up -d.

TIP

CLI alternative. If you prefer using the terminal, you can trigger re-indexing by calling the admin endpoint — only pending notes by default, add ?mode=all to the URL to force every note instead:

docker compose exec kybase node -e "
  fetch('http://localhost:3000/api/admin/reindex', {
    method: 'POST',
    headers: { Authorization: 'Bearer <KYBASE_SECRET>' }
  }).then(r => r.json()).then(console.log)
"

Export & Import

Your notes are never locked in. Settings → Export .zip downloads the whole vault as plain markdown files with frontmatter (title, tags, created/ updated dates), folders as directories — readable by any editor, Obsidian included. Import .zip merges a vault back; notes whose titles already exist are skipped. A new note's creation date is restored from the file; its "last updated" timestamp is set to the moment it lands back in the vault rather than carried over — that field tracks when this server last changed the row, so a re-imported note showing up as recently touched is correct, not a bug. Imported notes are re-embedded automatically in the background.

The same via API:

curl -H "Authorization: Bearer <KYBASE_SECRET>" -o vault.zip \
  http://localhost:3000/api/export

# mode=skip (default) keeps existing notes; mode=overwrite replaces them
curl -X POST -H "Authorization: Bearer <KYBASE_SECRET>" \
  --data-binary @vault.zip \
  "http://localhost:3000/api/import?mode=skip"

Sharing notes

The Share button on a note creates a public read-only link (/share/<token>) — rendered markdown, no login, wikilinks shown as plain text so nothing else in your vault is reachable. The threat model in one sentence: the link is the access — revoke links you no longer need (Settings → Active share links shows everything that is currently public).


Backups

Everything lives in one Postgres volume — 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 --build

Migrations apply automatically on startup. Details: docs/upgrading.md.


Local development

# Postgres only (app runs on the host)
docker compose up -d db
cp .env.example .env.local
# in .env.local: set KYBASE_SECRET and uncomment DATABASE_URL
npm install
npm run dev                  # http://localhost:3000

npm run build     # Production build check
npx tsc --noEmit  # Type check

More documentation

SECURITY.md (threat model, what's implemented) · CONTRIBUTING.md · docs/backup.md · docs/upgrading.md


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 tools
append_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. Re-embeds in the background like any content change.

ParametersJSON Schema
NameRequiredDescriptionDefault
atNoDefault section_end if section given, else note_end. note_start is after the H1/intro, before its first nested heading — not offset 0.
idNo
titleNoAlternative to id; resolved like get_note
contentYes
sectionNoTarget this section (heading text or slug) instead of the whole note

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full disclosure burden and meets it: it explains the no-resend behavior, the inserted blank-line separator, and the background re-embed side effect. These are concrete behavioral traits beyond what the schema states.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences cover purpose, preference over an alternative, formatting behavior, and side effects. No repetition of schema details and no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description plus schema covers the main decision (append vs update), target resolution (id/title/section), placement semantics (at), and the side-effect profile. It does not describe return values or error conditions, but for a no-output-schema append operation that gap is minor. Overall 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.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 60% and the tool description adds no direct parameter semantics beyond referring generally to 'your text'. The schema already documents at, title, section and content constraints, so the description provides no extra parameter-level value. Baseline 3 is appropriate given partial schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Add text to a note without resending the rest,' a specific verb-resource pair, and explicitly contrasts it with update_note. This makes the tool's scope unambiguous and distinguishes it from sibling mutation tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to prefer this tool over update_note for journals, logs and running lists, naming both the alternative and the usage context. This is direct when-to-use guidance the agent does not have to infer.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
parent_idNo

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden. It discloses a create mutation and optional nesting, but it does not state important behaviors such as idempotency (what if a folder with the same name exists), required parent existence, permissions, or what happens on failure/success. The only added note about optional nesting is already derivable from the schema (parent_id non-required), so it adds little beyond the structured data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely lean: two sentences, four main pieces of information, no redundancy. The purpose is front-loaded ('Create a new folder') and the only nuance (optional nesting) follows directly. Every word earns its place, and the structure is ideal for a search model.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although the operation is relatively simple, the description is not complete enough for correct invocation. It doesn't mention the existence of a parent (e.g., that parent must already exist) or the output/return value (no output schema). An agent cannot tell from this description what success looks like or whether there are preconditions, side effects, or uniqueness constraints—important gaps for a create operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, so the tool description must compensate for the undefined parameter semantics. It does add the note that the folder may be nested under a parent, clarifying the parent_id purpose, but it does not describe the name parameter beyond its existence or any constraints. It fails to explain that 'parent' means a folder ID, the expected naming conventions, or how nested paths work, leaving the agent to infer too much.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a verb and resource: 'Create a new folder.' It also adds a key scoping nuance, 'Optionally nested under a parent,' which distinguishes it from sibling tools like update_folder, delete_folder, and create_note without needing to inspect those schemas. The resource and action are unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers no guidance on when to use this tool vs alternatives. It does not mention any exclusions, prerequisites, or competing tools, leaving the agent to infer solely from the tool name. Without context such as 'Use this when you need to create a folder and not when...' the selection criteria are absent.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNo
titleYes
contentNo
folder_idNo
folder_pathNoFolder path (e.g. "Projects/Kybase") as alternative to folder_id

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of behavioral disclosure. It usefully reveals that embedding is generated automatically in the background and that server-side wikilink/tag rules apply. It does not mention what the tool returns, whether creation is synchronous, or failure behavior, leaving some operational gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler: purpose first, then a noteworthy behavioral detail, then the required server rules. Every clause earns its place and the most important instruction is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The definition covers the core action, background embedding, and required pre-steps, which is sufficient for basic usage. However, with no annotations and no output schema, it leaves return value, embedding completion status, and folder selection guidance largely unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20%, so the description must compensate. It adds meaningful semantics for the tags parameter by requiring verification against list_tags before coining new tags. It does not clarify title, content, folder_id, or the relationship between folder_id and folder_path beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Create a new note,' which clearly states the verb and resource. It does not explicitly distinguish itself from siblings like append_to_note or update_note, though the create semantic makes the primary intent unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit pre-use workflow instructions: search_notes first, link related notes, and call list_tags before introducing a new tag. However, it does not state when to prefer an alternative such as update_note or append_to_note, so it lacks explicit exclusions.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Since no annotations are provided, the description carries the full burden. It explicitly discloses that the operation is destructive (cascade delete), that notes are soft-deleted (recoverable), the recovery context (restore_note, retention window), and that the action is irreversible in the sense of losing folder structure unless moved first. It also notes the side effect of moving content. This is strong for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, front-loaded with the primary effect (cascade delete), then explains consequences and provides an alternative. No redundancy, every sentence adds value. It is appropriately structured for a destructive operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive tool with no output schema, the description covers the key aspects: cascade deletion, soft-delete behavior, recovery, and an alternative. It could also mention if there are any permission requirements or if the operation fails for non-existent folders, but these are likely self-explanatory. Overall, it is complete enough for the agent to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides the parameter 'id' with format UUID and pattern, but no description. The tool's description doesn't directly describe the parameter, but it implicitly indicates that 'id' identifies the folder to delete. Since the schema coverage is 0% and there is only one parameter, the description's context is enough to infer. However, it doesn't explicitly say 'the id is the folder identifier', but that is obvious from context. Given the single param, score 4 is fair.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool deletes a folder and its full subtree, and distinguishes cascading behavior from a single item deletion. It names the sibling delete_note and contrasts with delete_note, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains the cascade behavior and its implications for notes in subfolders, and gives an alternative approach (move items out) to preserve organization. However, it does not explicitly say when NOT to use it (e.g., if you want to keep any content), but the alternative is clear.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes

TDQS

A4.4/5.0
Behavior5/5

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 so very well. It discloses that the operation is a soft delete, what views are affected, that the note is recoverable for 30 days, and that it is eventually purged. This far exceeds a generic 'deletes a note' description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences front-load the primary behavior and then provide the most relevant recovery and inspection guidance. Every clause adds useful information and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter operation with no output schema, the description is complete: it explains the immediate effect, the recovery window, the eventual purge, and how to view trashed notes. No critical calling context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description only says 'by id', which adds little beyond the schema's property name for the id parameter. Since schema description coverage is 0%, the description should compensate, but it does not explain valid IDs, behavior for missing IDs, or idempotency. The schema itself defines UUID format, but the description adds no meaning beyond that.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states that this tool soft-deletes a note by id and describes the exact effect: the note disappears from list_notes, search, get_note, and the graph. This distinguishes it from related tools like restore_note and delete_folder.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains that the delete is recoverable and points to restore_note as the recovery path, and instructs agents to use list_notes with trashed:true to inspect the trash. It provides clear context for when to use the tool, though it does not explicitly exclude cases like permanently deleting or deleting folders.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_graphA

Get the knowledge graph: note nodes, directed edges from [[wikilinks]], and undirected semantic_edges (embedding cosine similarity) between related notes that may lack explicit links. Nodes are {id, t} (t = title); edges and semantic_edges reference nodes by their position in the nodes array (not id) — ["edges"][0] = [2, 5] means nodes[2] links to nodes[5], and a semantic_edges triple's third number is the cosine score. unresolved_links lists [[wikilink]] targets in this scope that match no note title — dangling links, not edges (no node index, since there is no node to point at); rename the target or fix the link text to resolve one. Unfiltered, this returns the ENTIRE vault in one response — fine for small vaults, but it will stop fitting in context as the vault grows. Scope it with folder_id (a subtree) or root_title+depth (the neighborhood around one note) when you only need part of the graph. Node titles in the result are valid [[wikilink]] targets — but only within whatever scope you asked for.

ParametersJSON Schema
NameRequiredDescriptionDefault
depthNoHop count for root_title; ignored without it
folder_idNoRestrict to notes in this folder and its descendant folders
min_scoreNoCosine floor for semantic_edges — lower to see more (noisier) edges
root_titleNoKeep only nodes within `depth` wikilink-hops of this note (case-insensitive)
unresolved_onlyNoIf true, return only { unresolved_links } without nodes and edges (fast check for broken links)
include_semanticNoInclude semantic_edges at all

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It details the return format thoroughly, explains that semantic_edges are based on cosine similarity, and clarifies that unresolved_links are not edges but dangling references. The warning about the unfiltered response potentially not fitting in context is a valuable behavioral trait. It doesn't explicitly state read-only behavior, but given the focus on retrieval and the lack of any mutation verbs, it's implicitly safe.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and information-rich, but it is slightly long, covering multiple aspects such as structure, semantics, and usage warnings. It front-loads the core purpose and structural details, which is effective, but the later part about node titles being valid wikilink targets adds context that might be less critical. Overall, it is efficient without being verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (multiple edge types, indexing conventions, and scoping options), the description covers most essential details: node format, edge indexing, semantic edge threshold, unresolved links, and scoping recommendations. It lacks some information like whether depth is inclusive or exclusive, but that is handled by the schema. The warning about context limits is crucial for an agent. No output schema exists, so the description must cover return format, which it does thoroughly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% description coverage for all six parameters, including their purpose and constraints. The description adds context by explaining how these parameters affect the graph structure (e.g., depth for hop count, min_score for semantic edge threshold) and how nodes reference each other. However, this is marginal value beyond the schema; the description could have delved deeper into parameter interactions, but the baseline of 3 is appropriate given high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool's purpose: to retrieve a knowledge graph with specific node/edge types. It distinguishes itself from siblings by focusing on graph structure rather than individual notes or lists. The explanation of nodes, edges, and semantic_edges is specific and actionable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool versus alternatives: it recommends scoping with folder_id or root_title+depth when you need only part of the graph, and it warns about the unfiltered full-vault return being too large for context. This guidance is direct and practical, helping the agent choose appropriate parameters.

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. Answers "what is this connected to" with a flat list of titles — no node indices to decode, no whole-vault payload. For the shape of that neighbourhood — which notes link to each other, not just which are near — use get_graph with root_title and depth instead; it scopes the same way and keeps the edges.

Traversal is undirected: a note linking HERE is a neighbour just as much as one linked FROM here, because "what is this connected to" means both. links_out and links_in describe the direct relation to the note you asked about, and are sent only when true — so a depth-2 row carries neither. That is not a missing value: "which way does the arrow point" has no answer two hops away. Each note appears once, at the shortest depth that reaches it, and depth: 1 means directly linked.

These are LINKS people wrote, not similarity — a note about the same subject that nobody linked is not here. get_graph's semantic_edges cover that, and search covers finding it at all. An empty result means nothing links to or from this note, which is a fact about the writing, not about the topic.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNo
depthNoHops to walk. 1 = directly linked notes; each extra hop widens the set fast
titleNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full transparency burden, and it delivers: undirected traversal, links_out/links_in sent only when true, absence at depth 2 meaning no arrow direction, deduplication at shortest depth, and the distinction between human-written links and semantic similarity. It even defines what an empty result means.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but densely purposeful: every paragraph explains a non-obvious behavior or decision boundary, and the core purpose is front-loaded in the first sentence. The extended clarifications prevent misinterpretations that would otherwise require trial and error.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and no annotations, the description covers output shape, traversal semantics, and empty-result meaning very thoroughly. The main gap is target-note parameter resolution: an agent still cannot be fully certain whether to pass id, title, or both, and what happens if both are supplied.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33%, so the description must compensate, but it never explains how the target note is identified via id or title, nor their relationship or precedence. It adds excellent semantics for depth, but the two most important parameters for addressing 'ONE note' are left essentially undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific operation with a precise resource and scope: 'What is around ONE note in the [[wikilink]] graph, out to depth hops.' It also clarifies the output shape ('flat list of titles') and explicitly contrasts itself with get_graph, making it easy to distinguish from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing guidance: use get_graph for the edge structure with 'same scope,' and use get_graph's semantic_edges or search when similarity or finding a note is the goal. It also explains when an empty result is meaningful, so an agent knows what conclusion to draw.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_noteA

Get full note content by id or title. Title matching is case-insensitive and forgiving: an exact match wins, otherwise it falls back to prefix then substring, so a unique partial title resolves. An ambiguous title returns the candidate list (id + title) to retry with. Large notes are windowed: content is capped at 20000 chars by default (see limit/offset) — check content_truncated and content_total_length in the response, and pass next_offset back as offset to fetch the rest. Every response carries headings — the H1–H3 outline with character offsets, so a truncated note still shows what is in the part you did not get. Jump there with that offset, or name it in section to get that heading and its body alone — with section, headings narrows to that section's own subheadings too (offsets re-based to the section's own start, matching offset/limit's meaning in that mode), not the whole note's. Pass resolve_links: true to also resolve [[wikilinks]] inside it one level deep — use when you need a note's linked context without extra round-trips. Each linked note comes back as id/title/folder_path only by default; pass include_content:true for the full text of each (expensive if the note links to many others), capped at 4000 chars — call get_note on a specific id for its full text. updated_at moves on any stored change, including another note's rename rewriting a [[link]] to this one — pass it back as expected_updated_at on a write. content_updated_at only moves when THIS note's own title/content/folder/tags were actually edited — that's the one that answers "did anyone really touch this". Unresolved links (targets not found) are listed separately.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNo
limitNoMax characters of content to return
titleNo
offsetNoCharacter offset into content to start from
sectionNoReturn only this section (heading text or slug, case-insensitive) and its body
resolve_linksNoAlso resolve [[wikilinks]] inside the note one level deep
include_contentNoWith resolve_links: include full text of linked notes, not just id/title/folder_path

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure, and it does so extensively. It discloses windowing behavior and the content_truncated/content_total_length flags, how headings behave when notes are truncated, section offset re-basing, one-level-deep wikilink resolution, the 4000-char cap on included linked-note content, and the subtle difference between updated_at and content_updated_at. No behavioral surprises are left for the agent to discover at call time.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but nearly every sentence carries functional information that is not available anywhere else since there are no annotations and no output schema. It is front-loaded with the core purpose and moves logically from retrieval to pagination, headings, sections, link resolution, and timestamps. It is not concise, but the length is justified by the tool's complexity; it loses a point only because a more scannable structure (e.g., shorter paragraphs or labeled behaviors) would help agent parsing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a complex tool with 7 parameters, zero required fields, no annotations, and no output schema, so the description must cover invocation behavior, return fields, and edge cases. It does: response fields like content_truncated, content_total_length, headings, next_offset, and unresolved links are all explained; pagination, section mode, link resolution, and timestamp semantics are fully covered. Nothing needed to call the tool correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, and the description substantially compensates for the undocumented params (id, title) while adding meaning to the documented ones. It explains title matching fallbacks, the meaning of offset/limit in windowing and section mode, section selection semantics, resolve_links depth, and include_content tradeoffs. This goes well beyond the schema and makes parameter behavior predictable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource: 'Get full note content by id or title.' It immediately distinguishes the tool from list/search siblings by focusing on retrieving a single note's full content, and the rest of the description clarifies the nuanced retrieval semantics (title matching, windowing, sections). This is unambiguous and distinguishes the tool's role among the sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use advanced options: use resolve_links when 'you need a note's linked context without extra round-trips' and use section to fetch a heading and its body alone. It does not explicitly contrast this tool with sibling alternatives like list_notes or search_notes, but for a single-note fetch tool the intended use is well implied. The absence of explicit exclusions or alternative-tool routing keeps it from a 5.

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 notes, complete=true when pending=0. Pending notes are still found by text search; notes with previous embeddings remain in semantic search with their last vector, while notes never embedded are excluded from semantic/hybrid until processed (automatic, background). Stuck pending count while nothing is being edited = check Ollama/server logs. Also names the active embedding model and says whether any automatic semantic cutoff is in force. By default there is none: semantic_profile reads "none" and semantic_min_similarity is null, meaning semantic search returns its nearest matches and refuses nothing on its own. Automatic abstention is deliberately not part of the default retrieval contract — a shipped per-model cutoff was measured and withdrawn, because it cost real answers (cross-language matches share no words, so nothing else finds them) without reliably stopping confident near-misses. An owner who has measured their own corpus can set one; then semantic_profile reads "configured" and the number is theirs. Raw cosines are NOT comparable between models: a number that means a good match on one means noise on another, which is why the model is named here rather than left to be inferred from the score.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure, and it does so thoroughly. It explains the behavior of pending notes (still found by text search), notes with previous embeddings (remain in semantic search with last vector), and never-embedded notes (excluded until processed). It also discloses the default semantic cutoff behavior, the meaning of semantic_profile values, and the non-comparability of raw cosines across models. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but information-dense, covering multiple important behaviors and caveats. It is front-loaded with the core status semantics, then expands into edge cases and configuration details. While it could be tightened, every sentence adds meaningful context that an agent would need to correctly interpret the tool's output. The length is justified by the complexity of the semantic search behavior it explains.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter status tool with no output schema, the description is remarkably complete. It explains what the tool reports, how to interpret each piece of information, what the default behavior is, why the model name is included, and what to do if the count appears stuck. An agent has everything it needs to call this tool and correctly interpret its results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema is trivially complete. The description adds substantial context about what the tool reports (total/indexed/pending counts, completion flag, model name, cutoff status), which is more than enough for an agent to understand what the tool will return. A 4 is appropriate because while there are no parameters to document, the description goes beyond the schema in explaining the tool's output semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise summary: 'Semantic-index progress: total/indexed/pending notes, complete=true when pending=0.' This states the tool's function (reporting indexing status) and its key output semantics. It clearly distinguishes itself from sibling tools like search_notes or get_note by focusing on index progress and embedding model information.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use this tool: to check indexing progress, to understand why pending notes may be stuck (check Ollama/server logs), and to determine the active embedding model and any semantic cutoff. It also explains when not to rely on it: it doesn't filter search results, and it clarifies that automatic abstention is not part of the default retrieval contract. This is strong usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_foldersA

List all folders (flat array) 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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden. It usefully reveals two behavioral traits: the return shape is a flat array and paths are already resolved. However, it does not mention ordering, whether deleted or hidden folders are included, or what fields accompany each folder. It is helpful but not fully transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences, each earning its place: the first defines the core behavior and output shape, and the second gives actionable downstream usage. Information is front-loaded and there is no filler or repetition of schema data.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless, read-only listing tool with no output schema, the description is complete enough for an agent to call it correctly. It states what the tool returns, how the result is structured, and how the result should be used in related operations. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

This tool has zero parameters, and the schema already covers that fully, so the baseline is 4. The description adds relevant context by explaining how returned folder ids should be used with create_folder/update_folder, though it does not need to explain any parameters of this tool itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: "List all folders (flat array)". It also clarifies the key distinguishing behavior—"full path already resolved—no need to walk parent_id yourself"—so the tool is immediately distinguishable from related tree-walking or graph tools. This is a precise, unambiguous purpose statement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives contextual guidance for when this tool is useful: you get complete folder paths without manually traversing parent_id. It also tells you how to use the result, saying to pass a folder's id as parent_id to create_folder/update_folder. It does not explicitly name alternatives or exclusions, but the intended context is clear.

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, sorted by recency (newest first). Optional filters: folder_id, tag, created_after/created_before, updated_after/updated_before, limit (max 200). created_after answers "what is new" — a note's creation date never changes after it is made. updated_after answers "what changed since I was last here" — it moves only when this note's own title/content/folder/tags were actually edited, NOT when renaming some other note rewrote a [[link]] to it in passing (that still touches updated_at, returned separately, but not this filter/sort). They are NOT interchangeable: a note edited today but created months ago matches updated_after, not created_after. sort picks which of the two dates drives the ordering (default "updated"). Each note carries content_length (characters in the full note) so you can tell a long note from a short one before spending a get_note call on it. Pass trashed:true to see soft-deleted notes instead (recoverable with restore_note until they age out of the trash) — other filters are ignored in that mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoFilter by tag
sortNoWhich date drives the orderingupdated
limitNo
trashedNoList soft-deleted notes instead of live ones
folder_idNoFilter by folder UUID
created_afterNoISO timestamp — only notes created at or after this
updated_afterNoISO timestamp — only notes whose own content actually changed at or after this
created_beforeNoISO timestamp — only notes created at or before this
updated_beforeNoISO timestamp — only notes whose own content actually changed at or before this

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and delivers richly. It discloses subtle behavior around updated_after (only own edits count, not link rewrites from other notes), the trashed-mode filter override, soft-delete recoverability, and that content_length is included so long notes can be distinguished without a fetch.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and every sentence carries useful information, with no filler. It is, however, a long single paragraph packing multiple nested caveats, which makes it denser than necessary; splitting the timestamp guidance and trashed-mode guidance would improve scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 9-parameter tool with no output schema, the description covers the tricky filter semantics, sorting, and trashed behavior well enough to invoke correctly. It does not describe the full response shape or pagination beyond limit, so an agent is left to infer what fields besides updated_at and content_length are returned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 89% schema coverage, the description adds significant semantic value beyond the schema. It explains the meaning of created_after vs updated_after, the sort default and its effect, the max limit of 200, and the fact that trashed:true ignores other filters. These are distinctions an agent cannot reliably infer from parameter names alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('List notes') and immediately adds the ordering rule ('sorted by recency'). It also differentiates from siblings by noting content_length can avoid a get_note call and by tying trashed mode to restore_note, so an agent can tell this endpoint apart from adjacent tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong situational guidance: created_after is for 'what is new', updated_after is for 'what changed since I was last here', and it explicitly warns they are not interchangeable. It also explains trashed mode and that other filters are ignored there. However, it never explicitly names alternatives like search_notes for cases where list_notes would be the wrong tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tagsA

List tags in use with the number of notes carrying each, most-used first, capped at limit (default 40). Call this before tagging a note and reuse an existing tag when one fits, rather than coining a near-duplicate (a translation, transliteration, or plural of an existing tag) — the vault has no tag synonyms, so near-duplicates fragment the same concept into separate tags. The default cuts off the one-off tail: a tag used once is not one worth reusing, so it is not shown unless you raise limit.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax tags to return, most-used first

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well. It discloses sorting order, the default cap, the behavior that one-off tags are omitted, and the reason behind that default. This goes well beyond a minimal read-only hint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three focused sentences: the first states core behavior, the second provides workflow guidance, and the third explains default cutoff behavior. No filler or repetition; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter, read-only listing tool with no output schema, the description covers result content, ordering, cap, and usage rationale. Nothing critical is missing for an agent to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents the limit parameter with default, min, max, and a description. The tool description adds value by explaining what the default cutoff means in practice and why raising the limit may be necessary, which helps the agent reason about the parameter's effect.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'List tags in use with the number of notes carrying each, most-used first.' It also includes sorting and cap behavior, which distinguishes it from sibling tools like list_notes 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs when to call the tool: 'Call this before tagging a note and reuse an existing tag when one fits.' It also explains the rationale for avoiding near-duplicates and notes the vault has no tag synonyms, making the usage guidance concrete and actionable.

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. Refuses unless find occurs exactly expected_count times (default 1) — protects against a loose find rewriting more than intended. Accepts either find/replace or old_string/new_string (same pair, either naming works).

For several replacements in one note, pass edits (array of {find/old_string, replace/new_string, expected_count}) instead of the singular fields — one row lock and one re-embed for the whole batch instead of one per call. Edits apply in order, and each one's find is matched against the note as already changed by the edits before it, not the original content — an earlier edit can create the text a later one needs, or remove the text a later one expects to find; sequence them accordingly. If any step's count does not match, the whole batch is refused and the note is left completely untouched — the error names which edit index failed and how many times its find text actually occurred. Do not combine edits with the singular find/replace/old_string/new_string/expected_count fields — use one form or the other.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNo
findNoText to replace. Alias: old_string
editsNoMultiple find/replace steps applied in order in a single call — see main description.
titleNoAlternative to id; resolved like get_note
replaceNoReplacement text. Alias: new_string
new_stringNoAlias for replace
old_stringNoAlias for find
expected_countNo
expected_updated_atNoISO updated_at from when you read the note; refuses the write if it changed since

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full behavioral burden and excels: it discloses the expected_count safety guard, the aliasing equivalence, the ordering semantics of batch edits, the atomicity of the batch (whole batch refused, note untouched), and the error behavior that names the failing index. This goes well beyond what annotations could have provided.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place. It is front-loaded with the core behavior, then progressively explains the safeguard, aliases, batch usage, sequencing, atomicity, and the prohibition on combining forms. No redundancy or filler exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description thoroughly covers the tool's behavior and edge cases, but does not state that a note must be identified via `id` or `title` (even though the schema lists required as zero). For an API call, that is a meaningful omission; otherwise the operational details are complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Though schema coverage is high at 78%, the description adds substantial meaning beyond the schema: it explains the alias equivalence (find/old_string, replace/new_string), the semantic difference between singular and batch forms, the order-dependent matching ('each one's find is matched against the note as already changed by the edits before it'), and the all-or-nothing batch result. These are not evident from parameter definitions alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Replace exact text in a note without resending the rest.' It clearly distinguishes this targeted operation from siblings like update_note and append_to_note by emphasizing exact-match replacement and avoiding a full rewrite.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool ('without resending the rest') and provides detailed internal guidance on choosing between singular fields and the `edits` array. However, it does not explicitly name sibling tools as alternatives or state when not to use this tool.

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the burden of exposing mutation semantics. It clearly says the note is brought back and enumerates the error cases. It doesn't state whether restore is reversible or what metadata changes, but for this scope it is reasonably transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both informative. First sentence states the primary action; second sentence enumerates error cases and a remediation step. No filler or schema repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, the description covers purpose, preconditions, error scenarios collectivized and a remedy. The only notable gap from an agent perspective is not explicitly naming the id parameter as the note identifier, but the context makes it clear.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero description coverage and the tool description never explicitly explains that the single id parameter must be the ID of the soft-deleted note. It is inferable from the tool purposeholster, but the description adds no parameter-level meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific operational purpose: 'Undo delete_note: brings a soft-deleted note back.' This clearly identifies the action, the resource affected, and the precondition (the note must be soft-deleted). There is no ambiguity about what restore_note does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States when to use it (to undo delete_note on a soft-deleted note) and, importantly, when it will fail: never deleted, already restored, purged past retention, or title conflict. It even gives a recovery step ('rename one first, then retry'), which an agent can act on directly.

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. type: "text" (fast), "semantic" (meaning-based), "hybrid" (best, uses RRF). Hybrid is the right default; prefer type=text for exact identifiers, code fragments, or quoted phrases, where FTS beats meaning-matching. Returns short excerpts, not full notes — call get_note on the top 1-2 hits to read them. A query is required, because this ranks text against text: to list or filter notes by folder, tag or recency with no keywords, use list_notes instead. has_more says whether hits exist past the page you got, so a short result is never mistaken for a small vault; read the next page with the next_offset it comes with. It is deliberately a flag and not a total — the only number available here is a capped candidate pool, and for meaning-based matching "how many match" has no answer at all.

A hit in a long note may carry excerpt_offset — where that excerpt sits in the text. Pass it to get_note as offset with a small limit to read around the answer in one call. That is how you read a book or a log: prose with no markdown headings has no outline and no section, so the position is the only way in short of paging from the top.

Read the SECTION, not the note. When a hit carries section, that is the markdown heading its excerpt came from — pass that exact string to get_note's section and you get that part alone (measured on a real 13000-character note: 681 characters). When a hit has no section and its content_length is large, get_note with a small limit still returns the note's FULL headings outline for about a kilobyte — choose a heading from it, then re-read with section. Two small calls beat one 13-60 KB one; pull a whole note only when you genuinely need the whole note. Each hit carries relevance (0..1, how close to the best hit in THIS response) and matched_by (which arms found it). Both describe the response, not the world: relevance orders hits, it does not judge them, and there is deliberately no confidence score. Judge a hit by reading its excerpt.

This is candidate retrieval, not a factual answer, and the search does NOT decide for you whether the vault knows something. Semantic search returns the nearest passages it has; by default nothing is filtered out for being too dissimilar, so an EMPTY result means the index returned nothing at all — and a NON-empty one is not evidence that what you asked about is in there. (An owner may configure a minimum similarity; threshold in the response says whether one is in force, and is null when none is.)

So a hit found ONLY by the semantic arm (matched_by is semantic_score alone) says the passage is ABOUT something similar — never that it confirms what you asked. The two are routinely different: a query about a technology a vault has never used still returns its nearest neighbours with nothing about that technology in them. When a hit is semantic-only and its excerpt does not actually contain what you asked about, the honest reading is "no confirmation found" — say that, or open the note to check. Do not report it as evidence the thing exists. The excerpt is the evidence; the score never is.

text_tier, coverage and exact are observed facts about the text match, shipped when they say something you would not assume. A tier of "or"/"substring" means the strict query found nothing and a looser pass filled in — recall, not confirmation. coverage measures LEXICAL overlap: the share of your query's significant words that occur in the hit, weighted by how rare each is here. A low or zero value does NOT mean irrelevant — a paraphrase or a cross-language match legitimately shares no words with the question, and that is what the semantic arm is for. Read it as "how much of what you typed is literally in there", nothing more. exact: true is the one thing FTS cannot express, and it means exactly this and nothing more: the query occurs as a contiguous, case-insensitive substring of that note (wildcards escaped — A_B does not match AxB). It is set only for a whitespace-free query that still splits into several words — a filename, an identifier, a code symbol, the case where the tokenizer takes one name apart and cannot put it back. Never for a phrase or a question: a note QUOTING your question is not a note answering it. Such hits take the top half of the relevance scale, ranked among themselves by their own text score. Neither tier nor coverage is comparable across different queries, only within one response. Filters: folder_id (or folder_path, the same folder written as a path — no need to look the UUID up first), tag, created_after/before (when a note was made), updated_after/before (when its own content/title/folder/tags last actually changed — a rename elsewhere rewriting a [[link]] to this note does not count) — these are NOT interchangeable. Dates filter, they do not rank: a note edited an hour ago and one untouched for months compete on relevance alone, and nothing here prefers the fresher one. So for "what is the LATEST state of X" this is the wrong first call — list_notes already sorts by recency, newest first, and takes updated_after. Search finds a topic; list_notes finds what changed. A question about the current state of something usually needs both. Every semantic/hybrid response includes threshold/best_score/pending_embeddings so you can tell "nothing was found" from "a configured filter removed it" from "embeddings not generated yet", even when results came back non-empty. Freshness: a hit carrying index_pending:true has an excerpt built from a PREVIOUS version of that note — the note row itself always holds the current text, only its search vectors lag. Call get_note on it (with section, if one is reported) and quote that, not the excerpt, before telling the user what the note says. Response-level pending_embeddings counts how many notes are in that state vault-wide, and stale_generation_chunks counts vectors left over from a previous embedding model, which are excluded from semantic results until reindexed — a non-zero value there explains a thin semantic arm rather than an empty vault. question_echo:true means the note LISTS your question without answering it (an FAQ or agenda of questions); treat it as a pointer to the topic, never as the answer. When reranked:true, prefer type="text" for a term you already know is written in your notes verbatim — an identifier, a filename, a code symbol, a product name. Reranking judges a passage by meaning, and a model that has never seen your vault can rank a passage that reads as more on-topic above the note that literally contains your term — a hit carrying most of your query's words can end up below one carrying far fewer. Only exact:true hits are protected from this. So hybrid remains the right default when you do not know the wording, and text is the better tool when you do — check coverage on a hybrid response to see whether the top hit actually contains what you typed. When the response carries reranked:true, a cross-encoder chose this order instead of rank fusion, and each hit's rerank_score is its best passage's score. That score is a model's opinion about ONE passage of the note, ordering this response only — it is not a confidence value, not comparable between queries, and not evidence the note answers you. reranked:false alongside it means the reranker was asked and did not answer, so you are reading the ordinary fused order. Read the text either way. That model is by far the slowest part of a search, and reranking is off unless an owner turned it on — it is optional and unproven, not an upgrade you are missing. Where it is on, pass rerank:false whenever you want an answer rather than a better ORDER: checking whether a term appears at all, or finding the note holding a value whose shape you already know. Pass explain:true to also see each hit's raw text_score/semantic_score/rrf_score and created_at — only useful for debugging the ranking itself, omitted by default to keep responses short.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoRestrict to notes with this tag
typeNohybrid
limitNo
queryYes
offsetNoSkip this many hits — with has_more in the response, how you read past the first page
rerankNoSet false to skip the cross-encoder and answer from the fused order — several times faster, and not measurably worse
explainNoInclude raw per-arm scores and created_at for debugging ranking
folder_idNoRestrict to notes in this folder
folder_pathNoSame restriction by path (e.g. "Projects/Kybase") instead of UUID — that folder itself, not its subfolders
created_afterNoISO timestamp — only notes created at or after this
updated_afterNoISO timestamp — only notes whose own content actually changed at or after this
created_beforeNoISO timestamp — only notes created at or before this
updated_beforeNoISO timestamp — only notes whose own content actually changed at or before this

TDQS

A4.9/5.0
Behavior5/5

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—and it does so thoroughly. It discloses that results are candidate retrieval, not factual answers; that empty results mean nothing was indexed; that relevance is relative, not absolute; that index_pending means the excerpt is stale; and that reranking is a model opinion, not confidence. It also explains the meaning of reranked:true/false and how to interpret threshold and pending_embeddings. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extraordinarily long (several thousand words) and dense, but it is well-structured with clear topical paragraphs (query semantics, reading hits, relevance, filters, reranking, debug flags). It front-loads the core purpose and gives critical routing advice early. However, some repetition occurs (e.g., multiple warnings that scores don't confirm existence), and it could likely be trimmed ~30% without losing value. Still, it is organized and each paragraph covers distinct concerns, so it earns a high score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (13 parameters, no output schema, many subtle response fields), the description is remarkably complete. It explains every response field mentioned (has_more, next_offset, excerpt_offset, section, relevance, matched_by, text_tier, coverage, exact, threshold, best_score, pending_embeddings, stale_generation_chunks, question_echo, reranked, rerank_score). It also covers edge cases like wildcards and multi-word tokens. An agent calling this tool would know exactly what to expect and how to interpret results for next steps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is high (77%), but the description adds significant meaning beyond the schema. For example, it distinguishes created_after/before from updated_after/before (the latter only counts own-content changes, not link rewrites), explains folder_id vs folder_path (no need to look up UUID), and details how rerank and explain affect behavior. It also clarifies type enum semantics (text vs semantic vs hybrid) beyond the basic default. The description compensates for any gaps in schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Search notes' and immediately distinguishes itself from siblings: it explicitly says to use list_notes for folder/tag/recency filtering without keywords, and to use get_note to read full notes. It clearly states the tool is for ranking text against a query, not for listing or filtering. This makes it unambiguous which tool to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage guidance: when to prefer type=text (exact identifiers, code fragments, quoted phrases) vs hybrid (default), when to use list_notes instead of search, and how to chain with get_note using section/offset. It even explains when NOT to use search (e.g., 'latest state of X' should use list_notes first). This is exhaustive and actionable.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes
nameNo
parent_idNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral disclosure burden. It discloses that the response includes the resolved path, letting the agent confirm the result without a follow-up call, and explains the parent_id null semantics. It does not cover error cases like invalid parent folders or cycles, but the core behavior is clearly conveyed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with no filler. The main operation is front-loaded, followed by parameter constraints and a valuable response-behavior note. Every sentence adds necessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple three-parameter update tool with no output schema or annotations, the description covers the operation, the required/optional parameter relationship, the null case, and the response format. Missing edge-case details such as folder-name conflicts or move-cycle prevention would improve completeness, but the agent has enough to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds real meaning beyond the schema by explaining that name triggers a rename, parent_id triggers a move, null means top level, and at least one of the two is required. This is strong compensation for a low-coverage schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses specific verbs ('rename', 'move') tied to the folder resource, which clearly distinguishes it from sibling tools like create_folder, delete_folder, and list_folders. The operation is unmistakable even without examining the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear conditions: at least one of name/parent_id must be supplied, and parent_id null targets the top level. It does not explicitly name alternatives or state when not to use this tool, but the purpose statement makes the intended use obvious.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes
tagsNo
titleNo
contentNo
folder_idNo
expected_updated_atNoISO updated_at from when you read the note; refuses the write if it changed since

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral disclosure burden. It reveals that title/content changes trigger re-embedding, title changes update wikilinks, substantial rewrites are subject to server rules, and expected_updated_at causes a refusal instead of silent overwrite. It does not mention return shape, errors, or how tag changes behave, but the core mutation behavior is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is four dense sentences with no filler. The core action is front-loaded, side effects are stated immediately, and the concurrency/tag guidance earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an update tool with no output schema and no annotations, the description supplies the critical operational facts: when side effects happen, when server rules apply, and how to avoid lost updates. It could mention the return value or folder_id null behavior, but the essential information for correct invocation is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only expected_updated_at has a schema description, so the description must compensate for low coverage. It does clarify expected_updated_at semantics and connects title/content to side effects. However, it adds little meaning for id, tags, or folder_id beyond their names and schema types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

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.' The additional side-effect details (re-embedding, wikilink updates) help characterize this as a field-level update tool rather than an append or replace operation. It does not explicitly contrast with create_note or append_to_note, so it misses the top score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use this tool: to update fields of an existing note. It also supplies actionable guidance, such as calling list_tags before coining a new tag and passing expected_updated_at for optimistic concurrency. It does not explicitly state when to prefer append_to_note or replace_in_note, so it is not a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 18 tool updatesv1.3.0
    • First observedappend_to_note
    • First observedcreate_folder
    • First observedcreate_note
    • First observeddelete_folder
    • First observeddelete_note
    • First observedget_backlinks
    • First observedget_graph
    • First observedget_neighbors
    • First observedget_note
    • First observedindexing_status
    • First observedlist_folders
    • First observedlist_notes
    • First observedlist_tags
    • First observedreplace_in_note
    • First observedrestore_note
    • First observedsearch_notes
    • First observedupdate_folder
    • First observedupdate_note

TDQS

A4.1/5.0

Scored across 18 tools

Disambiguation4/5

Most tools are clearly distinct (get_note vs list_notes vs search_notes; create/update/delete/restore_note; folder operations). The only mild overlap is get_neighbors vs get_graph, but their descriptions explicitly differentiate scope and output shape, so an agent can choose correctly.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern: get_note, list_notes, create_note, update_note, delete_note, restore_note, search_notes, list_folders, create_folder, update_folder, delete_folder, get_graph, get_backlinks, get_neighbors, append_to_note, replace_in_note, indexing_status, list_tags. No mixed conventions or vague verbs.

Tool Count4/5

18 tools is on the higher end but appropriate for a knowledge-management server covering notes, folders, search, graph, and indexing. Each tool earns its place; the count is justified by the domain breadth.

Completeness5/5

The surface covers the full note lifecycle (create, read, update, append, replace, delete, restore), folder management, search (text/semantic/hybrid), graph traversal, backlinks, tags, and indexing status. No obvious dead ends: every write has a corresponding read, and soft-delete has restore.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    A 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.
    1
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    A self-hosted persistent memory platform for AI agents and humans offering tools for memory storage, search, beliefs, work management, and code intelligence via MCP.
    7
    GPL 3.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Self-hosted personal knowledge base with semantic search, enabling AI agents to capture, search, and manage thoughts using PostgreSQL with pgvector.
    13 npm
    ISC