Files
codex/codex-rs/core/src/mcp_tool_exposure.rs
T
sayan-oai 1dd9bf9a74 Remove explicit connector tool undeferral (#23390)
## Summary
- remove the explicit-connector carveout that kept mentioned app tools
directly exposed instead of deferred
- keep the surviving explicit-mention reconstruction only for analytics,
preserving `codex_app_mentioned` and `codex_app_used.invoke_type`
- trim the now-unused prompt/tool-exposure plumbing and refresh coverage
around always-defer behavior

## Verification
- `just fmt`
- `cargo test -p codex-analytics`
- `cargo test -p codex-core` *(one transient timeout in
`shell_snapshot::tests::macos_zsh_snapshot_includes_sections`; isolated
rerun passed)*
- `cargo test -p codex-core --lib
shell_snapshot::tests::macos_zsh_snapshot_includes_sections`
- `cargo test -p codex-core --test all
explicit_app_mentions_respect_always_defer`
- `cargo test -p codex-core --lib
mcp_tool_exposure::tests::always_defer_feature_defers_apps_too`
- `just fix -p codex-analytics`
- `just fix -p codex-core`
2026-05-18 21:33:46 -07:00

88 lines
2.4 KiB
Rust

use std::collections::HashSet;
use codex_features::Feature;
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_mcp::ToolInfo as McpToolInfo;
use codex_tools::ToolsConfig;
use crate::config::Config;
use crate::connectors;
pub(crate) const DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD: usize = 100;
pub(crate) struct McpToolExposure {
pub(crate) direct_tools: Vec<McpToolInfo>,
pub(crate) deferred_tools: Option<Vec<McpToolInfo>>,
}
pub(crate) fn build_mcp_tool_exposure(
all_mcp_tools: &[McpToolInfo],
connectors: Option<&[connectors::AppInfo]>,
config: &Config,
tools_config: &ToolsConfig,
) -> McpToolExposure {
let mut deferred_tools = filter_non_codex_apps_mcp_tools_only(all_mcp_tools);
if let Some(connectors) = connectors {
deferred_tools.extend(filter_codex_apps_mcp_tools(
all_mcp_tools,
connectors,
config,
));
}
let should_defer = tools_config.search_tool
&& (config
.features
.enabled(Feature::ToolSearchAlwaysDeferMcpTools)
|| deferred_tools.len() >= DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD);
if !should_defer {
return McpToolExposure {
direct_tools: deferred_tools,
deferred_tools: None,
};
}
McpToolExposure {
direct_tools: Vec::new(),
deferred_tools: (!deferred_tools.is_empty()).then_some(deferred_tools),
}
}
fn filter_non_codex_apps_mcp_tools_only(mcp_tools: &[McpToolInfo]) -> Vec<McpToolInfo> {
mcp_tools
.iter()
.filter(|tool| tool.server_name != CODEX_APPS_MCP_SERVER_NAME)
.cloned()
.collect()
}
fn filter_codex_apps_mcp_tools(
mcp_tools: &[McpToolInfo],
connectors: &[connectors::AppInfo],
config: &Config,
) -> Vec<McpToolInfo> {
let allowed: HashSet<&str> = connectors
.iter()
.map(|connector| connector.id.as_str())
.collect();
mcp_tools
.iter()
.filter(|tool| {
if tool.server_name != CODEX_APPS_MCP_SERVER_NAME {
return false;
}
let Some(connector_id) = tool.connector_id.as_deref() else {
return false;
};
allowed.contains(connector_id) && connectors::codex_app_tool_is_enabled(config, tool)
})
.cloned()
.collect()
}
#[cfg(test)]
#[path = "mcp_tool_exposure_test.rs"]
mod tests;