Skip to main content
Glama

search_notes

Locate relevant notes in Kybase by querying with keyword, semantic, or hybrid search. Returns ranked excerpts with folder, tag, and date filters so you can pinpoint information.

Instructions

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.

Input Schema

TableJSON 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

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv1.3.0

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.