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 runs | Address |
|---|---|
| Installed from the Hub app store | http://companion-memory.localhost/api/mcp |
| Same, by LAN IP | http://<appliance-ip>:<allocated-port>/api/mcp |
| Tunnel or custom domain | https://<your-domain>/api/mcp |
| Standalone, from Memoryβs own compose | http://<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 sent | Companion Memory | Companion Hub |
|---|---|---|
POST /mcp | 405 | 404 |
POST /api/mcp, no key | 401 | 401 |
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 listfor Hub, Settings β API Keys for Memory. - The Hub key lacks the
mcpscope. Hub resolves the token and its scope in a single step, so a scope failure comes back as401 Invalid API keyβ the same answer as an unknown key, and not the 403 you would get from Memory.cihub api-key listshows 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 acceptsx-api-keytoo, 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.)
| Calling | Needs |
|---|---|
/api/mcp | MCP |
| the intent catalog | Intents |
/api/memory/* | Memory |
/api/graphql, bulk ingest, files | no 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 key | Capability | Tools returned |
|---|---|---|
MCP only | any | none β -32601 on tools/list |
MCP + Intents | write | 11 |
| No scopes selected | read | 65 |
| No scopes selected | full | 137 |
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 atoolscapability andtools/listanswers-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 400Strict 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.