Codex does not follow MCP `tools/list` pagination via `nextCursor`
What version of Codex CLI is running?
codex-cli 0.140.0
What subscription do you have?
ChatGPT Pro
Which model were you using?
gpt-5.5
What platform is your computer?
Darwin 25.5.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
zsh (/bin/zsh)
Codex doctor report
overallStatus: fail
codexVersion: 0.140.0
config.load: ok
mcp.config: ok
auth.credentials: ok
network.provider_reachability: ok
network.websocket_reachability: ok
terminal.env: fail because TERM=dumb
updates.status: ok, latest version: 0.140.0
What issue are you seeing?
Codex CLI appears not to follow MCP tools/list pagination when building the callable MCP tool set.
When an MCP server returns a tools/list response with nextCursor, Codex exposes only the first page of tools. Tools returned on later pages are not available as callable MCP tools.
This makes paginated MCP tool discovery incomplete.
I first observed this with an MCP server where MCP Inspector can load additional tools via “more tools” and execute a tool from a later page, but Codex only exposes the first page.
What steps can reproduce the bug?
I reproduced this with a minimal local stdio MCP server.
The server behaves as follows:
- First
tools/listresponse: - returns 30 tools
- includes
nextCursor: "page-2" - Second
tools/listresponse withcursor: "page-2": - returns an additional tool named
github-mcp-server___search_repositories
When connecting Codex CLI 0.140.0 to this server, Codex only exposed the first 30 tools. The tool from the second page was not callable.
Server-side received requests:
{"method":"initialize","id":0}
{"method":"tools/list","id":1,"params":{"_meta":{"progressToken":0}}}
There was no second tools/list request with cursor: "page-2".
Codex output:
probe exposes 30 callable tools.
FAIL:
github-mcp-server___search_repositories is not available
only mcp__probe.page1_tool_* tools were callable
Source investigation:
In Codex rust-v0.140.0, the callable tool discovery path appears to call tools/list once with params = None:
https://github.com/openai/codex/blob/rust-v0.140.0/codex-rs/codex-mcp/src/rmcp_client.rs#L345-L353
The lower-level client already carries next_cursor:
https://github.com/openai/codex/blob/rust-v0.140.0/codex-rs/rmcp-client/src/rmcp_client.rs#L487-L520
Codex also already follows cursor pagination for resources/list / resource_templates/list:
https://github.com/openai/codex/blob/rust-v0.140.0/codex-rs/codex-mcp/src/connection_manager.rs#L541-L568
What is the expected behavior?
If tools/list returns nextCursor, Codex should continue requesting subsequent pages by sending another tools/list request with that cursor.
Example:
{
"method": "tools/list",
"params": {
"cursor": "page-2"
}
}
Codex should expose tools from all pages as callable MCP tools.
This would make Codex’s MCP tool discovery consistent with MCP pagination and with Codex’s existing resource pagination behavior.
Additional information
MCP spec references:
tools/listsupports pagination:
https://modelcontextprotocol.io/specification/2025-06-18/server/tools
- MCP pagination:
https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination
I searched for existing Codex issues/PRs using:
tools/list nextCursorMCP pagination tools/listlist_tools_with_connector_ids
I did not find an existing matching issue.
3 Comments
Here is the minimal repro server I used.
Save this as
/tmp/mcp_pagination_probe.py:Then run:
Observed result:
The server logs show Codex sends only the first
tools/listrequest:It never sends a second
tools/listrequest with:So the reproduction does not depend on a specific gateway or a specific page size limit. It only depends on a valid paginated
tools/listresponse withnextCursor.Independent real-world reproduction using an HTTP MCP server built with Laravel MCP v0.5.9:
tools/listresponse returns exactly 15 tools and anextCursor.tools/listagain with the returned cursor provides the remaining eight tools.Laravel MCP defaults the page size to 15:
https://github.com/laravel/mcp/blob/39e8da60eb7bce4737c5d868d35a3fe78938c129/src/Server.php#L102-L104
Its
tools/listimplementation applies cursor pagination here:https://github.com/laravel/mcp/blob/39e8da60eb7bce4737c5d868d35a3fe78938c129/src/Server/Methods/ListTools.php#L15-L21
Increasing the server’s
defaultPaginationLengthto 50 works as a compatibility workaround, but Codex should follownextCursorso paginated MCP servers work without client-specific configuration.Root cause, minimal repro, and reference fix
Root cause.
list_tools_for_client_uncachedincodex-rs/codex-mcp/src/rmcp_client.rsissues a singlelist_tools_with_connector_ids(/*params*/ None, timeout)call and drops thenext_cursorfield of the response. The lower-level client already surfaces the cursor (ListToolsWithConnectorIdResult.next_cursorincodex-rs/rmcp-client/src/rmcp_client.rs), and Codex already follows cursors forresources/listandresources/templates/list(see the pagination loops incodex-mcp/src/connection_manager.rs, incl. a duplicate-cursor guard).tools/listis the only list endpoint missing that loop.Real-world repro.
codebase-memory-mcp0.9.0 (stdio) exposes 14 tools, paginated 8 per page:Output:
Codex registers only the first 8 tools from this server. As a cross-client control, the same server binary registers all 14 tools in an MCP client that follows
nextCursor(Claude Code), so the server side is spec-compliant.Reference implementation. I applied the same loop pattern Codex already uses for resources (accumulate pages until
next_cursorisNone, bail on a repeated cursor) tolist_tools_for_client_uncached: https://github.com/erictheng93/codex/commit/a27af5f52c280a09ec4dee23b5cf5d465e65c031.cargo check -p codex-mcppasses. Happy to open a PR with test coverage if the team would like to invite one per the contributing policy.