From a1a0d9dea52dc32f57f5efd3f7fe2b67c9f3cf9a Mon Sep 17 00:00:00 2001 From: Sayan Sisodiya Date: Mon, 6 Jul 2026 17:02:08 -0400 Subject: [PATCH] core: reuse MCP tool snapshot within a step --- codex-rs/core/src/session/step_context.rs | 11 +++++++++++ codex-rs/core/src/session/turn.rs | 8 ++++---- codex-rs/core/src/session/world_state.rs | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/codex-rs/core/src/session/step_context.rs b/codex-rs/core/src/session/step_context.rs index 3210eb028662..1d7316d91443 100644 --- a/codex-rs/core/src/session/step_context.rs +++ b/codex-rs/core/src/session/step_context.rs @@ -5,6 +5,8 @@ use crate::environment_selection::TurnEnvironmentSnapshot; use crate::session::McpRuntimeSnapshot; use crate::session::turn_context::TurnContext; use codex_exec_server::ResolvedSelectedCapabilityRoot; +use codex_mcp::ToolInfo; +use tokio::sync::OnceCell; /// Request-scoped state that may change between model sampling requests. #[derive(Debug)] @@ -15,6 +17,8 @@ pub(crate) struct StepContext { pub(crate) selected_capability_roots: Vec, /// The exact MCP config and manager used to advertise and execute tools for this step. pub(crate) mcp: Arc, + /// The fixed MCP tool list used for this exact sampling request. + mcp_tool_snapshot: OnceCell>, /// The canonical AGENTS.md value observed with this environment snapshot. pub(crate) loaded_agents_md: Option>, } @@ -32,7 +36,14 @@ impl StepContext { environments, selected_capability_roots, mcp, + mcp_tool_snapshot: OnceCell::new(), loaded_agents_md, } } + + pub(crate) async fn mcp_tools(&self) -> &[ToolInfo] { + self.mcp_tool_snapshot + .get_or_init(|| self.mcp.manager().list_all_tools()) + .await + } } diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index f16b525002fc..89bad5b75769 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -1182,8 +1182,8 @@ pub(crate) async fn built_tools( let turn_context = step_context.turn.as_ref(); let mcp_connection_manager = step_context.mcp.manager(); let has_mcp_servers = mcp_connection_manager.has_servers(); - let all_mcp_tools = mcp_connection_manager - .list_all_tools() + let all_mcp_tools = step_context + .mcp_tools() .or_cancel(cancellation_token) .await?; let loaded_plugins = sess @@ -1196,7 +1196,7 @@ pub(crate) async fn built_tools( let apps_enabled = turn_context.apps_enabled(); let accessible_connectors = - apps_enabled.then(|| connectors::accessible_connectors_from_mcp_tools(&all_mcp_tools)); + apps_enabled.then(|| connectors::accessible_connectors_from_mcp_tools(all_mcp_tools)); let accessible_connectors_with_enabled_state = accessible_connectors.as_ref().map(|connectors| { connectors::with_app_enabled_state(connectors.clone(), &turn_context.config) @@ -1289,7 +1289,7 @@ pub(crate) async fn built_tools( .await }; let mcp_tool_exposure = build_mcp_tool_exposure( - &all_mcp_tools, + all_mcp_tools, connectors.as_deref(), &turn_context.config, search_tool_enabled(turn_context), diff --git a/codex-rs/core/src/session/world_state.rs b/codex-rs/core/src/session/world_state.rs index a0d93cac8317..c7743c3fe18c 100644 --- a/codex-rs/core/src/session/world_state.rs +++ b/codex-rs/core/src/session/world_state.rs @@ -41,9 +41,9 @@ impl Session { } let apps_available = if turn_context.config.include_apps_instructions && turn_context.apps_enabled() { - let tools = step_context.mcp.manager().list_all_tools().await; + let tools = step_context.mcp_tools().await; connectors::with_app_enabled_state( - connectors::accessible_connectors_from_mcp_tools(&tools), + connectors::accessible_connectors_from_mcp_tools(tools), &turn_context.config, ) .into_iter()