You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Codex refuses ?codemode=false: tools/list has more than its 2,048-tool cap #262
Codex can't load the direct-tool surface (/mcp?codemode=false). It refuses any MCP server whose tools/list returns more than 2,048 tools, and drops the server at startup:
codex_mcp::rmcp_client: MCP server startup failed server_name="cf-stg-direct"
error=tools/list exceeded the catalog limit of 2048 items
The model then reports that none of the server's tools are available.
Repro
Codex CLI 0.157.0, logged in to https://staging.mcp.cloudflare.com/mcp?codemode=false:
Reproducing this from a second client with a different failure mechanism — worth separating from the catalogue cap, because it also bites clients that don't cap tool counts.
Client: Hermes Agent (macOS), MCP SDK 2.0.0 over httpx2, production endpoint https://mcp.cloudflare.com/mcp?codemode=false, OAuth.
Observed:
initialize succeeds.
tools/list returns 3,763 tools as one SSE event of 3,663,834 bytes.
httpx2 enforces a hard DEFAULT_MAX_EVENT_SIZE_BYTES = 1024 * 1024 per SSE event, and the SDK builds its reader without an override (EventSource(response) in mcp/client/streamable_http.py), so parsing raises SSEError: Server-sent event exceeded the 1048576 byte limit.
That exception is swallowed by a broad except Exception in the same module, so the caller only sees MCPError: SSE stream ended without a response — which reads like a transport or auth failure rather than a payload-size one.
Not the token, not the endpoint: the identical request over raw HTTP returns 200 with the complete 3.6 MB body in ~0.4 s, and the same client works against /mcp in Code Mode (4 tools, sub-second).
Suggestion: paginating tools/list with a nextCursor would fix both failure modes at once — clients with a catalogue cap (#262) and clients with a per-event size cap (this one) — and would let both stream the catalogue in bounded chunks. In the meantime, logging.getLogger("mcp.client.streamable_http").setLevel(logging.DEBUG) surfaces the swallowed SSEError and names the real cause.
Confirming the diagnosis from my side: raising the client's per-event cap to 64 MiB loads all 3,763 tools, which then call the API correctly.
Activity
martinmetzmacher commentedon Oct 16, 2026
Reproducing this from a second client with a different failure mechanism — worth separating from the catalogue cap, because it also bites clients that don't cap tool counts.
Client: Hermes Agent (macOS), MCP SDK 2.0.0 over
httpx2, production endpointhttps://mcp.cloudflare.com/mcp?codemode=false, OAuth.Observed:
initializesucceeds.tools/listreturns 3,763 tools as one SSE event of 3,663,834 bytes.httpx2enforces a hardDEFAULT_MAX_EVENT_SIZE_BYTES = 1024 * 1024per SSE event, and the SDK builds its reader without an override (EventSource(response)inmcp/client/streamable_http.py), so parsing raisesSSEError: Server-sent event exceeded the 1048576 byte limit.except Exceptionin the same module, so the caller only seesMCPError: SSE stream ended without a response— which reads like a transport or auth failure rather than a payload-size one.Not the token, not the endpoint: the identical request over raw HTTP returns
200with the complete 3.6 MB body in ~0.4 s, and the same client works against/mcpin Code Mode (4 tools, sub-second).Suggestion: paginating
tools/listwith anextCursorwould fix both failure modes at once — clients with a catalogue cap (#262) and clients with a per-event size cap (this one) — and would let both stream the catalogue in bounded chunks. In the meantime,logging.getLogger("mcp.client.streamable_http").setLevel(logging.DEBUG)surfaces the swallowedSSEErrorand names the real cause.Confirming the diagnosis from my side: raising the client's per-event cap to 64 MiB loads all 3,763 tools, which then call the API correctly.