Skip to content

Error codes and limits

A failed tool call returns a tool result with isError: true. The text content is one JSON object with error set to one of the codes below and a message of at most 500 characters. The message is safe text: it never contains a backend response, a secret or an argument value.

Code Extra fields When
unauthenticated none The call is not bound to a verified gateway request
access_denied none The user, the AI client or a policy does not allow the call
tool_disabled none An administrator disabled the tool or its server, or its definition waits for approval
not_found_or_denied none The resource does not exist, the user may not see it, or it lies outside the granted scope. One text for all three, so the answer does not reveal which. Also the answer for a tool that the endpoint filter of the request leaves out
invalid_argument none The arguments break the tool’s inputSchema, or the text fails the hygiene rules. The message may name a declared argument and the broken rule, never the value
credential_required system, connectUrl The user has not connected an account for the system. connectUrl is the portal page
confirmation_required confirmationId, description, previewUrl, registerUrl, expiresAt (all optional) A DESTRUCTIVE call needs the current code of the user’s authenticator. Either a pending call exists, or the user has no authenticator and only registerUrl is given
confirmation_failed none No pending call, expired, different arguments, wrong or used code, or attempts exhausted
confirmation_superseded none A newer destructive operation of the same user replaced the pending call. The user starts again
confirmation_cancelled none The owner cancelled the pending call in the portal
confirmation_blocked retryAfterSeconds Another destructive operation of this user awaits confirmation. A client must not ask for a code for this call
step_up_required stepUpUrl The call needs a fresher multi-factor login
rate_limited retryAfterSeconds The call is over a gateway limit. retryAfterSeconds is at least 1
upstream_unavailable none The target system, the secret store or the policy source is unavailable. A server also answers this when its policy data is missing, not approved or does not match its policies
internal_error none Anything the server did not anticipate, a result that breaks its output schema, or a credential type outside the server’s accepted types

In a server, the only exception that leaves a tool is SanitizedToolException. The starter maps for you: no credential to credential_required, InvalidToolArgumentException to invalid_argument, SecurityException to access_denied, an unreachable backend or a 502, 503 or 504 to upstream_unavailable, everything else to internal_error. Add your own mapping with a ToolErrorMapping bean, using C10 codes only.

Response Body When
401 unauthenticated, with WWW-Authenticate: Bearer resource_metadata="..." The client token is missing or invalid
400 {"error":"invalid_request","reason":"invalid_filter"} The query of the /mcp address is not a valid endpoint filter
400 or 414 {"error":"invalid_request"} The query is longer than the transport accepts (about 15 KB, depends on the deployment)
429 rate_limited with retryAfterSeconds and a Retry-After header A request that is not a tool call is over a limit
503 upstream_unavailable with Retry-After The gateway is overloaded, the session store or the identity provider’s keys are unavailable, or the rate counter does not answer
502, 504 bad_gateway, gateway_timeout A gateway instance failed or timed out during the request. The body says: The request may or may not have been processed. Check the result before repeating a write.

An UPDATE call is delivered at least once. The gateway never retries UPDATE or DESTRUCTIVE calls, so design an update tool so that a repeat is harmless (see Write a server from the template).

Response When
401 The internal JWT is missing or fails a check, see Authentication. On the two /.well-known/ paths the body also carries the reason, for example wrong_purpose
409 policy_data_stale The server holds no policy data or an older revision than the token’s prv. The gateway pushes the data and repeats the call once
400 The request body is not a single JSON object, or the policy data is not valid
413 The request body is larger than max-request-body
503 upstream_unavailable The gateway’s key set or the Redis store of jti is unavailable
API Values
Credential broker, authenticator enrollment invalid_code, enrollment_invalid
Credential broker, OAuth completion flow_invalid, system_not_configured
Credential broker, saving a secret secret_invalid
Portal, connecting an account flow_invalid, provider_error, cancelled
Portal, sign-in cancelled, idp_error, session_expired, step_up_failed

When an administrator adds a server, C5 can answer 422 with address_refused, plain_http_not_allowed, tls_handshake_failed, manifest_unreachable, manifest_invalid, system_mismatch, system_reserved or namespace_conflict, and 409 with server_exists or connection_changed.

Values are defaults of the gateway and starter; an operator can change them with the listed setting.

Counted in Redis per window. A tools/call over a limit gets rate_limited in the tool result; other MCP requests get 429. Gateway responses carry no X-RateLimit-* headers.

Limit Default Setting
Tool calls per user 600 MCP_RATE_LIMIT_PER_USER
Per user and AI client 300 MCP_RATE_LIMIT_PER_CLIENT
Per user and tool 120 MCP_RATE_LIMIT_PER_TOOL
Per user and destructive tool 10 MCP_RATE_LIMIT_DESTRUCTIVE_PER_TOOL
Window 1m MCP_RATE_LIMIT_WINDOW
Limits on true MCP_RATE_LIMIT_ENABLED

If Redis does not answer, the gateway refuses the call (upstream_unavailable) instead of letting traffic through uncounted.

Limit Default Setting
MCP requests served at once per gateway instance 128 MCP_MAX_CONCURRENT_REQUESTS
Wait for a free place before 503 100ms MCP_CONCURRENCY_QUEUE_WAIT
Retry-After of that 503 2 s MCP_SHED_RETRY_AFTER_SECONDS
Retry-After when the session store fails 10 s MCP_SESSION_STORE_RETRY_AFTER_SECONDS
Open event streams per instance 2000 MCP_MAX_OPEN_STREAMS
Time one server has to answer tools/list 3000 ms MCP_TOOLS_LIST_TIMEOUT

A server that is slower than that is left out of the tool list of that request.

Limit Default Setting
Request body of a server 4MB aiwcorpo.mcp.platform.internal-jwt.max-request-body
Tool result 1MB aiwcorpo.mcp.platform.tools.max-result-size
List in a result checked by policy 200 elements aiwcorpo.mcp.platform.tools.max-filtered-elements
Lifetime of an internal JWT 60 s fixed by the contract
Clock tolerance 30 s aiwcorpo.mcp.platform.internal-jwt.clock-skew, at most 30 s
Validity of a paging cursor 15m aiwcorpo.mcp.platform.paging.cursor-validity
Backend response read by the template server 1MB example.backend.max-response-size (rename for your system)

A result over max-result-size or a list over max-filtered-elements becomes internal_error, so a tool that returns lists pages them. An identifier longer than 1024 characters is invalid before any matching.

Limit Default Setting
OAuth starts per user and window 10 broker.rate-limits.oauth-starts
OAuth completions per user and window 20 broker.rate-limits.oauth-completions
Window of those two 1m broker.rate-limits.window
Token saves per portal session and window 10 per 1m PORTAL_LIMIT_SECRET_WRITE_MAX, PORTAL_LIMIT_SECRET_WRITE_WINDOW
Authenticator writes per portal session 10 per 10m PORTAL_LIMIT_AUTHENTICATOR_MAX, PORTAL_LIMIT_AUTHENTICATOR_WINDOW
Authenticator registration starts per user and hour 10 broker.authenticator.enrollment-starts-per-hour
Request body of the broker 16384 bytes broker.max-request-bytes
Unused connection kept before cleanup 180d broker.retention.unused-after
Activity retention 30d MCP_ACTIVITY_RETENTION