MCP tool-list changes are never picked up during a session
Context
We embed Codex in a product through the app server. Our agents use an MCP server whose tool list changes while a session runs. For example, a user connects a new integration mid-session, and the integration's tools become available. The MCP protocol has a standard notification for this: tools/list_changed.
The issue
Codex receives the notification but does not act on it. The handler (codex-rs/rmcp-client/src/logging_client_handler.rs:86) only writes a log line. The tool list the model sees stays as it was when the server first connected.
Codex does refresh its MCP setup between turns (refresh_mcp_if_dirty in codex-rs/core/src/session/mcp.rs). But that refresh only re-reads a server whose configuration changed. It reuses the existing connection and the cached tool list for a server whose config is unchanged (codex-mcp/src/connection_manager.rs:337-362, plus a 30-minute catalog cache in codex-mcp/src/tool_catalog_cache.rs). A server whose tools changed but whose config did not is exactly the case the refresh skips.
The result: a running session can never see new tools from a connected MCP server, even though the server announces them correctly.
Read from source at fcc4ca5 (main).
Proposed solution, in simple words
Two small steps, both inside Codex:
- When the
tools/list_changednotification arrives, remember which server sent it. - On the next refresh, fetch that one server's tool list again, even though its config is unchanged, and skip its cache entry.
The existing SendElicitation callback in rmcp-client/src/rmcp_client.rs shows how a notification can reach out of the handler, so the plumbing has a precedent. I have not written a patch, because where the invalidation hook belongs is a design call for maintainers.
Happy to test a fix against a real MCP server with a changing tool list.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I implemented and tested the native MCP 2026-07-28 path for this on current
main. The important distinction from the legacy handler path is that the new spec uses an explicit long-livedsubscriptions/listenrequest afterserver/discoveradvertisescapabilities.tools.listChanged: true; notifications routed to that subscription do not also reachClientHandler.Candidate branch: https://github.com/Tom-R-Main/codex/tree/codex/mcp-tool-list-subscriptions
Feature commit: https://github.com/Tom-R-Main/codex/commit/0b40fd83cc
The patch:
subscriptions/listenbefore the initialtools/list, so a change racing the snapshot is queued rather than lost;tools/list;Regression coverage passes for both layers:
I also grounded the flow against the canonical
modelcontextprotocol/modelcontextprotocol2026-07-28 schema andrmcp 3.0.0subscription API. The repository currently blocks unsolicited external PR creation, so I cannot open the upstream PR unless a maintainer invites it. Happy to submit it immediately if this direction matches the intended architecture.This candidate intentionally addresses the negotiated 2026 subscription path. The older pre-2026
ClientHandler::on_tool_list_changedpath remains a separate compatibility decision.