Feature request: surface MCP `notifications/message` to the model's conversation (not just tracing)

Open 💬 7 comments Opened Apr 16, 2026 by Co-Messi
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

MCP servers can send notifications/message (the standard MCP logging notification) to the client. Codex CLI currently receives these and routes them to Rust tracing macros in codex-rs/rmcp-client/src/logging_client_handler.rs — they show up in stderr/debug logs but the model never sees them.

Feature request: optionally inject the data field of notifications/message into the model's active conversation so the LLM can read and react to it, similar to how Claude Code's notifications/claude/channel surfaces server-pushed content mid-task.

Use case: inter-agent peer messaging

I'm building agent-peers-mcp — an MCP server that lets multiple Claude Code and Codex CLI sessions on the same machine discover each other and exchange messages (localhost broker, SQLite, no cloud). Think of it as Slack DMs between AI coding agents.

On the Claude Code side, this works seamlessly: the MCP server pushes peer messages via notifications/claude/channel, and Claude sees them mid-task. On the Codex side, we have no equivalent push surface — the only way to get a message to the model is to wait until the user happens to trigger a tool call, then piggyback the message in the tool response.

This makes Claude ↔ Codex collaboration feel broken: Claude sends a message to Codex, but Codex doesn't notice until the user manually types something. The "colleague" experience collapses.

If notifications/message content were surfaced to the model, the Codex MCP server could push peer messages the same way Claude's server does — and Codex would see and react to them mid-task.

What Codex already does (90% of the way there)

Looking at the source:

  1. codex-rs/rmcp-client/src/logging_client_handler.rson_logging_message() receives notifications/message and maps levels to tracing:
  • Emergency/Alert/Critical/Error → error!()
  • Warning → warn!()
  • Notice/Info → info!()
  • Debug → debug!()
  1. codex-rs/codex-mcp/src/mcp_connection_manager.rs — has a tx_event: Sender<Event> channel that already sends events from the MCP layer back to the agent loop (used for elicitation requests and startup updates).

So the notification arrives, the event channel exists — they're just not connected.

Proposed change (~50 lines across 3-4 files)

  1. Add a new EventMsg variant:

``rust
EventMsg::McpServerMessage {
server: String,
logger: Option<String>,
level: String,
data: serde_json::Value,
}
``

  1. In logging_client_handler.rs on_logging_message():

``rust
// After existing tracing macro call (backwards-compatible):
if let Some(tx) = &self.tx_event {
let _ = tx.send(Event {
id: "mcp_server_message".to_string(),
msg: EventMsg::McpServerMessage {
server: self.server_name.clone(),
logger: params.logger.clone(),
level: params.level.to_string(),
data: params.data.clone(),
},
}).await;
}
``

  1. In the agent loop (wherever EventMsg is consumed):

``rust
EventMsg::McpServerMessage { server, logger, data, .. } => {
// Inject
data as a system/tool-result message into the
// conversation so the model sees it on the next generation step.
// The model can then decide whether to act on it.
}
``

Why this benefits the ecosystem beyond our use case

Any MCP server that wants to push real-time information to the model — not just peer messages, but also:

  • File-watcher servers notifying the model when a file changes on disk
  • CI/CD servers pushing build results mid-task
  • Monitoring servers alerting about errors in a running service
  • Collaborative editing servers syncing changes from other users

All of these are currently impossible on Codex because notifications/message is a dead letter. The plumbing is 90% there; this request is about closing the last 10%.

Impact

  • No breaking changes. Existing behavior (tracing to stderr) is preserved. The event injection is additive.
  • MCP-spec-compliant. notifications/message is a standard MCP feature — this just makes Codex honor it more fully.
  • Scoped risk. The injection is filtered by level + logger, so only servers that explicitly opt in (by sending info-level log notifications) would trigger it. Debug/trace noise stays in tracing.

Related

  • MCP spec: Logging
  • Our repo: Co-Messi/agent-peers-mcp — the motivating use case
  • Claude Code's equivalent: notifications/claude/channel (proprietary, not part of MCP spec — but the MCP-standard notifications/message can serve the same purpose if surfaced)

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #17543

Powered by Codex Action

TeamDevWithTim · 2 months ago

Strong +1, would solve the same use case as #17543 with the smallest scope. We're running a multi-agent MCP bridge where peer messages arrive as notifications/message. On Claude Code these surface to the model via the experimental channel API; on Codex CLI they hit Rust tracing and the model never sees them. Even just exposing the data field in the model's conversation context (without going as far as #17543's user-submission injection) would unblock real-time message flow for our Codex agents.

tracyterrell · 2 months ago

Strong +1 on this. The feature gap is the difference between an agent that can be a peer in a multi-agent system and one that can't.

