Agent integration · MCP
MCP server
MCP (Model Context Protocol) is an open protocol that lets an AI agent call tools exposed by a local process over a transport such as stdio. Pointed at a keepsake vault, the keepsake MCP server gives an agent recall, write, and verify access to your memory without a vendor holding it.
Run the server
The server is a subcommand of the same keepsake binary. It takes the vault path from --vault and the passphrase from KEEPSAKE_PASSPHRASE; there is no passphrase flag. It reads the passphrase once at startup, so an unset variable is an error rather than a prompt.
# passphrase from the environment, vault from --vault$ KEEPSAKE_PASSPHRASE='correct horse battery staple' keepsake mcp --vault memory.keepsake# the server then speaks newline-delimited JSON-RPC 2.0 on stdio
The server makes no network calls. The vault is opened in process and decrypted on each tool call, so the plaintext is never held by a service. The only method it answers beyond tools/list and tools/call is initialize, notifications/initialized, and ping.
Configure a stdio client
Add the server to an MCP client's configuration. The passphrase belongs in the env block of the server entry, never in args.
{
"mcpServers": {
"keepsake": {
"command": "keepsake",
"args": ["mcp", "--vault", "/home/you/memory.keepsake"],
"env": { "KEEPSAKE_PASSPHRASE": "…" }
}
}
}
If you have not installed the binary globally, run it through Bun instead. This is the same server with the same arguments:
{
"mcpServers": {
"keepsake": {
"command": "bunx",
"args": ["github:srivtx/keepsake#main", "mcp", "--vault", "/home/you/memory.keepsake"],
"env": { "KEEPSAKE_PASSPHRASE": "…" }
}
}
}
The env value is visible to the client process. Use a secret manager or an OS keychain to fill it where you can, keep the config file out of version control, and never move the passphrase into args.
The tools
The server exposes six tools: four to read and two to write. Names and parameters are case-sensitive.
| Tool | Parameters | What it returns |
|---|---|---|
memory_recall |
query (string, required); size (integer, optional, 1–50, default 5) |
Ranked BM25 matches, one per blank-line-separated block, as n. [source · createdAt] text. Returns a "No memories matched" line when nothing matches. |
memory_remember |
text (string, required); tags (array of string, optional) |
Appends one cell with source mcp and role note, rewrites the vault, and returns Stored memory <id> (vault now holds N cells). |
memory_context |
task (string, required); budgetTokens (integer, optional, 100–20000, default 1500) |
A token-budgeted Markdown context pack for the task — the same pack as keepsake context. It is transient and never written to disk. |
memory_forget |
id (string, optional) or query (string, optional); at least one required |
Removes matching cells by exact id or by search query, rewrites the vault, and returns Forgot N memory(ies); M remain. or No memories matched. |
memory_stats |
none | The cell count, plaintext byte size, sources with counts, and tags with counts. |
memory_verify |
none | ok — N cell(s), Merkle root <root>, after re-checking every cell hash and the Merkle root. |
The two writing tools rewrite the vault file in place. They preserve the iteration count already stored in the vault, and they fail if the file is not writable or the passphrase is wrong. Recall, stats, and context read and decrypt the vault on every call.
memory_context or memory_recall?
They answer different questions. memory_recall takes a search query and returns the handful of cells that match it, so an agent can cite specific memories. memory_context takes a task and returns one assembled Markdown block sized to a token budget, so an agent can drop a bounded slice of memory straight into a prompt.
Use memory_context when you are about to give the model background for a job — it spends at most budgetTokens and, when nothing matches the task, falls back to the most recent cells (up to 50) instead of coming back empty. Use memory_recall when you want the top matches for a specific query, with their scores implied by rank. Both are lexical BM25; neither uses embeddings.
Troubleshooting
- The client reports the server exited immediately.
KEEPSAKE_PASSPHRASEwas not set for that process. The error isno passphrase: set KEEPSAKE_PASSPHRASE in the environment (keepsake never takes it as an argument). - Every call fails with a vault error. Confirm the passphrase with
KEEPSAKE_PASSPHRASE='…' keepsake verify --vault memory.keepsake. A wrong passphrase and a corrupt or truncated vault report the same failure by design. - No tools appear. Make sure the client can spawn the command — a bare
keepsakemust be on the client'sPATH, or use thebunxform above. The server advertises its tools overtools/listat protocol version2024-11-05. - Writes do nothing.
memory_rememberandmemory_forgetrewrite the vault file, so the path must be writable by the server process. A read-only file or a directory the process cannot write fails the call. - Recall misses a memory you know is there. The CLI and MCP server use lexical BM25 only; the on-device semantic model is a browser-app feature. Try the words that actually appear in the cell, or check the vault with
memory_stats. - An agent seems to use stale memory. Each read decrypts the vault fresh, so the file is current; the stale copy is usually in the agent's own context. Restart the conversation or re-issue the call.