Support `resources/subscribe` for MCP resources as a client (resource notification subscriptions)

Open 💬 3 comments Opened Mar 29, 2026 by alejandro5042

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

  1. Give LoggingClientHandler (or a replacement) an event channel so on_resource_updated and on_resource_list_changed forward events to McpConnectionManager instead of just logging them.
  2. Add resources/subscribe and resources/unsubscribe client methods on McpConnectionManager using the existing rmcp wire types (SubscribeRequestParams, UnsubscribeRequestParams).
  3. During McpConnectionManager::new(), after a server reaches Ready, check if it advertises capabilities.resources.subscribe == true. If so, enumerate resources via resources/list and subscribe to all of them.

Phase 2: Resource cache invalidation

  1. Add a per-server resource cache (HashMap<String, HashMap<String, CachedResource>>) to McpConnectionManager. Populate on first list/read, invalidate entries on ResourceEvent::Updated.
  2. On ResourceEvent::ListChanged, re-issue resources/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:

  1. Add an mcp_resource_context field to TurnContextItem (URI -> content snapshot).
  2. Populate it in make_turn_context() / to_turn_context_item() from the cached subscribed resources.
  3. Add a build_mcp_resource_update_item() diff function in context_manager/updates.rs alongside the existing build_permissions_update_item, build_collaboration_mode_update_item, etc. Wire it into build_settings_update_items().
  4. Optionally, on mid-turn ResourceEvent::Updated, queue updated content via queue_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
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.

View original on GitHub ↗

3 Comments

teneko · 5 months ago

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/updated is not handled by Codex. Apart from that it seems that .mcp.json - part of a plugin definition/bundle - cannot be describe the equivalent of tool_timeout_sec (part of mcp_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.

TeamDevWithTim · 4 months ago

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.

tracyterrell · 4 months ago

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.