diff --git a/codex-rs/core/src/mcp.rs b/codex-rs/core/src/mcp.rs index 71571deae..abd28ec61 100644 --- a/codex-rs/core/src/mcp.rs +++ b/codex-rs/core/src/mcp.rs @@ -45,6 +45,12 @@ impl McpManager { /// runtime-only extension overlays. pub async fn runtime_config(&self, config: &Config) -> McpConfig { let mut mcp_config = config.to_mcp_config(self.plugins_manager.as_ref()).await; + let disabled_server_names = mcp_config + .configured_mcp_servers + .iter() + .filter(|(_, server)| !server.enabled) + .map(|(name, _)| name.clone()) + .collect::>(); if mcp_config.apps_enabled { mcp_config.configured_mcp_servers.insert( CODEX_APPS_MCP_SERVER_NAME.to_string(), @@ -60,6 +66,11 @@ impl McpManager { } let contributions = self.contributions(config).await; Self::apply_to_configured_servers(&contributions, &mut mcp_config.configured_mcp_servers); + for name in disabled_server_names { + if let Some(server) = mcp_config.configured_mcp_servers.get_mut(&name) { + server.enabled = false; + } + } mcp_config } diff --git a/codex-rs/ext/mcp/tests/hosted_apps_mcp.rs b/codex-rs/ext/mcp/tests/hosted_apps_mcp.rs index bb401578f..ea1b330ca 100644 --- a/codex-rs/ext/mcp/tests/hosted_apps_mcp.rs +++ b/codex-rs/ext/mcp/tests/hosted_apps_mcp.rs @@ -42,6 +42,34 @@ async fn contributes_hosted_plugin_runtime_without_an_executor() -> TestResult { Ok(()) } +#[tokio::test] +async fn runtime_overlay_preserves_disabled_server() -> TestResult { + let codex_home = tempfile::tempdir()?; + let config = ConfigBuilder::default() + .codex_home(codex_home.path().to_path_buf()) + .fallback_cwd(Some(codex_home.path().to_path_buf())) + .cli_overrides(vec![ + ("features.apps".to_string(), true.into()), + ( + "mcp_servers.codex_apps.url".to_string(), + "https://example.com/mcp".into(), + ), + ("mcp_servers.codex_apps.enabled".to_string(), false.into()), + ]) + .build() + .await?; + let auth = CodexAuth::create_dummy_chatgpt_auth_for_testing(); + let manager = installed_manager(&config); + + let servers = manager.effective_servers(&config, Some(&auth)).await; + let server = servers + .get(CODEX_APPS_MCP_SERVER_NAME) + .ok_or("hosted plugin runtime should remain configured")?; + + assert!(!server.enabled()); + Ok(()) +} + #[tokio::test] async fn legacy_fallback_overwrites_reserved_config_without_an_extension() -> TestResult { let codex_home = tempfile::tempdir()?;