From 547ed1971743735abd622eab27697701e8f1c982 Mon Sep 17 00:00:00 2001 From: Francis Chalissery Date: Sun, 12 Apr 2026 11:42:21 -0700 Subject: [PATCH 1/2] Support flattened deferred MCP tool calls --- codex-rs/core/src/tools/spec_tests.rs | 2 + codex-rs/tools/src/tool_registry_plan.rs | 7 ++++ .../tools/src/tool_registry_plan_tests.rs | 40 +++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/codex-rs/core/src/tools/spec_tests.rs b/codex-rs/core/src/tools/spec_tests.rs index da76a1bb28f2..b0195e4563d5 100644 --- a/codex-rs/core/src/tools/spec_tests.rs +++ b/codex-rs/core/src/tools/spec_tests.rs @@ -909,6 +909,8 @@ fn search_tool_registers_namespaced_mcp_tool_aliases() { assert!(registry.has_handler(&ToolName::plain(TOOL_SEARCH_TOOL_NAME))); assert!(registry.has_handler(&app_alias)); assert!(registry.has_handler(&mcp_alias)); + assert!(registry.has_handler(&ToolName::plain("mcp__codex_apps__calendar_create_event"))); + assert!(registry.has_handler(&ToolName::plain("mcp__rmcp__echo"))); } #[test] diff --git a/codex-rs/tools/src/tool_registry_plan.rs b/codex-rs/tools/src/tool_registry_plan.rs index 82b4c3a14267..6f35272fa1d5 100644 --- a/codex-rs/tools/src/tool_registry_plan.rs +++ b/codex-rs/tools/src/tool_registry_plan.rs @@ -270,6 +270,13 @@ pub fn build_tool_registry_plan( ToolName::namespaced(tool.tool_namespace, tool.tool_name), ToolHandlerKind::Mcp, ); + let qualified_name = format!("{}{}", tool.tool_namespace, tool.tool_name); + if !params + .mcp_tools + .is_some_and(|tools| tools.contains_key(&qualified_name)) + { + plan.register_handler(qualified_name, ToolHandlerKind::Mcp); + } } } diff --git a/codex-rs/tools/src/tool_registry_plan_tests.rs b/codex-rs/tools/src/tool_registry_plan_tests.rs index 9da58849c1be..c95fbf40a6e7 100644 --- a/codex-rs/tools/src/tool_registry_plan_tests.rs +++ b/codex-rs/tools/src/tool_registry_plan_tests.rs @@ -1294,6 +1294,46 @@ fn search_tool_description_lists_each_mcp_source_once() { })); } +#[test] +fn search_tool_registers_deferred_mcp_flattened_handlers() { + let model_info = search_capable_model_info(); + let mut features = Features::with_defaults(); + features.enable(Feature::ToolSearch); + let available_models = Vec::new(); + let tools_config = ToolsConfig::new(&ToolsConfigParams { + model_info: &model_info, + available_models: &available_models, + features: &features, + image_generation_tool_auth_allowed: true, + web_search_mode: Some(WebSearchMode::Cached), + session_source: SessionSource::Cli, + sandbox_policy: &SandboxPolicy::DangerFullAccess, + windows_sandbox_level: WindowsSandboxLevel::Disabled, + }); + + let (_, handlers) = build_specs( + &tools_config, + /*mcp_tools*/ None, + Some(vec![deferred_mcp_tool( + "js", + "mcp__node_repl__", + "node_repl", + /*connector_name*/ None, + /*connector_description*/ None, + )]), + &[], + ); + + assert!(handlers.contains(&ToolHandlerSpec { + name: ToolName::namespaced("mcp__node_repl__", "js"), + kind: ToolHandlerKind::Mcp, + })); + assert!(handlers.contains(&ToolHandlerSpec { + name: ToolName::plain("mcp__node_repl__js"), + kind: ToolHandlerKind::Mcp, + })); +} + #[test] fn search_tool_requires_model_capability_and_feature_flag() { let model_info = search_capable_model_info(); From e3c74fd2e774338a7d5d92209280744d8638b07e Mon Sep 17 00:00:00 2001 From: Francis Chalissery Date: Sun, 12 Apr 2026 12:42:41 -0700 Subject: [PATCH 2/2] Keep deferred MCP aliases out of tool plans --- codex-rs/core/src/tools/spec.rs | 9 +++++ codex-rs/tools/src/tool_registry_plan.rs | 7 ---- .../tools/src/tool_registry_plan_tests.rs | 40 ------------------- 3 files changed, 9 insertions(+), 47 deletions(-) diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index bfad3cdb3531..188be42ba179 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -263,6 +263,15 @@ pub(crate) fn build_specs_with_discoverable_tools( } } } + if let Some(deferred_mcp_tools) = deferred_mcp_tools.as_ref() { + for (name, _) in deferred_mcp_tools.iter().filter(|(name, _)| { + !mcp_tools + .as_ref() + .is_some_and(|tools| tools.contains_key(*name)) + }) { + builder.register_handler(name.clone(), mcp_handler.clone()); + } + } builder } diff --git a/codex-rs/tools/src/tool_registry_plan.rs b/codex-rs/tools/src/tool_registry_plan.rs index 6f35272fa1d5..82b4c3a14267 100644 --- a/codex-rs/tools/src/tool_registry_plan.rs +++ b/codex-rs/tools/src/tool_registry_plan.rs @@ -270,13 +270,6 @@ pub fn build_tool_registry_plan( ToolName::namespaced(tool.tool_namespace, tool.tool_name), ToolHandlerKind::Mcp, ); - let qualified_name = format!("{}{}", tool.tool_namespace, tool.tool_name); - if !params - .mcp_tools - .is_some_and(|tools| tools.contains_key(&qualified_name)) - { - plan.register_handler(qualified_name, ToolHandlerKind::Mcp); - } } } diff --git a/codex-rs/tools/src/tool_registry_plan_tests.rs b/codex-rs/tools/src/tool_registry_plan_tests.rs index c95fbf40a6e7..9da58849c1be 100644 --- a/codex-rs/tools/src/tool_registry_plan_tests.rs +++ b/codex-rs/tools/src/tool_registry_plan_tests.rs @@ -1294,46 +1294,6 @@ fn search_tool_description_lists_each_mcp_source_once() { })); } -#[test] -fn search_tool_registers_deferred_mcp_flattened_handlers() { - let model_info = search_capable_model_info(); - let mut features = Features::with_defaults(); - features.enable(Feature::ToolSearch); - let available_models = Vec::new(); - let tools_config = ToolsConfig::new(&ToolsConfigParams { - model_info: &model_info, - available_models: &available_models, - features: &features, - image_generation_tool_auth_allowed: true, - web_search_mode: Some(WebSearchMode::Cached), - session_source: SessionSource::Cli, - sandbox_policy: &SandboxPolicy::DangerFullAccess, - windows_sandbox_level: WindowsSandboxLevel::Disabled, - }); - - let (_, handlers) = build_specs( - &tools_config, - /*mcp_tools*/ None, - Some(vec![deferred_mcp_tool( - "js", - "mcp__node_repl__", - "node_repl", - /*connector_name*/ None, - /*connector_description*/ None, - )]), - &[], - ); - - assert!(handlers.contains(&ToolHandlerSpec { - name: ToolName::namespaced("mcp__node_repl__", "js"), - kind: ToolHandlerKind::Mcp, - })); - assert!(handlers.contains(&ToolHandlerSpec { - name: ToolName::plain("mcp__node_repl__js"), - kind: ToolHandlerKind::Mcp, - })); -} - #[test] fn search_tool_requires_model_capability_and_feature_flag() { let model_info = search_capable_model_info();