# MCP Troubleshooting

Isolate where a failure lives: the management routes, the tool gateway, or the upstream service.
Start with the caller's JSON-RPC code or HTTP status, then check the server test result and the
policy state before touching credentials.

## Symptom and action table

| Symptom                                                   | Likely cause                                                                                                           | Action                                                                                                                                                                                       |
| --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `501 MCP_MANAGEMENT_UNAVAILABLE` on a management route    | The runtime did not wire the MCP management service                                                                    | Confirm the deployment includes management service and the request targets the API origin                                                                                                    |
| `403` API key missing capability                          | The key lacks `mcp:manage` or `mcp:invoke`                                                                             | Grant `mcp:manage` to management keys and `mcp:invoke` to client keys; neither ships in the default key set                                                                                  |
| `tools/list` lists only the five hosted tools             | No allow policy matches the principal, while federation tools were expected                                            | Hosted tools are pre-approved; federation tools are default-deny. Create an allow policy and confirm the upstream tools are published                                                        |
| `tools/list` returns an empty catalog                     | An explicit deny matches, or every tool is `draft` / `archived`                                                        | Remove the overriding deny; sync the server and publish eligible tools                                                                                                                       |
| `tools/call` → `-32001` permission denied                 | Adjudication denied the call: explicit deny, default deny, or a request that widened the allowed scope                 | Check policy priority and that the tool sits inside an allow scope. This is an authorization decision, not a bad credential; hosted tools still run under default-deny unless a deny matches |
| Workbench shows no primary credential or a paused primary | Credentials exist but none is active, or the primary is paused                                                         | The catalog stays editable; only invocation is blocked. Add a backup credential, isolation-test it, promote it, or resume the paused primary                                                 |
| `tools/call` → `-32001` after a previously working call   | Native MCP upstream rejected the sealed credential (`401` / `403`), or a Node OpenAPI call received a non-2xx response | Add a fresh backup credential, test it, and promote it; the outbound connection refreshes on the next call                                                                                   |
| `tools/call` → `-32601` method not found                  | The tool is `draft` or `archived`, or the built-in target is not registered                                            | Publish the tool, or confirm the built-in target id (`provon` or `duckduckgo`)                                                                                                               |
| Call rejected for a credential-shaped field               | Arguments contain a blocked key such as `authorization`, `token`, or `api-key`                                         | The sealed outbound credential is the only auth channel; move secrets out of tool arguments                                                                                                  |
| Call rejected for a byte budget                           | Arguments exceed 64 KiB, or tool output exceeds 256 KiB                                                                | Reduce argument size; oversized output is withheld rather than returned                                                                                                                      |
| `tools/call` → `-32002` rate limited                      | A fixed-window call cap was exceeded in its bucket                                                                     | Back off and retry after the window. Buckets differ by runtime; see [Security rate limits](./security.md#rate-limiting-and-concurrency)                                                      |
| `tools/call` → `-32003` upstream failure                  | Transport error, timeout, serialization failure, blocked host, or a non-2xx response on the hosted-edge OpenAPI path   | Re-run the server test; verify the sealed credential and that the upstream host is public. Native MCP `401` / `403` maps to `-32001` instead                                                 |
| `tools/call` → `-32000` session expired                   | A Node OpenAPI call could not be completed due to a transport or timeout error                                         | Retry once; persistently failing means inspect upstream reachability and the sealed credential                                                                                               |
| Server `connectionStatus` is `unreachable` after a test   | Upstream unreachable, wrong base URL, or rejected credential                                                           | Re-run the server test and read its message; a probe `401` marks the credential invalid, so test and promote a fresh secret                                                                  |
| Call blocked as a private-network target                  | Upstream host resolves to localhost, a private range, or a metadata address, or the URL carries embedded credentials   | Point the server base URL at a permitted public address; tool-call redirects are not followed                                                                                                |

## Reading the evidence

Outbound calls emit a bounded `MCP <method>` span tagged with `mcp.outcome` and
`mcp.rpcResponseStatusCode`. Start from the outcome category:

- `capability_unavailable` (`-32601`, `-32004`) — tool not published or invocable, or the project
  tool gateway is paused.
- `permission_denied` (`-32001`) — policy denied the call, the guardrail rejected arguments, or the
  upstream rejected the sealed credential on a native MCP call.
- `session_expired` (`-32000`) — Node OpenAPI transport could not complete the call; retry after
  checking reachability.
- `rate_limited` (`-32002`) — local call cap reached.
- `upstream_error` or `internal` — upstream failure, serialization error, or an output guardrail
  rejection.

Tool arguments, content bodies, upstream URLs, and secrets are intentionally absent from spans. Use
the server test result and the connection status field to inspect the exact upstream message, and
strip prompts, credentials, and personal data before sharing a trace with a support channel.
