Kybase
NPM · KYBASE-MCP · SCANNED SEP 26
Self-hosted Markdown memory for AI agents: notes you can read and edit, with hybrid search.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 44 of 124 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency48
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (AGPL-3.0-only).Pass
- Actively maintained (last published 2 days ago).Pass
- Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability68
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 4628 tokens (~257/item across 18 items; 18 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management0
- Stability not yet verified: not enough scan history yet (needs a 30-day window).Unverified
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
Tool Safety75
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- 0 of 2 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "delete_note" implies "delete" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
- An AI judge read all 19 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Unverified: 1 category
A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.
How do I install the Kybase MCP server?
Kybase runs locally as an npm package, launched with npx -y kybase-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · kybase-mcp
claude mcp add kyrzin-kybase -- npx -y kybase-mcp
{
"mcpServers": {
"kyrzin-kybase": {
"command": "npx",
"args": [
"-y",
"kybase-mcp"
]
}
}
} {
"servers": {
"kyrzin-kybase": {
"command": "npx",
"args": [
"-y",
"kybase-mcp"
]
}
}
} codex mcp add kyrzin-kybase -- npx -y kybase-mcp
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"kyrzin-kybase": {
"type": "local",
"command": [
"npx",
"-y",
"kybase-mcp"
],
"enabled": true
}
}
} openclaw mcp add kyrzin-kybase --command npx --arg -y --arg kybase-mcp
mcp_servers:
kyrzin-kybase:
command: "npx"
args: ["-y", "kybase-mcp"] {
"McpServers": {
"kyrzin-kybase": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"kybase-mcp"
]
}
}
} assistant mcp add kyrzin-kybase -t stdio -c npx -a -y kybase-mcp
{
"mcpServers": {
"kyrzin-kybase": {
"command": "npx",
"args": [
"-y",
"kybase-mcp"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 25 Sept 26 0
- We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
- 24 Sept 26 +11
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → 0.84 ▲ functional
- 23 Sept 26 57
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 26 Sept 2026 · Analysed npm/kybase-mcp@0.2.1
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 124 packages
| Packages resolved | 124 |
|---|---|
| Stale | 44 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
append_to_note ~359
Add text to a note without resending the rest — prefer it over update_note for journals, logs and running lists. A blank line separates your text from what was there. The note is locked for the read-modify-write, so two sessions appending at the same moment keep both additions instead of the later one overwriting the earlier. Re-embeds in the background like any content change.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | – | Where the text lands. Defaults to section_end when section is given, else note_end. note_end: the very end. note_start: above the first heading nested under the opening one — NOT offset 0, except on… |
| content | string | yes | Text to add. Trailing whitespace is trimmed and a blank line is inserted before it, so the addition never runs into the preceding paragraph |
| id | string | – | The note's UUID. Alternative to title |
| section | string | – | Target this section (heading text or slug) instead of the whole note. Valid values come from a search hit's `section`, get_note's `headings`, or a heading line in the note's own text — the slug form… |
| title | string | – | Alternative to id; resolved like get_note |
No output schema declared.
No examples provided.
create_folder ~66
Create a new folder. Optionally nested under a parent.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | Folder name. Unique among its siblings — the same name under a different parent is fine |
| parent_id | – | – | Parent folder UUID. Omit or pass null to create it at the top level |
No output schema declared.
No examples provided.
create_note ~218
Create a new note. Embedding is generated automatically in the background. The server instructions' wikilink and tag rules apply: search_notes for the topic first and link the related notes it finds, and call list_tags before coining a new tag.
| Name | Type | Req | Description |
|---|---|---|---|
| content | string | – | Markdown body. Empty by default, so a note can be created first and filled with append_to_note |
| folder_id | – | – | Folder UUID. Omit or pass null for the vault root; use folder_path instead when you have the path rather than the id |
| folder_path | string | – | Folder path (e.g. "Projects/Kybase") as alternative to folder_id |
| tags | array | – | Tags for the new note: lowercase, kebab-case, in the language already in use. Call list_tags first and reuse an existing tag where one fits |
| title | string | yes | Unique across live notes, case-insensitively; a clash is refused rather than merged. This is the string other notes link to as [[Title]] |
No output schema declared.
No examples provided.
delete_folder ~98
Delete a folder and its full subtree of child folders (cascade). Every note inside — including notes in nested subfolders — is soft-deleted into the trash along with it (see delete_note), recoverable via restore_note within the retention window. To preserve organization instead, move notes/subfolders out first.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | UUID of the folder to delete along with its subfolders. Notes inside are moved to the trash, not destroyed |
No output schema declared.
No examples provided.
delete_note ~86
Soft-delete a note by id — it disappears from list_notes/search/get_note/the graph, but is recoverable with restore_note for 30 days before being purged for good. Use list_notes with trashed:true to see what's currently in the trash.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | The note's UUID. An unknown or already-trashed id is refused rather than reported as deleted |
No output schema declared.
No examples provided.
get_backlinks ~192
Notes that link to this one via [[Title]] wikilinks, by id or title. Each comes back as id/title/folder_path plus a snippet around the link; include_content:true returns their full text instead, which is expensive when many notes link here — prefer get_note on the ids you actually want. offset and limit count notes, not characters.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | – | UUID of the note whose incoming links you want |
| include_content | boolean | – | Return each linking note's full text instead of a snippet around the link. Expensive when many notes link here |
| limit | integer | – | Linking notes per page. Several links from the same note count as one |
| offset | integer | – | Skip this many linking notes — pass back next_offset from the previous page |
| title | string | – | Alternative to id; resolved like get_note (exact, then prefix, then substring) |
No output schema declared.
No examples provided.
get_graph ~388
Many notes at once and the edges between them — the heavy graph tool, and the only one that reaches for the whole vault. For one note's surroundings use get_neighbors; for who links to it, get_backlinks. Nodes are `{t}` (t = title). Edges reference nodes BY POSITION in the `nodes` array: `edges[0] = [2, 5]` means nodes[2] links to nodes[5]. semantic_edges are undirected and come from embedding similarity rather than written links, with the cosine as a third number. `unresolved_links` are [[wikilink]] targets matching no note title — dangling, so they have no node index. Unscoped this reaches for the ENTIRE vault and stops at max_nodes: `truncated: true` means you hold a recency-ordered prefix, NOT the shape of the vault. Scope with folder_id or root_title+depth rather than raising the cap.
| Name | Type | Req | Description |
|---|---|---|---|
| depth | integer | – | Hop count for root_title; ignored without it |
| folder_id | string | – | Restrict to notes in this folder and its descendant folders |
| include_semantic | boolean | – | Include semantic_edges at all |
| max_nodes | integer | – | Ceiling on nodes returned, most recently edited first. The reply says `truncated: true` when it applies — scope with folder_id or root_title instead of raising this |
| min_score | number | – | Cosine floor for semantic_edges — lower to see more (noisier) edges |
| root_title | string | – | Keep only nodes within `depth` wikilink-hops of this note — resolved like get_note: exact, then unique prefix, then unique substring, case-insensitive |
| unresolved_only | boolean | – | If true, return only { unresolved_links } without nodes and edges (fast check for broken links) |
No output schema declared.
No examples provided.
get_neighbors ~284
What is around ONE note in the [[wikilink]] graph, out to `depth` hops: a flat list of titles, no node indices to decode and no whole-vault payload. For the shape of that neighbourhood — which of them link to each other — use get_graph with root_title instead. Traversal is undirected: a note linking HERE counts as much as one linked FROM here. `links_out`/`links_in` describe the direct relation and appear only at depth 1 — two hops out, "which way does the arrow point" has no answer. Each note appears once, at the shortest depth that reaches it. These are links people wrote, not similarity: a note on the same subject that nobody linked is not here, and an empty result is a fact about the writing rather than about the topic. Rows carry the title, which is what get_note, get_backlinks and this tool all take.
| Name | Type | Req | Description |
|---|---|---|---|
| depth | integer | – | Hops to walk. 1 = directly linked notes; each extra hop widens the set fast |
| id | string | – | UUID of the note whose surroundings you want |
| limit | integer | – | Maximum neighbours to return, nearest depth first. `total` still counts them all |
| title | string | – | Alternative to id; resolved like get_note (exact, then prefix, then substring) |
No output schema declared.
No examples provided.
get_note ~373
Read one note, by id or title. - Long notes come back windowed — 20000 chars by default: check `content_truncated` and pass `next_offset` back as `offset` for the rest. A windowed reply carries `headings` — the H1–H3 outline with character offsets — so name one in `section` to get that heading and its body alone instead of paging through the note. - `resolve_links:true` also returns the notes this one links to, id/title only unless you add include_content:true, whose text is capped at 4000 chars — call get_note on an id for the whole of one. Targets that match no note are listed as unresolved. - Pass the `updated_at` you read back as `expected_updated_at` when you write. `content_updated_at` is the one that moves only on a real edit to this note: a rename elsewhere rewriting a [[link]] inside it touches `updated_at` but not that.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | – | The note's UUID. Live notes only — a trashed note is not found until restore_note brings it back |
| include_content | boolean | – | With resolve_links: include full text of linked notes, not just id/title/folder_path |
| limit | integer | – | Max characters of content to return |
| offset | integer | – | Character offset into content to start from |
| resolve_links | boolean | – | Also resolve [[wikilinks]] inside the note one level deep |
| section | string | – | Return only this section (heading text or slug, case-insensitive) and its body |
| title | string | – | Alternative to id: exact match first, then unique prefix, then unique substring. An ambiguous title comes back as the candidate list to retry with |
No output schema declared.
No examples provided.
indexing_status ~110
Semantic index progress: total/indexed/pending, complete=true when pending is 0. Pending notes are still found by text search; ones never embedded stay out of semantic results until the background pass reaches them. Also names the active embedding model and the configured similarity cutoff (`semantic_min_similarity`, null when there is none — the default, meaning nothing is refused for being too dissimilar). Cosines are not comparable between models, which is why the model is named rather than left to be guessed from a score.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
list_folders ~109
List folders with the full path already resolved — no need to walk parent_id yourself. Pass a folder's own id as parent_id to create_folder/update_folder to nest under it. Sorted by path, so a page is a contiguous slice of the tree read top to bottom; the reply is `{folders, has_more, next_offset?}`.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Folders per page |
| offset | integer | – | Skip this many folders — pass back next_offset from the previous page |
No output schema declared.
No examples provided.
list_notes ~332
List notes newest first, filtered by folder, tag or date. This is the tool for "what is new" and "what changed lately": search_notes ranks by relevance and never by recency. created_* is when a note was made, updated_* when its own text last changed — a rename elsewhere rewriting a [[link]] inside it does not count as an edit here. Each row carries content_length, so you can tell a long note from a short one before spending a get_note call. With trashed:true the other filters are ignored.
| Name | Type | Req | Description |
|---|---|---|---|
| created_after | string | – | ISO timestamp — only notes created at or after this |
| created_before | string | – | ISO timestamp — only notes created at or before this |
| folder_id | string | – | Filter by folder UUID — that folder itself, not its subfolders |
| folder_path | string | – | Same filter by path (e.g. "Projects/Kybase") instead of UUID — that folder itself, not its subfolders |
| limit | integer | – | Maximum notes to return per page. Applies in trashed mode too |
| offset | integer | – | Skip this many notes — pass back next_offset from the previous page |
| sort | string | – | Which date drives the ordering |
| tag | string | – | Filter by tag |
| trashed | boolean | – | List soft-deleted notes instead of live ones |
| updated_after | string | – | ISO timestamp — only notes whose own content actually changed at or after this |
| updated_before | string | – | ISO timestamp — only notes whose own content actually changed at or before this |
No output schema declared.
No examples provided.
list_tags ~66
Tags in use with the number of notes carrying each, most-used first. The default limit cuts off the one-off tail — a tag used once is not one worth reusing — so raise it to see those.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Max tags to return, most-used first |
No output schema declared.
No examples provided.
replace_in_note ~325
Replace exact text in a note without resending the rest. Either find/replace or old_string/new_string — the same pair, either spelling. For several replacements pass `edits` rather than the singular fields (one lock and one re-embed for the batch, not one per call); the two forms cannot be combined in one call. Edits apply in order, and each `find` is matched against the note as the edits before it already changed it — an earlier edit can create the text a later one needs, or destroy it, so sequence them. If any step's count is wrong the whole batch is refused and the note is left untouched, and the error names the failing index.
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Multiple find/replace steps applied in order in a single call — see main description. |
| expected_count | integer | – | How many times `find` is expected to occur (default 1). The edit is refused if the real count differs, so a loose `find` cannot quietly rewrite more than intended |
| expected_updated_at | string | – | ISO updated_at from when you read the note; refuses the write if it changed since |
| find | string | – | Text to replace. Alias: old_string |
| id | string | – | The note's UUID. Alternative to title |
| new_string | string | – | Alias for replace |
| old_string | string | – | Alias for find |
| replace | string | – | Replacement text. Alias: new_string |
| title | string | – | Alternative to id; resolved like get_note |
No output schema declared.
No examples provided.
restore_note ~87
Undo delete_note: brings a soft-deleted note back. Errors if the note isn't in the trash (never deleted, already restored, or purged past the retention window), or if a live note has since taken the same title (rename one of them first, then retry).
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | UUID of a note currently in the trash — the same id delete_note was given |
No output schema declared.
No examples provided.
search_notes ~688
Search notes: hybrid (keyword + meaning) by default. Returns ranked excerpts, not whole notes. - Use type="text" for an exact identifier, filename, code symbol or quoted phrase; "hybrid" for questions and topics. - READ THE SECTION, NOT THE NOTE. A hit's `section` is the heading its excerpt came from — pass that string to get_note's `section` to get that part alone. If a long hit has no `section`, get_note with limit:1000 returns its `headings` outline; pick one and re-read with `section`. For prose without headings, a hit's `excerpt_offset` goes to get_note as `offset`. - A hit is a candidate, not an answer. `relevance` is relative to the best hit in this response, so the top result always reads 1.0 — an ordering, not a verdict; `best_score` is that hit's own raw similarity. `matched_by` says which arms found it: semantic_score alone means "about something similar", never that it confirms your question. Quote the excerpt or open the note — a score is never evidence. `exact:true` means the query occurs verbatim in that note; `text_tier` of "or" or "substring" means the strict words missed and a looser pass filled in — recall, not confirmation. - Dates here filter, they do not rank. For "what changed lately" use list_notes, which sorts by recency; it is also how you browse by folder or tag, since a query is required here. - `has_more` with `next_offset` pages the results.
| Name | Type | Req | Description |
|---|---|---|---|
| created_after | string | – | ISO timestamp — only notes created at or after this |
| created_before | string | – | ISO timestamp — only notes created at or before this |
| explain | boolean | – | Include raw per-arm scores and created_at for debugging ranking |
| folder_id | string | – | Restrict to notes in this folder itself, not its subfolders |
| folder_path | string | – | Same restriction by path (e.g. "Projects/Kybase") instead of UUID — that folder itself, not its subfolders |
| limit | integer | – | Hits per page. Prefer has_more with offset over asking for one large page |
| offset | integer | – | Skip this many hits — with has_more in the response, how you read past the first page |
| query | string | yes | What to look for: words or a question for hybrid/semantic, an exact identifier, path or phrase for type "text" |
| rerank | boolean | – | Set false to skip the cross-encoder and answer from the fused order — several times faster, and not measurably worse. Applies to type "hybrid" only: text and semantic never rerank, and this flag chan… |
| tag | string | – | Restrict to notes with this tag |
| type | string | – | "hybrid" fuses keyword and meaning-based matching and is the right default; "text" is keyword-only and exact; "semantic" is meaning-only |
| updated_after | string | – | ISO timestamp — only notes whose own content actually changed at or after this |
| updated_before | string | – | ISO timestamp — only notes whose own content actually changed at or before this |
No output schema declared.
No examples provided.
update_folder ~125
Rename a folder and/or move it under a different parent (set parent_id to null for top level). Provide at least one of name/parent_id. The response includes the resolved `path` so a rename or move can be confirmed without a follow-up list_folders call.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | UUID of the folder to rename or move |
| name | string | – | New name. Must stay unique among this folder's siblings |
| parent_id | – | – | New parent folder UUID; null moves it to the top level. Moving a folder into its own descendant is refused |
No output schema declared.
No examples provided.
update_note ~261
Update note fields. Re-embeds if title or content changed. Updates wikilinks if title changed. The server instructions' wikilink and tag rules apply when substantially rewriting — in particular, call list_tags before coining a new tag. Pass expected_updated_at (the updated_at you read) to be refused instead of overwriting a change made in between.
| Name | Type | Req | Description |
|---|---|---|---|
| content | string | – | Replaces the whole body. To add to a note use append_to_note, to change part of one use replace_in_note — both leave the rest untouched |
| expected_updated_at | string | – | ISO updated_at from when you read the note; refuses the write if it changed since |
| folder_id | – | – | Move the note to this folder; null moves it to the vault root. Omit to leave it where it is |
| id | string | yes | The note's UUID. Live notes only; a note in the trash has to be restored before it can be edited |
| tags | array | – | Replaces the entire tag list — anything left out is removed. To add one tag, send the existing tags plus the new one |
| title | string | – | New title. Renaming rewrites every [[link]] pointing here in other notes |
No output schema declared.
No examples provided.
What is the Kybase MCP server?
Kybase is an MCP server listed in the public MCP registry as io.github.Kyrzin/kybase. Self-hosted Markdown memory for AI agents: notes you can read and edit, with hybrid search. This page covers its npm package (kybase-mcp).
Is the Kybase MCP server safe to use?
Kybase scores 68 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 26 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the Kybase MCP server expose?
Kybase exposes 18 tools: list_notes, get_note, create_note, update_note, append_to_note, and 13 more. Their descriptions and schemas cost roughly 4,167 tokens of context every time the server is loaded.
Is the Kybase MCP server still maintained?
Kybase is still listed as active in the MCP registry. We last reached this channel on 26 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the Kybase MCP server under?
Kybase declares the AGPL-3.0-only licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.