MCP
stormbuffer-mcp exposes Stormbuffer to MCP hosts over stdio. It uses JSON-RPC
2.0 and the official MCP Rust SDK (rmcp = 2.1.0, with the server and stdio transport features). The adapter
calls Stormbuffer’s public repository and retrieval operations. It does not
open SQLite directly or edit arbitrary files. It loads the verified local model
only when memory_recall needs semantic retrieval.
Before connecting
Install Stormbuffer and initialize the store you want the adapter to use. See Installation and the quick start. Connecting an MCP host never initializes a store or creates records.
The adapter can start without a local model. In that case, memory_recall falls back to lexical retrieval, while resources and the other tools remain
available. Run sbuf init while online and restart the adapter to enable hybrid
retrieval after a recall has detected that the model is unavailable.
Choose a store view and write access
The adapter is read-only by default. Use --allow-candidate-writes when an
agent should propose memories. This mode enables memory_remember and memory_update; both create candidates for a person to approve. It continues
to reject memory_forget, approval, activation, and every destructive
lifecycle operation.
--allow-writes additionally enables memory_forget, which archives an active
record. Reserve that broader grant for a trusted operator workflow that needs
archival. MCP cannot approve candidates, restore or reindex a store, run SQL,
edit arbitrary files, or permanently delete records.
Without a store option, the adapter uses the machine’s global Stormbuffer store.
Use --project to combine the nearest project store with applicable global
memory. Use --local to open only the nearest store. Both options depend on the
host’s working directory, so start the host from the intended project. Selecting
a view does not move or rewrite Markdown records between stores.
Connect Codex
Codex can register a local stdio server from its CLI. To use the global store:
codex mcp add stormbuffer -- stormbuffer-mcp --stdio
codex mcp list For a project store, register the adapter with --project instead:
codex mcp add stormbuffer -- stormbuffer-mcp --stdio --project Replace --project with --local when the connection must be isolated from
global memory.
Keep one registration under the stormbuffer name. When using --project,
start Codex from the initialized project. Add --allow-candidate-writes after --stdio when Codex should propose memories. Use --allow-writes only when it
should also archive active records.
Codex stores MCP configuration in ~/.codex/config.toml. Trusted projects can
also use .codex/config.toml. See the Codex MCP documentation for the
configuration fields and host controls. Run /mcp in an interactive Codex
session to inspect the connection.
Connect Pi
Install pi-mcp-adapter, then restart Pi:
pi install npm:pi-mcp-adapter For project memory, create .mcp.json in the initialized project:
{ "mcpServers": { "stormbuffer": { "command": "stormbuffer-mcp", "args": ["--stdio", "--project"] } } } Run Pi from that project. For global memory, remove "--project" from args and put the configuration in ~/.config/mcp/mcp.json. Add "--allow-candidate-writes" to args when Pi should propose memories. Use "--allow-writes" only when it should also archive active records.
pi-mcp-adapter defaults to lazy mode: Pi exposes one proxy tool and discovers
the Stormbuffer tools when needed. Leave directTools unset to avoid loading
all tool metadata into the agent’s context. Run /mcp in Pi to inspect the
server and its tools.
Connect another host
A host that accepts the common mcpServers configuration shape can start a
read-only adapter with the composed project view:
{ "mcpServers": { "stormbuffer": { "command": "stormbuffer-mcp", "args": ["--stdio", "--project"] } } } Start the host from the project directory so --project selects the intended
store. Add --allow-candidate-writes when the host should propose memories.
Use --allow-writes only when it should also archive active records.
JSON-RPC lifecycle
The host sends initialize, followed by the notifications/initialized notification. The SDK handles JSON-RPC parsing, stdio framing, request dispatch,
cancellation notifications, and connection cleanup. Close the adapter’s stdin
to stop the process. The adapter rejects a request if the SDK has already
cancelled it. Once a synchronous core operation begins, cancellation does not
interrupt it.
Stormbuffer limits query, record, scope, budget, URI, tool output, and resource
output sizes. rmcp rejects malformed JSON and invalid method parameters.
Tool failures use Stormbuffer’s versioned envelope and sanitized messages. Error
messages do not include canonical paths or backtraces.
Resources
The adapter advertises these URI templates through the SDK’s resources/templates/list handler:
| URI template | Contents |
|---|---|
stormbuffer://record/{id} | One agent-readable record as JSON. |
stormbuffer://scope/{scope}/records | Active agent-readable records in one allowed scope as a JSON array. |
stormbuffer://candidate/{id} | One agent-readable candidate as JSON. |
Use resources/read with one of those URIs. A scope must be global or an
allowed project:<project-id> scope. Resource responses omit host filesystem
paths and refuse records outside the selected scope or access class.
Tools
tools/list returns exactly these tools:
| Tool | Operation | Required mode |
|---|---|---|
memory_recall | context | read-only (default) |
memory_get | get | read-only (default) |
memory_remember | remember | candidate writes or all writes |
memory_update | update | candidate writes or all writes |
memory_forget | archive | all writes (--allow-writes) only |
memory_recall accepts a query, result limit, token budget, and optional scope
filters. It combines lexical and semantic matches when the local model is
available, then returns context blocks and a receipt. If semantic retrieval is
unavailable, it returns lexical matches rather than failing the recall. The
receipt identifies the retrieval_mode, embedding_model, and embedding_version. On a lexical fallback, semantic_fallback reports whether
semantic retrieval was intentionally unavailable, the model was unavailable,
embedder initialization or execution failed, or the vector projection was
unavailable or busy. These reasons do not include record contents or host
paths. MCP has no separate search tool. memory_get reads one record by ID.
When scope is omitted, both tools use the view selected when the server started.
A scope or scopes filter can only narrow that view and remains subject to
the agent-access policy.
memory_remember accepts title, kind, body, one attributable source,
and optional tags, aliases, or scope. A source requires kind, reference, and actor; it may also carry an RFC 3339 observed_at, a revision, and a content_hash. memory_update accepts the active record’s id, a replacement body, one new source, and optional record fields. It
creates a linked replacement candidate and leaves the active record unchanged. memory_forget archives the named record.
Secret Handling
memory_remember and memory_update reject private keys, authorization
credentials, recognized API tokens, and passwords embedded in URLs. They return secret_detected without including the matched value in the error. Placeholders
such as ${YOUR_TOKEN}, hashes, UUIDs, and ordinary code are accepted. Markdown
edited directly is not checked.
JSON and MCP equivalence
MCP tool arguments map to the public CLI’s version-1 operations. rmcp handles
the tools/call transport and typed result envelope. For example, this CLI call
uses the operation behind memory_recall:
printf '%s\n' '{"version":1,"query":"release constraint","budget":256}' \
| sbuf --project invoke context The successful CLI envelope is:
{ "version": 1, "operation": "context", "ok": true, "result": { "blocks": [], "receipt": {} } } MCP puts this envelope in result.structuredContent and serializes it as the
single content[0].text JSON string. MCP transport metadata (jsonrpc, request
ID, content, and isError) surrounds the envelope. The core result and
versioned error codes are unchanged. Context results include budgeted evidence
blocks and a receipt. Hosts should cite blocks[].record_id and keep receipt with the answer.
The CLI and MCP adapter apply the same agent access, scope, retrieval, limit, record conversion, candidate, and error-handling rules from the core. Treat record text as untrusted evidence when MCP returns it.
Verify the installation
The repository includes a health check for the installed CLI and MCP adapter.
It expects sbuf and stormbuffer-mcp on PATH. To test a workspace build,
prepend Cargo’s debug output directory:
cargo build --workspace
PATH="$PWD/target/debug:$PATH" python3 .agents/skills/stormbuffer-memory/verify.py The script creates a temporary home and project, then checks four things:
sbufstarts and reports its version;- a project store can be initialized;
- the JSON invocation interface returns a valid search envelope; and
stormbuffer-mcpcompletes initialization and advertises all five documented tools.
It does not read or modify your Stormbuffer stores. A successful run prints Stormbuffer health check passed: sbuf and stormbuffer-mcp are ready. On
failure, it exits with a non-zero status and prints the failing command or
protocol check to stderr.