Support `resources/subscribe` for MCP resources as a client (resource notification subscriptions)
What variant of Codex are you using?
CLI, Desktop App, IDE Extensions
What feature would you like to see?
Feature: Codex should support subscribing to MCP resources (resources/subscribe) as an MCP client
Problem
Codex currently implements listing and reading MCP resources as a client (resources/list, resources/read, and resources/templates/list) but does not support subscribing to resource notifications via resources/subscribe or resources/unsubscribe or handling notifications/resources/updated and related events as a client.
This means:
- Resource caches in Codex can get stale with no way to keep them up to date when MCP servers change or publish new resources.
- Live update scenarios relying on the MCP spec for resource change invalidation (see MCP spec "Server Resources" section) aren't functional -- even though the underlying SDK provides the wire format.
- There's no extension point for users to auto-inject dynamic context into
messages[]without modifying codex-rs source. MCP resource subscriptions would naturally fill this gap.
Current state
(This was AI-assisted.)
| MCP Capability | Codex Support | Location |
|---|---|---|
| resources/list | ✅ via list_mcp_resources tool | mcp_resource.rs, mcp_connection_manager.rs |
| resources/read | ✅ via read_mcp_resource tool | mcp_resource.rs |
| resources/templates/list | ✅ via list_mcp_resource_templates tool | mcp_resource.rs |
| resources/subscribe | ❌ Not implemented | -- |
| resources/unsubscribe | ❌ Not implemented | -- |
| notifications/resources/updated | ⚠️ Received but only logged | logging_client_handler.rs:71-77 |
| notifications/resources/list_changed | ⚠️ Received but only logged | logging_client_handler.rs:79-81 |
Implementation plan
(This was AI-assisted.)
Phase 1: Wire up subscription lifecycle
- Give
LoggingClientHandler(or a replacement) an event channel soon_resource_updatedandon_resource_list_changedforward events toMcpConnectionManagerinstead of just logging them. - Add
resources/subscribeandresources/unsubscribeclient methods onMcpConnectionManagerusing the existing rmcp wire types (SubscribeRequestParams,UnsubscribeRequestParams). - During
McpConnectionManager::new(), after a server reachesReady, check if it advertisescapabilities.resources.subscribe == true. If so, enumerate resources viaresources/listand subscribe to all of them.
Phase 2: Resource cache invalidation
- Add a per-server resource cache (
HashMap<String, HashMap<String, CachedResource>>) toMcpConnectionManager. Populate on first list/read, invalidate entries onResourceEvent::Updated. - On
ResourceEvent::ListChanged, re-issueresources/list, diff against the cached list, subscribe to new resources, unsubscribe from removed ones.
Phase 3: Auto-inject into messages[]
This is the key payoff -- subscriptions become an extension point for the model context pipeline:
- Add an
mcp_resource_contextfield toTurnContextItem(URI -> content snapshot). - Populate it in
make_turn_context()/to_turn_context_item()from the cached subscribed resources. - Add a
build_mcp_resource_update_item()diff function incontext_manager/updates.rsalongside the existingbuild_permissions_update_item,build_collaboration_mode_update_item, etc. Wire it intobuild_settings_update_items(). - Optionally, on mid-turn
ResourceEvent::Updated, queue updated content viaqueue_response_items_for_next_turn()for immediate injection.
Phase 4: Configuration
Allow users to control subscription behavior in config.toml:
[mcp_resources]
auto_subscribe = true # subscribe to all resources from all servers
auto_inject = true # inject subscribed resource content into model context
max_inject_size = 8192 # cap total injected resource content (bytes)
References
- Original acceptance criteria for resource support in #4956 asked for cache updating via notifications.
- Current stub code only logs resource notification events, notifies nothing, and never subscribes.
- See MCP spec: https://modelcontextprotocol.io/specification/2025-11-25/server/resources#subscribing-to-resource-updates
Impact
- Enables Codex agents to keep MCP resource state in sync with underlying MCP servers
- Creates a first-class extension point for injecting dynamic context into the model -- users can write an MCP server that exposes a resource, and Codex will auto-inject updates into
messages[]without any source changes - Reduces stale data risk and aligns Codex with MCP spec and other major clients
- Fixes a gap identified in the closure of #4956 / PR #5239 -- subscription support was scoped out despite being part of the original design
Additional information
The initial implementation in #5239 and tracking in #4956 covered listing/reading resources, but not subscribing or notification flow in the client. See those as context for demand and scope. Current state: Codex logs resource notifications but does not act on them, and never issues subscribe/unsubscribe requests as a client.
This is about the Codex client role, not MCP server implementation.
3 Comments
That would be awesome. This becomes relevant once https://modelcontextprotocol.io/specification/draft/basic/utilities/tasks is out of draft status. I already face the problem that my mcp server - part of a plugin - takes more than 120 seconds and run into timeout. I thought okay let's use https://modelcontextprotocol.io/docs/learn/architecture#notifications, but as the issue author stated, not handled by Codex. Additionally the mcp server I design has such a complex workflow, that resources could be stateful/dynamic/situational and change during usage, but
notifications/resources/updatedis not handled by Codex. Apart from that it seems that .mcp.json - part of a plugin definition/bundle - cannot be describe the equivalent oftool_timeout_sec(part ofmcp_servers.*inside.codex/config.toml). And a mcp server coming from a plugin is not listed as a plugin, but skills from a plugin are listed as skills.. anyway I am digressing from the topic. It would be awesome if mcp servers would be first-class supported in Codex.Strong +1. We're using Codex CLI alongside Claude Code in a multi-agent flock that communicates through a shared MCP bridge server. Each agent has an "inbox" resource on the bridge that updates when peer agents or external systems (Teams, email, Discord) send messages addressed to it. Today we have to poll resources/list + resources/read on a 30s loop because notifications/resources/updated events log to tracing but don't invalidate caches or surface to the model. Push-based subscriptions would let our Codex agents react to peer messages in real time instead of running idle for 30s windows.
Adding to Tim's flock context above with a slightly different angle. The compelling part of this proposal isn't just stale-cache invalidation, it's Phase 3 (auto-inject into messages[]). That phase turns subscriptions from a hygiene fix into a first-class extension point: any MCP server that exposes a resource becomes a context-injection mechanism without needing changes to Codex or to the agent loop.
In practice that means writing an MCP server that exposes "current ticket queue," "current meeting transcript," "current org chart," etc., subscribing once, and having Codex stay in sync without anyone polling. Today the same thing has to ship as a tool the model has to remember to call, or as part of a system prompt that gets rebuilt every turn. Phase 3 makes it the cleanest extension surface for context engineering on Codex.
The implementation plan is well-scoped. Phase 1+2 fix the hygiene, Phase 3 unlocks the design pattern. Worth shipping all three.