Skip to content

Troubleshooting

The server tries to put the fix in the error text, so read the message before reaching for this page. When it does not, start here.

The server writes to stderr, and MCP clients hide stderr by default. On startup it logs:

[mero-mcp] ready on stdio; the node connects when a client opens the connection

A down node or bad credentials do not fail at startup. When the client connects, the server tries once to read the installed apps; if that fails it logs [mero-mcp] app list unavailable at connect: <error> and serves only the fixed tools until a later read reaches the node. After that a failure hits only the tool call that met it, and the next call retries. If tools fail and you cannot see why, find your client’s MCP server log (in Claude Code, claude --debug, or the MCP output panel in editors) and read the stderr.

No Calimero node found. Start one in the Calimero desktop app, or set
CALIMERO_NODE_URL. (Looked in ~/.calimero and probed local ports.)

Discovery found nothing at any rung. Either the node is not running, or it is somewhere the server does not look: a non-default CALIMERO_NODE_HOME, a port outside the probe set (2528, 2428, 2529, 2429), or a remote host. Set CALIMERO_NODE_URL and the whole search is skipped. See node discovery.

Several nodes found in ~/.calimero: alice (http://localhost:2428),
bob (http://localhost:2429). Set CALIMERO_NODE_NAME or CALIMERO_NODE_URL.

More than one node config, none of them named default, so the server refuses to guess. Name one with CALIMERO_NODE_NAME, or address it directly with CALIMERO_NODE_URL. list_nodes shows the candidates.

CALIMERO_NODE_NAME did not match a directory under CALIMERO_NODE_HOME. The error lists the available names. Note that a node directory only counts if its config.toml yields a listen address — a directory the server cannot read a port out of is skipped entirely.

This node's merod does not support the ABI endpoint

Section titled “This node's merod does not support the ABI endpoint”
This node's merod does not support the ABI endpoint
(GET /admin-api/applications/:id/abi). Upgrade merod to a release that includes it.

The whole generated-tool mechanism reads the ABI from that route. It is newer than the current merod release, so until a release carries it, build merod from core master:

Terminal window
cd core && cargo build -p merod

Every other tool works without it: only the app tools (describe_app, select_app, call and the generated tools) need an ABI. An app whose ABI cannot be read is left out of the tool list, and stderr says why.

The generated tools are listed from the moment the client connects, one per method of every installed app except init, which create_context runs. If an app was installed after that and its tools are missing, wait for the 30-second refresh or reconnect. If the node was down when the client connected, the first select_app, describe_app or call that reaches the node reads the list again, adds the app tools and starts the 30-second refresh.

select_app names the tools in its result along with a note:

These are the server-side tool names. An MCP client may expose them under a prefix of its own (commonly mcp__<server>__<tool>), so if a name does not resolve, look for the prefixed form.

Two separate things go wrong here:

  1. The name is prefixed. kv_store_get may be exposed as mcp__mero-mcp__kv_store_get. Look for the prefixed form before concluding it is missing.

  2. The client did not pick up the new tool list. Not every client refreshes on a tools/list_changed notification. The call tool exists for exactly this: it is registered at startup, so it is always visible, and it reaches every method with the same handle:

    Call the `call` tool with the app_handle, method "get" and args {"key": "greeting"}.

Call select_app for <package> and retry with the returned app_handle.

Section titled “Call select_app for <package> and retry with the returned app_handle.”

An app tool or call refused the app_handle and ran nothing. The refusal carries the app’s guide when it has one, so read it before retrying. Either the handle is missing or was not issued by this server, or it has gone stale for one of four reasons:

  1. The app was upgraded. A handle names the app version it was issued for.
  2. The app’s guide changed. A handle carries a hash of the guide it was issued with.
  3. The context is gone. The handle names a context that no longer exists for that app.
  4. The handle key changed. Handles are signed with the key in handle.key in the state directory, so they survive a restart, but not that file being deleted or replaced.

In every case, call select_app again and use the handle it returns. A handle from describe_app names no context, so app tools refuse it with a request to call select_app with a context. A handle binds one application, so the tools of the same package from another signer refuse it.

Application "x" has no contexts on this node

Section titled “Application "x" has no contexts on this node”
Application "kv-store" has no contexts on this node. Create one in the Calimero
desktop app, or use create_context.

Installing an application does not create a context. This is the single most common failure — see contexts and namespaces.

Application "x" has N contexts; pass context with one of: …

Section titled “Application "x" has N contexts; pass context with one of: …”

The application has several contexts, so select_app cannot choose one for you. Pass context to select_app; the handle it returns names that context.

The short name you used — the trailing package segment — matches more than one installed application. Use the full package name or the application id. Matching is on whole segments, so this is never a prefix collision. A display name that several installed applications carry is refused the same way.

Application "x" is published by several signers

Section titled “Application "x" is published by several signers”

The package is installed from more than one signer, and each is a separate app with its own tools and handles. The error lists each application id with its signer; pass the id of the one you mean to select_app or describe_app.

Context "x" not found: it is neither a context id nor an alias

Section titled “Context "x" not found: it is neither a context id nor an alias”

The value did not look like a base58 context id and no alias by that name resolved. The error lists the contexts that application does have. Create the alias with create_alias, or use the id.

A method call fails with the app’s own error

Section titled “A method call fails with the app’s own error”

Guest (WASM) errors arrive from the node without a readable message — just FunctionCallError and a Rust-debug-formatted byte array. The server decodes that back into the real text, so what you see is the application’s own error:

Error: label must not be empty

If you are seeing a bare FunctionCallError with no explanation, the payload was not in either shape the decoder knows, and the raw error is in the server’s stderr.

A transport failure rather than anything the node rejected — wrong port, node not listening, TLS mismatch. Confirm with node_status, and check the URL with list_nodes.

node_status reports authMode. If it says none and calls are rejected, the node wants auth and the server found no credentials. If it says handoff but the node rejects the token, the handoff file may be stale — the desktop app’s Connect AI agent action rewrites it.

The server ignores a handoff file that points at a non-loopback origin and logs why: only the local desktop app writes that file, so a remote URL in it means something else did. Use CALIMERO_NODE_URL to reach a remote node.

Tokens are cached per node and identity under the state directory. To force re-authentication, delete tokens-*.json from ~/.config/calimero/mcp (or your CALIMERO_MCP_STATE_DIR). See authentication.

Check CALIMERO_MCP_TOOLSETS. It defaults to all three, but if it is set, only the named toolsets are registered — plus core, which is always on regardless. An unrecognised name in that list simply matches nothing, silently.