Skip to Content

Connection Troubleshooting

Organized by what you observe, because the symptom rarely names the cause. Every entry here was reproduced against a live appliance.

Connection refused, or the request just hangs

Nothing is listening on that port β€” almost always because a port was assumed rather than looked up. It hits both servers, for different reasons.

Companion Hub, over a public URL or VPN. 5002 is a real, fixed port, but it is only in the URL when you are talking to it directly β€” on the LAN or across a VPN such as Tailscale. Reached by its public URL or tunnel, Hub answers on 443 as https://<your-hub-domain>/api/mcp, with no port at all: that route enters through cloudflared and is served by the appliance’s Traefik on port 80. Appending :5002 to a tunnel origin is a connection error. See Find your address.

Companion Memory, on any install. Here the port is not fixed at all.

8642 is the port inside Companion Memory’s container. When Hub installs it from the app store, Hub publishes it on a host port it allocates itself β€” a different number on every appliance β€” so 8642 is not reachable from your machine on a typical install. Hub’s own 5002, by contrast, is fixed and can be relied on.

Use whichever of these matches your install:

How Memory runsAddress
Installed from the Hub app storehttp://companion-memory.localhost/api/mcp
Same, by LAN IPhttp://<appliance-ip>:<allocated-port>/api/mcp
Tunnel or custom domainhttps://<your-domain>/api/mcp
Standalone, from Memory’s own composehttp://<host>:8642/api/mcp

.localhost is Hub’s default local domain; substitute yours if you set LOCAL_DOMAIN.

The Hub dashboard’s Companion Memory tile carries the right address, and Open on local network gives the LAN form with the allocated port already in it. See Find your address.

A refused connection is not an auth problem β€” if you are getting one, the key is not yet involved.

405 Method Not Allowed, or 404 Not Found

The path is wrong. Companion Hub and Companion Memory serve MCP at /api/mcp, not /mcp.

The two servers report the same mistake differently, which is worth knowing before you conclude one of them is down:

You sentCompanion MemoryCompanion Hub
POST /mcp405404
POST /api/mcp, no key401401

Memory’s 405 is the more misleading of the two β€” it reads like the service is refusing your request method, when in fact its gateway routes ^/api/mcp only and the request never reached the MCP server.

401 with a key attached

One of four things:

  • The key is unknown or revoked. Confirm it exists β€” cihub api-key list for Hub, Settings β†’ API Keys for Memory.
  • The Hub key lacks the mcp scope. Hub resolves the token and its scope in a single step, so a scope failure comes back as 401 Invalid API key β€” the same answer as an unknown key, and not the 403 you would get from Memory. cihub api-key list shows each key’s scopes.
  • You sent it to the wrong server. Hub keys and Memory keys are not interchangeable, and the error is the same either way.
  • You used the wrong header on Hub. Hub accepts only Authorization: Bearer. Memory accepts x-api-key too, so a config that works against Memory will 401 against Hub if it uses that header.

403 β€” Companion Memory only

Only Companion Memory answers 403. The key is valid, but its scopes do not cover the surface you are calling. Enforcement is deny-by-default: only three surfaces declare a scope, and a key with any scope ticked is refused on every route that declares none. (Companion Hub never returns 403 for a scope problem β€” see the 401 entry above.)

