twin memory

MCP

The memory tools over the Model Context Protocol, at one URL, with the same key and end-user header as the HTTP routes.

POST /v1/mcpAuth: read key; write key for memory_addCost: memory_search one model call; the others none

/v1/mcp speaks MCP over Streamable HTTP. Each request is one JSON-RPC 2.0 message, and each answer is plain JSON; it never opens an SSE stream. No session is minted, so no Mcp-Session-Id is sent or needed, and a request needs nothing from the last. GET and DELETE /v1/mcp answer 405. To connect a client such as Claude Code or Cursor, see MCP; this page is the wire format.

The end user is fixed by the X-Twin-Account header. No tool takes an account argument, so a model using these tools cannot reach another end user's memory.

Headers

Authorizationstringrequired

Bearer tm_…. A read key lists the read tools. A read and write key also lists memory_add.

X-Twin-Accountstringrequired

The end user whose memory the tools read. See End users.

Content-Typestringrequired

application/json.

MCP-Protocol-Versionstring

One of the versions below. Absent, it is read as 2024-11-05, the oldest served.

Methods

initializemethod

Answers with the server's capabilities (tools) and the protocol version. Supported versions: 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05; any other asked for is answered with 2025-11-25.

pingmethod
Answers {}.
tools/listmethod
The tools this key may call, each with its input schema.
tools/callmethod

{name, arguments}. Runs one tool. The result is {content: [{type: "text", text}], isError: false}, where text is the JSON the matching HTTP route returns. A tool that ran and could not answer, such as an end user with no memory yet, answers isError: true with the reason as text.

A notification, a message with no id, is answered 202 with no body. A JSON array of messages (a batch) is refused with 400: one message a request.

The server lists eight read tools for every key, and memory_add for a key that writes. memory_search can make one model call; the others make none.

Tools

memory_searchtool
{query, before?, after?, scope?}. As /memory/search.
memory_greptool
{pattern, scope?, limit?}. As /memory/grep.
memory_readtool
{path}. As /memory/read.
memory_lstool
{path?}. As /memory/ls.
memory_aroundtool
{passage_id, width?}. As /memory/around.
memory_latesttool
{k?, place?, after?, before?}. As /memory/latest.
memory_historytool
{subject, attribute?}. As /memory/history.
memory_overviewtool
No arguments. As /memory/overview.
memory_addtool
{items, wait?}, the same body as /memory/add. Listed only for a key that writes.

The arguments and bounds of each tool are in the tools reference. memory_recall, memory_lessons, memory_how_they_work and memory_next are not served here; the local stdio server lists them.

Errors

400bad request

X-Twin-Account is missing or not a usable id; an MCP-Protocol-Version not served here; a body that is not JSON (-32700); or a batch (-32600).

401unauthorized

The bearer is not a key this service issued.

403forbidden

An Origin header naming a host other than the one the request was sent to (-32600).

405method not allowed

A GET or a DELETE.

-32700JSON-RPC

The body is not JSON. Sent with a 400.

-32600JSON-RPC

The message is not a JSON-RPC 2.0 request.

-32601JSON-RPC

No such method.

-32602JSON-RPC

No such tool, or its arguments failed validation. data holds the details.

-32603JSON-RPC

The tool failed.

Request
curl https://api.twinmemory.dev/v1/mcp \
  -H "Authorization: Bearer $TWIN_MEMORY_API_KEY" \
  -H "X-Twin-Account: user_42" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": 2,
    "method": "tools/call",
    "params": {
      "name": "memory_search",
      "arguments": { "query": "Porto", "after": "2026-10-01" }
    }
  }'
200 OK
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"query\": \"Porto\", \"found\": 1, \"hits\": [{\"path\": \"passages/memory/documents/th_a4c4bfb9e995f6bc/p_0001.md\", …}]}"
      }
    ],
    "isError": false
  }
}
initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {},
    "clientInfo": { "name": "my-agent", "version": "1.0" }
  }
}
200 OK
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": { "tools": { "listChanged": false } },
    "serverInfo": { "name": "twin-memory", "version": "0.3.0" }
  }
}