Troubleshooting Guides
These guides cover common issues encountered while operating an AI Gateway (MCP Gateway) deployment. Each entry lists the Symptom you'll observe, the likely Cause, and the Fix to apply.
Quick reference
Match what you're seeing to jump straight to the fix. See Log Events for the full event reference.
| Symptom | Guide |
|---|---|
GUARD_JWT_AUTHORIZATION_FAILED | Why do tool calls fail with an authorization error? |
BINDING_MCP_AUTHORIZATION_FAILED | See Log Events |
New upstream's tools missing from tools/list | Why don't a new upstream's tools show up in tools/list? |
| Tool call routes to the wrong upstream, or doesn't route at all | Why does a tool call route to the wrong upstream, or fail to route at all? |
BINDING_MCP_SESSION_CLOSED | Why did a client's MCP session close unexpectedly? |
BINDING_MCP_ELICITATION_TIMEOUT | Why did an elicitation request time out? |
BINDING_MCP_HTTP_SCHEMA_ACCESSOR_UNRESOLVED | Why does an mcp-http tool call fail with "unresolved expression"? |
| Well-formed tool call or response is rejected | Why does Guardrails reject a well-formed tool call or response? |
BINDING_TCP_DNS_FAILED, BINDING_TLS_* | Why can't the gateway reach an upstream MCP server or HTTP API? |
Authentication & authorization
Why do tool calls fail with an authorization error?
Symptom: Zilla raises GUARD_JWT_AUTHORIZATION_FAILED.
Cause: the gateway enforces auth once, at the http server route in front of the mcp binding, using the JWT Bearer flow. The logged reason narrows down the cause: an invalid alg or unknown key, a signature that doesn't verify, an expired token, or an issuer or audience that doesn't match the guard's configuration.
Fix: compare the caller's token against the guard's configured issuer, audience, and keys in zilla.yaml.
Discovery & routing
Why don't a new upstream's tools show up in tools/list?
Symptom: a newly added upstream's tools are missing from tools/list.
Cause: two independent things have to be true after adding an upstream: the route has to exist, and the listing cache has to have picked it up.
Fix: check both things that have to be true for a tool to appear:
- Confirm the new upstream has both a binding (an
mcp · clientormcp-http · proxy) and a matching route onmcp · proxy, keyed bytoolkit. A binding with no route, or a route with the wrongtoolkitvalue, never gets aggregated intotools/list. - If the route is correct but the tool still doesn't appear, the merged listing may simply be serving a cached response from before the upstream was added. The cache TTL defaults to
PT5M(5 minutes); wait for it to expire, or restart the gateway to force a refresh.
Why does a tool call route to the wrong upstream, or fail to route at all?
Symptom: a tool call is routed to the wrong upstream, or gets no route.
Cause: Toolkit routing matches on the toolkit prefix of the tool name, using the <toolkit>__<tool> convention (for example bluesky__get_weather routes on toolkit: bluesky). This happens when the prefix the agent sends doesn't match any configured routes[].when[].toolkit value.
Fix: check the exact toolkit name configured on each route against what the agent is actually calling, since this comparison is exact, not a partial or case-insensitive match. If two upstreams are meant to share one toolkit name, only the first matching route is ever taken.
Sessions & elicitation
Why did a client's MCP session close unexpectedly?
Symptom: Zilla raises BINDING_MCP_SESSION_CLOSED, sometimes paired with a BINDING_MCP_SESSION_ESTABLISHED shortly after on a reconnect.
Cause: in a horizontally scaled deployment (see Scale MCP Gateway), there are no sticky sessions by design, a client's connection can land on a different replica after a reconnect, closing the session the previous replica held. Outside that pattern, frequent open/close pairs usually point at the client not keeping its connection alive, an idle timeout between the client and the gateway, or a load balancer resetting the connection.
Fix: if the gateway is running multiple replicas, confirm this isn't just expected reconnect behavior under a load balancer before treating it as a fault. Otherwise, check the client's keep-alive behavior and any idle-timeout configuration in front of the gateway.
Why did an elicitation request time out?
Symptom: Zilla raises BINDING_MCP_ELICITATION_TIMEOUT.
Cause: an upstream server's elicitation request went unanswered by the client past the configured timeout. This is frequently a human-in-the-loop delay, a form left unfilled, an OAuth consent screen never completed, rather than a gateway or upstream defect.
Fix: check the timeout configured under options.elicitation on the mcp · server binding, and confirm the client actually surfaced the elicitation request to the user instead of silently dropping it.
Requests & validation
Why does an mcp-http tool call fail with "unresolved expression"?
Symptom: Zilla raises BINDING_MCP_HTTP_SCHEMA_ACCESSOR_UNRESOLVED.
Cause: a ${...} accessor in the tool's HTTP request template, used to map a field from the incoming MCP tool call onto the outbound HTTP request (see HTTP APIs as Tools), didn't resolve against the tool call the agent actually sent.
Fix: check that the tool's schema declares the field the accessor points to, and that the agent's tool call actually included that field. A tool call missing an optional argument that an accessor assumes is present is the most common cause.
Why does Guardrails reject a well-formed tool call or response?
Symptom: a tool call or response that looks well-formed is rejected.
Cause: a Guardrails model configured on the http binding's request or response content rejects a payload when it doesn't match that model, for example a content.model: json field rejecting a request body that isn't valid JSON, or a schema-backed model (avro, protobuf) rejecting a payload that doesn't conform to the schema resolved from its catalog.
Fix: check the exact model and, if configured, catalog on the matching requests[]/responses[] entry in the http binding against the payload the agent or upstream actually sent. See Validate for the full configuration shape.
Connectivity
Why can't the gateway reach an upstream MCP server or HTTP API?
Symptom: BINDING_TCP_DNS_FAILED if the upstream hostname doesn't resolve, or one of the BINDING_TLS_* events if the TLS handshake fails.
Cause: both mcp · client and mcp-http · proxy exit over tcp, and usually tls, to reach an upstream. See the full event reference for every connectivity event.
Fix: confirm the upstream hostname and port in the client or proxy's options are reachable from the gateway, and that the upstream's certificate is trusted if TLS is in the path.
Log Events
Named events raised by the mcp and mcp-http bindings show up in the log format as <event name> - <details>. For events raised by the surrounding tcp, tls, http, and guard bindings in an AI Gateway pipeline, see the full event reference.
The mcp binding defines four named events of its own, in addition to being instrumented through the mcp.* metrics (mcp.initialize, mcp.tools.list, mcp.tools.call, and their .duration histograms):
| Event | What to check |
|---|---|
| BINDING_MCP_AUTHORIZATION_FAILED | An authorization failure raised by the mcp binding itself. Compare against GUARD_JWT_AUTHORIZATION_FAILED above to see whether the guard or the mcp binding rejected the request. |
| BINDING_MCP_SESSION_ESTABLISHED | An MCP session was established. Expected on every new client connection; see Why did a client's MCP session close unexpectedly? if it's paired with an unexpected close. |
| BINDING_MCP_SESSION_CLOSED | See Why did a client's MCP session close unexpectedly? |
| BINDING_MCP_ELICITATION_TIMEOUT | See Why did an elicitation request time out? |
The mcp-http binding, used when an mcp · proxy maps MCP tool calls onto HTTP requests, raises one event of its own:
| Event | What to check |
|---|---|
| BINDING_MCP_HTTP_SCHEMA_ACCESSOR_UNRESOLVED | A ${...} expression accessor referenced by a tool's HTTP request template could not be resolved against the incoming tool call. Check that the tool's schema declares the field the accessor points to and that the caller actually supplied it in the request. |

