Skip to content

Codex refuses ?codemode=false: tools/list has more than its 2,048-tool cap #262

Open

Description

@mattzcarey

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:

codex mcp add cf-stg-direct --url "https://staging.mcp.cloudflare.com/mcp?codemode=false"
codex mcp login cf-stg-direct
RUST_LOG=codex_mcp=debug codex exec "Call the cf-stg-direct MCP tool accounts_list once."

The result is the same with and without Codex's code_mode and mcp_2026_07_28 features.

Scope

Activity

  1. martinmetzmacher commented on Oct 16, 2026

    @martinmetzmacher

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions