Send raw Codex events to subscribed MCP servers

Remove the _meta.threadId envelope from forwarded codex/event notifications. External MCP servers now receive the serialized Event directly as notification params, so the payload contract is just id plus msg, with msg.type still used for subscription filtering.

This keeps the custom notification API minimal and avoids carrying duplicate thread metadata in a one-field wrapper. Event fanout semantics are unchanged: Codex still emits only to servers that advertise matching capabilities.experimental["codex/events"].eventTypes, skips servers that are still starting, and treats delivery as best effort.
This commit is contained in:
Justin Rushing
2026-04-02 23:48:11 -07:00
parent f2620e7c8b
commit 7fc03f4a19
2 changed files with 3 additions and 30 deletions
@@ -34,7 +34,6 @@ use async_channel::Sender;
use codex_async_utils::CancelErr;
use codex_async_utils::OrCancelExt;
use codex_config::Constrained;
use codex_protocol::ThreadId;
use codex_protocol::approvals::ElicitationRequest;
use codex_protocol::approvals::ElicitationRequestEvent;
use codex_protocol::mcp::CallToolResult;
@@ -600,20 +599,6 @@ pub struct SandboxState {
pub use_legacy_landlock: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ExternalMcpEventNotificationMeta {
pub(crate) thread_id: ThreadId,
}
#[derive(Debug, Clone, Serialize)]
pub(crate) struct ExternalMcpEventNotification {
#[serde(rename = "_meta")]
pub(crate) meta: ExternalMcpEventNotificationMeta,
#[serde(flatten)]
pub(crate) event: Event,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CodexEventsCapability {
@@ -1171,8 +1156,8 @@ impl McpConnectionManager {
Ok(())
}
pub async fn notify_codex_event(&self, params: &ExternalMcpEventNotification) -> Result<()> {
let params = serde_json::to_value(params)?;
pub async fn notify_codex_event(&self, event: &Event) -> Result<()> {
let params = serde_json::to_value(event)?;
let Some(event_type) = params
.get("msg")
.and_then(|msg| msg.get("type"))
+1 -13
View File
@@ -322,11 +322,6 @@ use codex_git_utils::get_git_repo_root;
use codex_mcp::mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_mcp::mcp::auth::compute_auth_statuses;
use codex_mcp::mcp::with_codex_apps_mcp;
use codex_mcp::mcp_connection_manager::ExternalMcpEventNotification;
use codex_mcp::mcp_connection_manager::ExternalMcpEventNotificationMeta;
use codex_mcp::mcp_connection_manager::McpConnectionManager;
use codex_mcp::mcp_connection_manager::codex_apps_tools_cache_key;
use codex_mcp::mcp_connection_manager::filter_non_codex_apps_mcp_tools_only;
use codex_otel::SessionTelemetry;
use codex_otel::TelemetryAuthMode;
use codex_otel::metrics::names::THREAD_STARTED_METRIC;
@@ -2784,15 +2779,8 @@ impl Session {
}
async fn notify_external_mcp_event(&self, event: &Event) {
let params = ExternalMcpEventNotification {
meta: ExternalMcpEventNotificationMeta {
thread_id: self.conversation_id,
},
event: event.clone(),
};
let manager = self.services.mcp_connection_manager.read().await;
if let Err(err) = manager.notify_codex_event(&params).await {
if let Err(err) = manager.notify_codex_event(event).await {
warn!("failed to notify MCP servers about codex event: {err:#}");
}
}