Troubleshooting
What to check when twin memory's tools do not appear in an MCP client, and what each error means.
The tools do not appear
Check, in this order:
- The URL. It is
https://api.twinmemory.dev/v1/mcp, with/v1. - Both headers. Every request with a key needs
Authorization: Bearer tm_...andX-Twin-Account: <end user>. A client that sends only one is refused. claude.ai and ChatGPT sign in instead: see claude.ai and ChatGPT. - The transport. The server speaks Streamable HTTP: a
POSTper message, answered with JSON. AGETanswers405, so a client set to the older SSE transport cannot connect. Withmcp-remote, pass--transport http-only. - The client's own status. In Claude Code, run
claude mcp list. In Cursor, open the MCP settings. In VS Code, open the MCP view and the server's output.
HTTP errors
The server checks the key and the end user as the HTTP API does, before any tool runs.
| Status | Message | What to do |
|---|---|---|
400 | X-Twin-Account is required: ... | The client sent no X-Twin-Account header. Add it. |
400 | X-Twin-Account is not a usable end user id: '...' | Use letters, digits, ., _ and -, starting with a letter or digit. See End users. |
400 | MCP-Protocol-Version '...' is not spoken here | Served versions are 2024-11-05 through 2025-11-25. Update the client or let it fall back. |
401 | a bearer this service issued is required | The key is missing, mistyped or revoked. Check the Authorization header reads Bearer tm_.... |
401 | with WWW-Authenticate: Bearer resource_metadata= | A signed-in connection's token is missing, expired or no longer valid. The client refreshes it or asks to sign in. |
403 | with error="insufficient_scope" | A Read only connection called memory_add. Connect again with Read and save. |
403 | a request from another origin | A browser page on another host sent an Origin header. Call the server from your backend or a desktop client. |
405 | The client sent a GET or a DELETE. Use Streamable HTTP. |
The memory is empty, or a tool answers 404
An end user nothing was ever written for has no memory to read. Tools for that end user answer with
no memory for end user '...' yet. Add something for them with /v1/memory/add first, or check
that X-Twin-Account names the end user you meant.
Right after an add, the item can take a moment to land. Search finds it by its words once it has, and its dated
facts appear after it has been read in the background. /v1/memory/status says where each
item is.
memory_add is missing
memory_add is listed only for a read and write key, or a connection with Read and save. With a read key, or a
Read only connection, the client sees the read tools alone. This
is on purpose: see which key to give a client.
The key is sent as ${TWIN_MEMORY_API_KEY}
In Claude Code, a ${VAR} in .mcp.json that is not set is sent as written, and the server answers 401.
claude mcp list warns about it. Set the variable in the environment Claude Code starts from.
In Windsurf (Devin Desktop), an unset ${env:VAR} becomes an empty string, with the same result.
mcp-remote splits the header on Windows
Some clients, among them Claude Desktop on Windows, do not escape spaces inside args, so
"Authorization: Bearer tm_..." arrives as two arguments. Write the header without a space and keep the space in
an environment variable:
"args": ["mcp-remote", "https://api.twinmemory.dev/v1/mcp",
"--header", "Authorization:${AUTH_HEADER}",
"--header", "X-Twin-Account:user_42"],
"env": { "AUTH_HEADER": "Bearer tm_..." }JSON-RPC errors
Once a request is admitted, a problem with the message itself comes back as a JSON-RPC error:
| Code | Meaning |
|---|---|
-32700 | The message is not JSON. |
-32600 | The message is not a JSON-RPC 2.0 request. |
-32601 | No such method. The server answers initialize, ping, tools/list and tools/call. |
-32602 | No tool by that name, or the arguments do not fit its schema. data holds the details. |
-32603 | The tool failed. The message names the method and the error. |
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "memory_around: invalid arguments",
"data": [
{ "type": "less_than_equal", "loc": ["width"], "msg": "Input should be less than or equal to 5" }
]
}
}