We run a fleet of Claude Code agents in production, communicating with each other and with humans through a custom MCP server that emits exactly this notifications/message shape. The agents pick up messages mid-task without any user interaction. The "colleague" experience the author describes is real and load-bearing. Once you see code agents, data agents, comms agents, and codebase-aware research agents collaborating via a shared messaging substrate, going back to "you only learn about events when the user types another tool call" feels broken.

We've actively considered Codex in the same patterns (cost, latency, reasoning style differ in useful ways) but the lack of push notifications has kept it out. Until Codex closes this gap, it can sit in one seat at a time, never the seat where multiple AI peers talk to each other. For organizations standardizing on multi-agent architectures, that effectively rules Codex out of the higher-order patterns.

The proposed implementation (EventMsg::McpServerMessage, ~50 lines, reuses tx_event) seems proportional to the value. Closing the asymmetry with Claude Code's notifications/claude/channel would unlock real production deployments rather than enabling one more demo.

bluwavesd · 2 months ago

+1 — also building a fleet of agents that needs this exact capability.

Our use case (BluPrint MSP fleet)

We run ~10 Claude Code agents on internal infra (Mattermost-bridged) — coders, ops, testers, coordinators — collaborating on customer engagements. Server-pushed mid-session messages are load-bearing for the coordination model:

  • Coordinator agent assigns a task → message pushes into target agent's session, target acts immediately (vs polling)
  • Tester reports a failed gate → coordinator + ops see the signal mid-session and re-route
  • Customer escalation lands in a channel → on-call agent picks it up without manual prompt

On Claude Code today, --dangerously-load-development-channels server:mattermost + the notifications/claude/channel shape gives us this push-injection. Roughly 100+ agent-coordination decisions per day across our fleet ride on this primitive.

Why we want Codex parity

We've been evaluating non-Anthropic backends for cost-arbitrage on burst-shape work (one of our agents — Carson V2 — runs on DeepSeek-V3 via CCR). The model swap works for chat-shape tasks; the coordination plumbing collapses without push-injection. We currently route around this by polling mm_history from non-Anthropic agents, which adds 30-60s latency to every cross-agent coordination decision and burns extra tokens on every poll cycle.

Codex CLI gaining notifications/message → conversation injection would directly unblock fleet expansion to Codex-backed agents — same coordination-primitive, just different provider.

Why the proposed change is the right shape

The author's diagnosis matches what we've seen on Claude side: the plumbing exists (event channel, tracing path), only the wire-up is missing. The proposed EventMsg::McpServerMessage variant + opt-in level filter keeps backwards-compat clean and matches MCP-spec semantics rather than inventing a Codex-specific notification path.

Beyond peer-messaging

The list of MCP-server use cases the author enumerated (file-watcher, CI/CD, monitoring, collaborative-edit) all map directly to fleet-coordination patterns we'd want on the Codex side: alertmanager pushing to ops agent, log-tailer pushing to incident-response agent, etc. Each one is currently impossible on Codex without this.

Filing this as a +1 from a real production fleet that would adopt the moment it ships.

backnotprop · 1 month ago

+1

surfskidude · 1 month ago

Strong +1 from my side as well.

I am building an MCP server for embedded and real-time lab environments where asynchronous runtime feedback is essential. My server already correctly implements Streamable HTTP with SSE and emits standard MCP notifications/message events for runtime logs, trace output, Lua exceptions, status updates, and long-running execution state.

At the protocol level everything works correctly:

  • MCP Inspector receives the notifications.
  • Raw SSE clients receive the live events.

However, Codex currently appears to expose only tool-call responses to the model, whereas asynchronous MCP notifications from the SSE channel are not visible to the agent.

This prevents an important class of real-time MCP workflows from working properly. In my case, the AI agent may:

  • start an embedded runtime or lab,
  • deploy or execute Lua programs,
  • monitor live trace output,
  • detect runtime exceptions asynchronously,
  • react to device/runtime state changes in real time.

Without access to async MCP notifications, the agent cannot observe the runtime after the initial tool call completes. The only workaround is artificial polling or server-side buffering, both of which are undesirable for embedded systems.

alexfrmn · 29 days ago

I validated a local implementation of this behavior against a patched 0.141.0-line CLI build.

The compatibility path supports notifications/message, but only when both gates are present:

  • the MCP server is configured with surface_notifications = true
  • the payload explicitly targets the live session, e.g. toSession: true

With that in place, the notification is surfaced as a normal model-visible user turn rather than only going to tracing/logging.

For upstream API clarity, I would still recommend notifications/channel or another custom method for new integrations, because notifications/message is already overloaded as a logging-style MCP notification. But this patch can keep notifications/message compatibility for existing MCP servers that already emit it.

Patch link: https://github.com/openai/codex/compare/main...alexfrmn:upstream-pr-mcp-surface-notifications?expand=1