diff --git a/README.md b/README.md index cdc2c0f2..e26f2232 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,16 @@ Dimension is detected automatically. ⚠️ Switching models changes the vector ## MCP Server -The `mcp-server/` directory contains a standalone [MCP](https://modelcontextprotocol.io) server. Any MCP-compatible client (Claude Code, OpenClaw, Cursor, etc.) connects and gets structured long-term memory. +The `mcp-server/` directory contains a standalone [MCP](https://modelcontextprotocol.io) server over stdio. + +**What is actually verified**, as of 2026-08-24, against a live backend: protocol version +`2025-06-18`; `initialize`, `tools/list` and `tools/call` all round-trip; `memory_recall` +returns real results. That is a protocol-level check run directly over stdio — not a +client-by-client compatibility matrix. + +Any client that speaks MCP over stdio should therefore work, but we have not sat in front +of each one. Listed below is the config we run ourselves (Claude Code) and no others. If +you get it working with a different client, a PR to this section is the useful kind. ### Tools @@ -139,6 +148,11 @@ The `mcp-server/` directory contains a standalone [MCP](https://modelcontextprot `memory_recall` is the only one of the five that never calls a model. `memory_reflect` is an agentic loop with repeated LLM calls — if you expose this server to anything untrusted, expose `memory_recall` alone. +One thing worth knowing before you budget context: the backend treats `limit` on recall as +a retrieval hint, not a result cap — it returns everything inside its own token budget, +around 110 facts. The MCP layer enforces your `limit` on the way out, so a `limit: 2` recall +costs about 1 KB instead of 43 KB. Recall spends no model call; it does spend context. + ### Setup ```bash diff --git a/mcp-server/server.js b/mcp-server/server.js index 8f4e7c6f..80abeef5 100644 --- a/mcp-server/server.js +++ b/mcp-server/server.js @@ -98,7 +98,10 @@ async function hindsightRequest(method, path, body = null) { const server = new McpServer({ name: 'rcll', - version: '1.0.0', + // Keep in step with package.json and server.json — the MCP registry validates + // the package it resolves against this manifest, and a version that disagrees + // with the tarball is a review failure, not a cosmetic drift. + version: '0.1.0', }); // Tool 1: memory_retain @@ -177,7 +180,7 @@ server.tool( const result = await hindsightRequest('POST', `/${bankId}/memories/recall`, body); - const memories = (result.results || []).map(r => ({ + const all = (result.results || []).map(r => ({ id: r.id || r.uuid || null, text: r.text, type: r.type, @@ -187,6 +190,13 @@ server.tool( hall: r.hall || null, })); + // The backend treats `limit` as a retrieval hint, not a result cap: it returns + // everything that fits its own token budget (~110 facts, ~40 KB of JSON) no + // matter what we ask for. Unenforced here, the tool's own description would be + // false and every recall would spend ~10k tokens of the caller's context. + const effectiveLimit = body.limit; + const memories = all.slice(0, effectiveLimit); + return { content: [{ type: 'text', @@ -194,6 +204,9 @@ server.tool( success: true, bank_id: bankId, count: memories.length, + ...(all.length > memories.length + ? { returned_of_available: `${memories.length} of ${all.length}` } + : {}), memories, }, null, 2), }],