diff --git a/codex-rs/app-server/src/request_processors/mcp_processor.rs b/codex-rs/app-server/src/request_processors/mcp_processor.rs index 2d60ed1353..4aa323c40a 100644 --- a/codex-rs/app-server/src/request_processors/mcp_processor.rs +++ b/codex-rs/app-server/src/request_processors/mcp_processor.rs @@ -402,6 +402,10 @@ impl McpRequestProcessor { let thread_id = params.thread_id.clone(); let (_, thread) = self.load_thread(&thread_id).await?; let meta = with_mcp_tool_call_thread_id_meta(params.meta, &thread_id); + let meta = with_mcp_tool_call_turn_metadata_meta( + meta, + thread.current_mcp_request_turn_metadata().await, + ); let request_id = request_id.clone(); tokio::spawn(async move { @@ -416,6 +420,34 @@ impl McpRequestProcessor { } } +fn with_mcp_tool_call_turn_metadata_meta( + meta: Option, + turn_metadata: Option, +) -> Option { + let Some(turn_metadata) = turn_metadata else { + return meta; + }; + + match meta { + Some(serde_json::Value::Object(mut map)) => { + map.insert( + codex_core::X_CODEX_TURN_METADATA_HEADER.to_string(), + turn_metadata, + ); + Some(serde_json::Value::Object(map)) + } + None => { + let mut map = serde_json::Map::new(); + map.insert( + codex_core::X_CODEX_TURN_METADATA_HEADER.to_string(), + turn_metadata, + ); + Some(serde_json::Value::Object(map)) + } + other => other, + } +} + fn with_mcp_tool_call_thread_id_meta( meta: Option, thread_id: &str, diff --git a/codex-rs/core/src/codex_thread.rs b/codex-rs/core/src/codex_thread.rs index 1b40387c3f..27c215a9f0 100644 --- a/codex-rs/core/src/codex_thread.rs +++ b/codex-rs/core/src/codex_thread.rs @@ -5,6 +5,7 @@ use crate::goals::GoalRuntimeEvent; use crate::session::Codex; use crate::session::SessionSettingsUpdate; use crate::session::SteerInputError; +use crate::turn_metadata::McpTurnMetadataContext; use codex_features::Feature; use codex_otel::SessionTelemetry; use codex_protocol::config_types::ApprovalsReviewer; @@ -502,6 +503,18 @@ impl CodexThread { self.codex.session.get_config().await } + pub async fn current_mcp_request_turn_metadata(&self) -> Option { + let active = self.codex.session.active_turn.lock().await; + let (_, active_task) = active.as_ref()?.tasks.first()?; + let turn_context = active_task.turn_context.as_ref(); + turn_context + .turn_metadata_state + .current_meta_value_for_mcp_request(McpTurnMetadataContext { + model: turn_context.model_info.slug.as_str(), + reasoning_effort: turn_context.effective_reasoning_effort(), + }) + } + /// Refresh the thread's layer-backed user config state from a caller-supplied /// config snapshot. Thread-scoped layers and session-static settings remain /// unchanged.