CallingNeeds
/api/mcpMCP
the intent catalogIntents
/api/memory/*Memory
/api/graphql, bulk ingest, filesno scopes ticked at all

A key minted for MCP connects fine and returns 403 on every memory REST call. These are separate scopes, and needing both is normal β€” see Get Your API Keys.

If a key that holds MCP + Intents + Memory still 403s, check whether the surface is one of the undeclared ones in the last row β€” those are reachable only by an unscoped, full-access key.

On Companion Hub the equivalent failure is a 401, not a 403 β€” a key that lacks the mcp scope is rejected by the MCP auth guard rather than by a separate scope check.

Connected, but zero tools

The most common problem in this whole section, and it is not a fault.

A Companion Memory key with MCP but not Intents authenticates, opens a session, and advertises nothing. Depending on your client you will see an empty tool list, or tools/list answering -32601 Method not found.

Measured on a live Companion Memory instance. Both axes move the count, but scopes do the heavier work β€” they decide which families are registered at all, and capability then filters whatever survived:

Scopes on the keyCapabilityTools returned
MCP onlyanynone β€” -32601 on tools/list
MCP + Intentswrite11
No scopes selectedread65
No scopes selectedfull137

Read down one column at a time. Both variables change between rows, so the numbers are not comparable across rows β€” the write row returns fewer tools than the read row below it because its scopes differ, not because write sees less than read. Holding scopes fixed, full βŠ‡ write βŠ‡ read always.

Scopes do two separate things, which is why that 11-versus-65 gap is so much larger than a capability change could explain:

  • No Intents β†’ no tools at all. Nothing is registered, so the server never advertises a tools capability and tools/list answers -32601.
  • Any scope ticked β†’ no graph tools, ever. A key with any scope is scope-limited and is confined to the native intent tools. The much larger family generated from the GraphQL schema is withheld from it at every capability, because those tools run against resolvers a scope-limited key is denied anyway.

Treat these as illustrative rather than exact: the intent catalog grows with what you have installed, and these are Memory’s numbers β€” Companion Hub advertises its own, smaller set.

Fix: mint a key with both MCP and Intents.

Fewer tools than you expected

Your key’s capability is filtering the list. A read key sees only tools it could actually call; a write key sees everything except destructive ones.

This is working as intended β€” it stops the agent burning a turn on a tool that was always going to be refused. If you want more, see Choosing a capability.

Alternating success and empty-bodied 400

Every second request fails, with a 400 carrying no body at all:

200 400 200 400 200 400

Strict alternation, unaffected by delays between requests. This is a gateway defect, not a client problem β€” no config change will help.

Test for it with ten requests, not one. A single successful initialize proves nothing here, and the handshake tends to fail at the second step, making it look like notifications/initialized or tools/list is unsupported when the connection was simply dropped underneath it.

Fixed in Companion Memory v2026.7.30 β€” upgrade. If you cannot upgrade immediately, retrying works β€” the failures observed were strictly alternating, so a second attempt succeeded every time.

tools/list returns -32601 Method not found

Not a missing method, and β€” on Companion Memory β€” almost always one cause: your key lacks Intents, so nothing was ever registered for tools/list to return. See the scope trap.

A lost session is not the explanation, even though it looks like a candidate. Neither server reports one this way: both answer 404 with -32001 Session not found. If you are getting -32601, the session is not the problem and re-running initialize will not help.

The agent connected but does not remember anything

Working as designed, and the most common surprise with this setup.

MCP provides tools. It does not provide passive turn capture or automatic context injection β€” those come from a memory-slot provider, which is a separate mechanism. Over MCP alone, your agent has to call a memory tool during a conversation for anything to be stored, and saying so in its system prompt is usually enough.

If you want capture to happen on its own, that provider is published for both agents: OpenClaw, Hermes. See also Beyond MCP: first-class memory.

If it is installed and still nothing accumulates, the cause is usually one of a short list β€” each agent’s page ends with them. The one to check first, on either agent: the key’s scopes and capability. The provider talks REST, so its key needs the Memory scope at Read & write β€” an MCP-scoped or Read-only key is refused on every capture, silently, while every setup check passes. On OpenClaw the other usual answer is hooks.allowConversationAccess missing from the plugin’s entry: you get the tools, and nothing is captured.

A browser-based client cannot connect

Companion Memory sends no CORS headers at all, so a browser cannot call it β€” no client-side change fixes that. Use a server-side or CLI client.

Companion Hub is the exception, and not in a way you should rely on: its CORS layer reflects any http://localhost:<port> or http://127.0.0.1:<port> origin, with credentials allowed. A browser tool served from localhost can therefore reach /api/mcp β€” and so can any other page on any localhost port. Treat that as a reason to keep the endpoint off untrusted machines, not as a supported integration path.

Still stuck

Take the client out of the picture and test the server directly with curl. That single step separates β€œmy config is wrong” from β€œmy key is wrong” faster than any amount of reading logs.

Last updated on