Kybase
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Kybasesearch my notes about meeting notes"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Your AI agent forgets everything between sessions. Kybase fixes that: a
self-hosted Markdown knowledge base you browse and edit in the browser,
that any MCP-speaking agent — Claude, Cursor, Windsurf — uses as
persistent memory over MCP. The agent writes notes as
you work, links them with [[wikilinks]], and finds them again next session —
no re-onboarding, no lost decisions.
Everything runs on your machine via Docker: PostgreSQL for notes, pgvector + Ollama for embeddings. No SaaS, no accounts, private by default (see Switching Embedding Providers for the trade-off if you opt into a cloud embedding provider).
Why Kybase? · Quick Start · Environment variables · Connect an MCP Client · Stack · Switching Embedding Providers · Export & Import · Sharing · Backups · Upgrading · Local development · 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:
MCP-native — 17 tools (
search_notes,get_notewith optional wikilink resolution,get_graph,get_backlinks,append_to_note,replace_in_note,indexing_status, CRUD for notes/folders) over Streamable HTTP, with instructions that teach the agent to interlink notes properlyLocal semantic search — pgvector + Ollama embeddings, private by default; hybrid RRF fusion with bilingual full-text search and chunked, excerpt-based results
Agent-friendly graph — explicit wikilink edges plus semantic edges computed from embedding similarity, so the agent discovers related notes that were never linked
A real notes app, not a black box — web editor with backlinks, graph view with a similarity slider, workspace focus mode; renaming a note rewrites its wikilinks everywhere
Zero external services — app, Postgres+pgvector, and Ollama in one compose file; single-secret auth, revocable per-client OAuth tokens for MCP
Related MCP server: Cairn MCP Server
Quick Start (Docker)
git clone https://github.com/Kyrzin/kybase.git
cd kybase
cp .env.example .env
# edit .env: set KYBASE_SECRET (openssl rand -hex 32)
docker compose pull && docker compose up -dThis 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.
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.
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 |
| (required) | UI login password and MCP/API bearer token. Generate with |
| claude.ai's connector callback | Comma-separated extra OAuth |
|
| Host port the app is exposed on. |
| (required) | Postgres is only reachable inside the compose network, but |
|
| Prebuilt image tag from |
|
|
|
|
| Point at an external Ollama instance instead of the bundled container. |
|
| Or |
| (empty) / | Only used when |
| (empty) | Only used when |
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.
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>"
}
}
}
}MCP tools (17)
Tool | Category | What it does for the agent |
| Search | Hybrid RRF search (pgvector + bilingual FTS); |
| Read | Fetch a note by id or fuzzy title; windowed for large notes, with a heading outline. |
| Read | Newest-first listing, filterable by folder/tag/updated date |
| Read | All tags in use with counts, so the agent reuses existing tags instead of coining duplicates |
| Read | Flat folder list for reconstructing the tree |
| Graph | Notes that link to a given note via |
| Graph | The knowledge graph — wikilink edges plus semantic edges — scoped by folder or by hop count from a root note |
| Write | Create a note; embedding is generated automatically in the background |
| Write | Update fields; supports |
| Write | Insert text at a note/section boundary ( |
| Write | Find-and-replace exact text; refuses unless the match count equals |
| Write | Soft-delete; recoverable with |
| Write | Undo |
| Organize | Create a folder, optionally nested |
| Organize | Rename or move a folder; refuses a move that would create a cycle |
| Organize | Delete a folder and its subtree; every note inside is soft-deleted along with it |
| 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.
On search results. Kybase doesn't grade a hit's confidence — relevance
only orders a response against its own best hit, it isn't a probability.
What it does decide is whether to answer at all: a semantic hit below the
active model's threshold isn't returned, so an empty result means "nothing
close enough," not "nothing matched." exact:true means the query is a
literal substring of the note, nothing softer. When a hit's section is
set, get_note(section:) reads just that part instead of the whole note —
cheaper, and usually all an agent needs.
Stack
Layer | Tech |
Frontend | Next.js App Router, React 19 |
Database | PostgreSQL 16 + pgvector (direct |
Embeddings | Ollama |
Search | RRF hybrid: pgvector HNSW cosine + bilingual FTS |
MCP |
|
Auth |
|
Switching Embedding Providers
You can switch the embedding provider (between local Ollama, Google, or OpenAI) and trigger re-indexing directly in the browser:
Open the settings modal in the web UI.
Select your provider, add the API key if needed, and click Save & Apply (switching the provider automatically re-indexes every note).
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.
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 (Google,
multilingual) — for multilingual vaults (e.g. Russian/German) set the Ollama
model to embeddinggemma; it separates relevant from irrelevant notes far
better than English-centric models. nomic-embed-text is a smaller,
English-leaning alternative. Models Kybase has measured (embeddinggemma,
nomic-embed-text, Google's text-embedding-004) ship with their own
similarity threshold, so switching between them needs no manual tuning —
see lib/embeddings.ts for which models are profiled. An unmeasured model
runs semantic search with no threshold at all rather than a guessed one;
indexing_status reports this, and you can supply your own via the
embeddingBands setting.
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.
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 --buildMigrations 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 checkLicense
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)
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Self-hosted AI-native knowledge workspace with hybrid search, GraphRAG, and MCP.
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Persistent memory for AI agents. Semantic search, memory graph, W3C DID identity.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceA self-hosted Markdown knowledge base and Agent Harness with an MCP server that enables AI agents to read and write notes, providing persistent memory and a shared workspace for multi-agent collaboration.1MIT
- AlicenseNot gradedqualityFmaintenanceA self-hosted persistent memory platform for AI agents and humans offering tools for memory storage, search, beliefs, work management, and code intelligence via MCP.7GPL 3.0
- AlicenseNot gradedqualityDmaintenanceSelf-hosted personal knowledge base with semantic search, enabling AI agents to capture, search, and manage thoughts using PostgreSQL with pgvector.14ISC
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to persist, search, and evolve knowledge through a Markdown vault with a typed knowledge graph and MCP interface.14Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kyrzin/kybase'
If you have feedback or need assistance with the MCP directory API, please join our Discord server