Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codex-rs/cli/src/mcp_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ async fn run_add(config_overrides: &CliConfigOverrides, add_args: AddArgs) -> Re
transport: transport.clone(),
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/codex-mcp/src/mcp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ fn codex_apps_mcp_server_config(config: &McpConfig, auth: Option<&CodexAuth>) ->
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(30)),
tool_timeout_sec: None,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/codex-mcp/src/mcp/mod_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async fn effective_mcp_servers_preserve_user_servers_and_add_codex_apps() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand All @@ -216,6 +217,7 @@ async fn effective_mcp_servers_preserve_user_servers_and_add_codex_apps() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/codex-mcp/src/mcp/skill_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ fn mcp_dependency_to_server_config(
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand All @@ -147,6 +148,7 @@ fn mcp_dependency_to_server_config(
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/codex-mcp/src/mcp/skill_dependencies_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn collect_missing_respects_canonical_installed_key() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -91,6 +92,7 @@ fn collect_missing_dedupes_by_canonical_key_but_preserves_original_name() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/codex-mcp/src/mcp_connection_manager_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@ fn mcp_init_error_display_prompts_for_github_pat() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -806,6 +807,7 @@ fn mcp_init_error_display_reports_generic_errors() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/config/src/mcp_edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ fn serialize_mcp_server(config: &McpServerConfig) -> TomlItem {
if config.required {
entry["required"] = value(true);
}
if config.supports_parallel_tool_calls {
entry["supports_parallel_tool_calls"] = value(true);
}
if let Some(timeout) = config.startup_timeout_sec {
entry["startup_timeout_sec"] = value(timeout.as_secs_f64());
}
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/config/src/mcp_edit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ async fn replace_mcp_servers_serializes_per_tool_approval_overrides() -> anyhow:
},
enabled: true,
required: false,
supports_parallel_tool_calls: true,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -59,6 +60,7 @@ async fn replace_mcp_servers_serializes_per_tool_approval_overrides() -> anyhow:
serialized,
r#"[mcp_servers.docs]
command = "docs-server"
supports_parallel_tool_calls = true

[mcp_servers.docs.tools]

Expand Down
8 changes: 8 additions & 0 deletions codex-rs/config/src/mcp_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ pub struct McpServerConfig {
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub required: bool,

/// When `true`, every tool from this server is advertised as safe for parallel tool calls.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub supports_parallel_tool_calls: bool,

/// Reason this server was disabled after applying requirements.
#[serde(skip)]
pub disabled_reason: Option<McpServerDisabledReason>,
Expand Down Expand Up @@ -146,6 +150,8 @@ pub struct RawMcpServerConfig {
#[serde(default)]
pub required: Option<bool>,
#[serde(default)]
pub supports_parallel_tool_calls: Option<bool>,
#[serde(default)]
pub enabled_tools: Option<Vec<String>>,
#[serde(default)]
pub disabled_tools: Option<Vec<String>>,
Expand Down Expand Up @@ -180,6 +186,7 @@ impl TryFrom<RawMcpServerConfig> for McpServerConfig {
tool_timeout_sec,
enabled,
required,
supports_parallel_tool_calls,
enabled_tools,
disabled_tools,
scopes,
Expand Down Expand Up @@ -243,6 +250,7 @@ impl TryFrom<RawMcpServerConfig> for McpServerConfig {
tool_timeout_sec,
enabled: enabled.unwrap_or_else(default_enabled),
required: required.unwrap_or_default(),
supports_parallel_tool_calls: supports_parallel_tool_calls.unwrap_or_default(),
disabled_reason: None,
enabled_tools,
disabled_tools,
Expand Down
33 changes: 33 additions & 0 deletions codex-rs/config/src/mcp_types_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,38 @@ fn deserialize_server_config_with_tool_filters() {
assert_eq!(cfg.disabled_tools, Some(vec!["blocked".to_string()]));
}

#[test]
fn deserialize_server_config_with_parallel_tool_calls() {
Comment thread
josiah-openai marked this conversation as resolved.
let cfg: McpServerConfig = toml::from_str(
r#"
command = "echo"
supports_parallel_tool_calls = true
"#,
)
.expect("should deserialize supports_parallel_tool_calls");

assert!(cfg.supports_parallel_tool_calls);
}

#[test]
fn serialize_round_trips_server_config_with_parallel_tool_calls() {
let cfg: McpServerConfig = toml::from_str(
r#"
command = "echo"
supports_parallel_tool_calls = true
tool_timeout_sec = 2.0
"#,
)
.expect("should deserialize supports_parallel_tool_calls");

let serialized = toml::to_string(&cfg).expect("should serialize MCP config");
assert!(serialized.contains("supports_parallel_tool_calls = true"));

let round_tripped: McpServerConfig =
toml::from_str(&serialized).expect("should deserialize serialized MCP config");
assert_eq!(round_tripped, cfg);
}

#[test]
fn deserialize_ignores_unknown_server_fields() {
let cfg: McpServerConfig = toml::from_str(
Expand All @@ -267,6 +299,7 @@ fn deserialize_ignores_unknown_server_fields() {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
4 changes: 4 additions & 0 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,10 @@
"format": "double",
"type": "number"
},
"supports_parallel_tool_calls": {
"default": null,
"type": "boolean"
},
"tool_timeout_sec": {
"default": null,
"format": "double",
Expand Down
15 changes: 14 additions & 1 deletion codex-rs/core/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7127,11 +7127,24 @@ pub(crate) async fn built_tools(
);
let direct_mcp_tools = has_mcp_servers.then_some(mcp_tool_exposure.direct_tools);

let parallel_mcp_server_names = turn_context
.config
.mcp_servers
.get()
.iter()
.filter_map(|(server_name, server_config)| {
server_config
.supports_parallel_tool_calls
.then_some(server_name.clone())
})
.collect::<HashSet<_>>();

Ok(Arc::new(ToolRouter::from_config(
&turn_context.tools_config,
ToolRouterParams {
deferred_mcp_tools: mcp_tool_exposure.deferred_tools,
mcp_tools: direct_mcp_tools,
deferred_mcp_tools: mcp_tool_exposure.deferred_tools,
parallel_mcp_server_names,
discoverable_tools,
dynamic_tools: turn_context.dynamic_tools.as_slice(),
},
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/core/src/codex_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ fn test_tool_runtime(session: Arc<Session>, turn_context: Arc<TurnContext>) -> T
crate::tools::router::ToolRouterParams {
mcp_tools: None,
deferred_mcp_tools: None,
parallel_mcp_server_names: HashSet::new(),
discoverable_tools: None,
dynamic_tools: turn_context.dynamic_tools.as_slice(),
},
Expand Down Expand Up @@ -5353,6 +5354,7 @@ async fn fatal_tool_error_stops_turn_and_reports_error() {
crate::tools::router::ToolRouterParams {
deferred_mcp_tools,
mcp_tools: Some(tools),
parallel_mcp_server_names: HashSet::new(),
discoverable_tools: None,
dynamic_tools: turn_context.dynamic_tools.as_slice(),
},
Expand Down
16 changes: 16 additions & 0 deletions codex-rs/core/src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fn stdio_mcp(command: &str) -> McpServerConfig {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand All @@ -104,6 +105,7 @@ fn http_mcp(url: &str) -> McpServerConfig {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2011,6 +2013,7 @@ async fn replace_mcp_servers_round_trips_entries() -> anyhow::Result<()> {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(3)),
tool_timeout_sec: Some(Duration::from_secs(5)),
Expand Down Expand Up @@ -2257,6 +2260,7 @@ async fn replace_mcp_servers_serializes_env_sorted() -> anyhow::Result<()> {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2330,6 +2334,7 @@ async fn replace_mcp_servers_serializes_env_vars() -> anyhow::Result<()> {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2383,6 +2388,7 @@ async fn replace_mcp_servers_serializes_cwd() -> anyhow::Result<()> {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2434,6 +2440,7 @@ async fn replace_mcp_servers_streamable_http_serializes_bearer_token() -> anyhow
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(2)),
tool_timeout_sec: None,
Expand Down Expand Up @@ -2501,6 +2508,7 @@ async fn replace_mcp_servers_streamable_http_serializes_custom_headers() -> anyh
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(2)),
tool_timeout_sec: None,
Expand Down Expand Up @@ -2580,6 +2588,7 @@ async fn replace_mcp_servers_streamable_http_removes_optional_sections() -> anyh
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(2)),
tool_timeout_sec: None,
Expand Down Expand Up @@ -2612,6 +2621,7 @@ async fn replace_mcp_servers_streamable_http_removes_optional_sections() -> anyh
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2679,6 +2689,7 @@ async fn replace_mcp_servers_streamable_http_isolates_headers_between_servers()
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: Some(Duration::from_secs(2)),
tool_timeout_sec: None,
Expand All @@ -2701,6 +2712,7 @@ async fn replace_mcp_servers_streamable_http_isolates_headers_between_servers()
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2786,6 +2798,7 @@ async fn replace_mcp_servers_serializes_disabled_flag() -> anyhow::Result<()> {
},
enabled: false,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2833,6 +2846,7 @@ async fn replace_mcp_servers_serializes_required_flag() -> anyhow::Result<()> {
},
enabled: true,
required: true,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2880,6 +2894,7 @@ async fn replace_mcp_servers_serializes_tool_filters() -> anyhow::Result<()> {
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down Expand Up @@ -2931,6 +2946,7 @@ async fn replace_mcp_servers_streamable_http_serializes_oauth_resource() -> anyh
},
enabled: true,
required: false,
supports_parallel_tool_calls: false,
disabled_reason: None,
startup_timeout_sec: None,
tool_timeout_sec: None,
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/core/src/config/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ mod document_helpers {
if config.required {
entry["required"] = value(true);
}
if config.supports_parallel_tool_calls {
entry["supports_parallel_tool_calls"] = value(true);
}
if let Some(timeout) = config.startup_timeout_sec {
entry["startup_timeout_sec"] = value(timeout.as_secs_f64());
}
Expand Down
Loading
Loading