From 987dd7fde332fdbfe37a3b2b2881376ed091bc0a Mon Sep 17 00:00:00 2001 From: Shijie Rao Date: Sat, 20 Dec 2025 14:18:00 -0800 Subject: [PATCH] Chore: remove rmcp feature and exp flag usages (#8087) ### Summary With codesigning on Mac, Windows and Linux, we should be able to safely remove `features.rmcp_client` and `use_experimental_use_rmcp_client` check from the codebase now. --- .../app-server/src/codex_message_processor.rs | 10 ---- codex-rs/cli/src/mcp_cmd.rs | 51 ++++--------------- codex-rs/core/src/config/mod.rs | 14 ----- codex-rs/core/src/config/profile.rs | 1 - codex-rs/core/src/features.rs | 11 ---- codex-rs/core/src/features/legacy.rs | 11 ---- codex-rs/core/tests/suite/rmcp_client.rs | 7 --- codex-rs/core/tests/suite/truncation.rs | 4 -- docs/config.md | 10 +--- docs/example-config.md | 1 - 10 files changed, 12 insertions(+), 108 deletions(-) diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 8c48436b6e..d1804801d5 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -1992,16 +1992,6 @@ impl CodexMessageProcessor { } }; - if !config.features.enabled(Feature::RmcpClient) { - let error = JSONRPCErrorError { - code: INVALID_REQUEST_ERROR_CODE, - message: "OAuth login is only supported when [features].rmcp_client is true in config.toml".to_string(), - data: None, - }; - self.outgoing.send_error(request_id, error).await; - return; - } - let McpServerOauthLoginParams { name, scopes, diff --git a/codex-rs/cli/src/mcp_cmd.rs b/codex-rs/cli/src/mcp_cmd.rs index 9dcc4e2140..ef872e5972 100644 --- a/codex-rs/cli/src/mcp_cmd.rs +++ b/codex-rs/cli/src/mcp_cmd.rs @@ -13,15 +13,12 @@ use codex_core::config::find_codex_home; use codex_core::config::load_global_mcp_servers; use codex_core::config::types::McpServerConfig; use codex_core::config::types::McpServerTransportConfig; -use codex_core::features::Feature; use codex_core::mcp::auth::compute_auth_statuses; use codex_core::protocol::McpAuthStatus; use codex_rmcp_client::delete_oauth_tokens; use codex_rmcp_client::perform_oauth_login; use codex_rmcp_client::supports_oauth_login; -/// [experimental] Launch Codex as an MCP server or manage configured MCP servers. -/// /// Subcommands: /// - `serve` — run the MCP server on stdio /// - `list` — list configured servers (with `--json`) @@ -39,24 +36,11 @@ pub struct McpCli { #[derive(Debug, clap::Subcommand)] pub enum McpSubcommand { - /// [experimental] List configured MCP servers. List(ListArgs), - - /// [experimental] Show details for a configured MCP server. Get(GetArgs), - - /// [experimental] Add a global MCP server entry. Add(AddArgs), - - /// [experimental] Remove a global MCP server entry. Remove(RemoveArgs), - - /// [experimental] Authenticate with a configured MCP server via OAuth. - /// Requires features.rmcp_client = true in config.toml. Login(LoginArgs), - - /// [experimental] Remove stored OAuth credentials for a server. - /// Requires features.rmcp_client = true in config.toml. Logout(LogoutArgs), } @@ -282,24 +266,17 @@ async fn run_add(config_overrides: &CliConfigOverrides, add_args: AddArgs) -> Re { match supports_oauth_login(&url).await { Ok(true) => { - if !config.features.enabled(Feature::RmcpClient) { - println!( - "MCP server supports login. Add `features.rmcp_client = true` \ - to your config.toml and run `codex mcp login {name}` to login." - ); - } else { - println!("Detected OAuth support. Starting OAuth flow…"); - perform_oauth_login( - &name, - &url, - config.mcp_oauth_credentials_store_mode, - http_headers.clone(), - env_http_headers.clone(), - &Vec::new(), - ) - .await?; - println!("Successfully logged in."); - } + println!("Detected OAuth support. Starting OAuth flow…"); + perform_oauth_login( + &name, + &url, + config.mcp_oauth_credentials_store_mode, + http_headers.clone(), + env_http_headers.clone(), + &Vec::new(), + ) + .await?; + println!("Successfully logged in."); } Ok(false) => {} Err(_) => println!( @@ -352,12 +329,6 @@ async fn run_login(config_overrides: &CliConfigOverrides, login_args: LoginArgs) .await .context("failed to load configuration")?; - if !config.features.enabled(Feature::RmcpClient) { - bail!( - "OAuth login is only supported when [features].rmcp_client is true in config.toml. See https://github.com/openai/codex/blob/main/docs/config.md#feature-flags for details." - ); - } - let LoginArgs { name, scopes } = login_args; let Some(server) = config.mcp_servers.get(&name) else { diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 397b3c0a2b..b6cbb05499 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -322,10 +322,6 @@ pub struct Config { /// If set to `true`, used only the experimental unified exec tool. pub use_experimental_unified_exec_tool: bool, - /// If set to `true`, use the experimental official Rust MCP client. - /// https://github.com/modelcontextprotocol/rust-sdk - pub use_experimental_use_rmcp_client: bool, - /// Settings for ghost snapshots (used for undo). pub ghost_snapshot: GhostSnapshotConfig, @@ -827,7 +823,6 @@ pub struct ConfigToml { pub experimental_instructions_file: Option, pub experimental_compact_prompt_file: Option, pub experimental_use_unified_exec_tool: Option, - pub experimental_use_rmcp_client: Option, pub experimental_use_freeform_apply_patch: Option, /// Preferred OSS provider for local models, e.g. "lmstudio" or "ollama". pub oss_provider: Option, @@ -1243,7 +1238,6 @@ impl Config { let include_apply_patch_tool_flag = features.enabled(Feature::ApplyPatchFreeform); let tools_web_search_request = features.enabled(Feature::WebSearchRequest); let use_experimental_unified_exec_tool = features.enabled(Feature::UnifiedExec); - let use_experimental_use_rmcp_client = features.enabled(Feature::RmcpClient); let forced_chatgpt_workspace_id = cfg.forced_chatgpt_workspace_id.as_ref().and_then(|value| { @@ -1383,7 +1377,6 @@ impl Config { include_apply_patch_tool: include_apply_patch_tool_flag, tools_web_search_request, use_experimental_unified_exec_tool, - use_experimental_use_rmcp_client, ghost_snapshot, features, active_profile: active_profile_name, @@ -1997,7 +1990,6 @@ trust_level = "trusted" let codex_home = TempDir::new()?; let cfg = ConfigToml { experimental_use_unified_exec_tool: Some(true), - experimental_use_rmcp_client: Some(true), experimental_use_freeform_apply_patch: Some(true), ..Default::default() }; @@ -2010,12 +2002,10 @@ trust_level = "trusted" assert!(config.features.enabled(Feature::ApplyPatchFreeform)); assert!(config.features.enabled(Feature::UnifiedExec)); - assert!(config.features.enabled(Feature::RmcpClient)); assert!(config.include_apply_patch_tool); assert!(config.use_experimental_unified_exec_tool); - assert!(config.use_experimental_use_rmcp_client); Ok(()) } @@ -3196,7 +3186,6 @@ model_verbosity = "high" include_apply_patch_tool: false, tools_web_search_request: false, use_experimental_unified_exec_tool: false, - use_experimental_use_rmcp_client: false, ghost_snapshot: GhostSnapshotConfig::default(), features: Features::with_defaults(), active_profile: Some("o3".to_string()), @@ -3280,7 +3269,6 @@ model_verbosity = "high" include_apply_patch_tool: false, tools_web_search_request: false, use_experimental_unified_exec_tool: false, - use_experimental_use_rmcp_client: false, ghost_snapshot: GhostSnapshotConfig::default(), features: Features::with_defaults(), active_profile: Some("gpt3".to_string()), @@ -3379,7 +3367,6 @@ model_verbosity = "high" include_apply_patch_tool: false, tools_web_search_request: false, use_experimental_unified_exec_tool: false, - use_experimental_use_rmcp_client: false, ghost_snapshot: GhostSnapshotConfig::default(), features: Features::with_defaults(), active_profile: Some("zdr".to_string()), @@ -3464,7 +3451,6 @@ model_verbosity = "high" include_apply_patch_tool: false, tools_web_search_request: false, use_experimental_unified_exec_tool: false, - use_experimental_use_rmcp_client: false, ghost_snapshot: GhostSnapshotConfig::default(), features: Features::with_defaults(), active_profile: Some("gpt5".to_string()), diff --git a/codex-rs/core/src/config/profile.rs b/codex-rs/core/src/config/profile.rs index b74b70887d..718d97205a 100644 --- a/codex-rs/core/src/config/profile.rs +++ b/codex-rs/core/src/config/profile.rs @@ -25,7 +25,6 @@ pub struct ConfigProfile { pub experimental_compact_prompt_file: Option, pub include_apply_patch_tool: Option, pub experimental_use_unified_exec_tool: Option, - pub experimental_use_rmcp_client: Option, pub experimental_use_freeform_apply_patch: Option, pub tools_web_search: Option, pub tools_view_image: Option, diff --git a/codex-rs/core/src/features.rs b/codex-rs/core/src/features.rs index 22fd310b99..443d9a87e8 100644 --- a/codex-rs/core/src/features.rs +++ b/codex-rs/core/src/features.rs @@ -69,8 +69,6 @@ pub enum Feature { // Experimental /// Use the single unified PTY-backed exec tool. UnifiedExec, - /// Enable experimental RMCP features such as OAuth login. - RmcpClient, /// Include the freeform apply_patch tool. ApplyPatchFreeform, /// Allow the model to request web searches. @@ -226,7 +224,6 @@ impl Features { let base_legacy = LegacyFeatureToggles { experimental_use_freeform_apply_patch: cfg.experimental_use_freeform_apply_patch, experimental_use_unified_exec_tool: cfg.experimental_use_unified_exec_tool, - experimental_use_rmcp_client: cfg.experimental_use_rmcp_client, tools_web_search: cfg.tools.as_ref().and_then(|t| t.web_search), tools_view_image: cfg.tools.as_ref().and_then(|t| t.view_image), ..Default::default() @@ -243,7 +240,6 @@ impl Features { .experimental_use_freeform_apply_patch, experimental_use_unified_exec_tool: config_profile.experimental_use_unified_exec_tool, - experimental_use_rmcp_client: config_profile.experimental_use_rmcp_client, tools_web_search: config_profile.tools_web_search, tools_view_image: config_profile.tools_view_image, }; @@ -348,13 +344,6 @@ pub const FEATURES: &[FeatureSpec] = &[ }, default_enabled: false, }, - // Unstable features. - FeatureSpec { - id: Feature::RmcpClient, - key: "rmcp_client", - stage: Stage::Experimental, - default_enabled: false, - }, FeatureSpec { id: Feature::ApplyPatchFreeform, key: "apply_patch_freeform", diff --git a/codex-rs/core/src/features/legacy.rs b/codex-rs/core/src/features/legacy.rs index 19210c6759..09a982569f 100644 --- a/codex-rs/core/src/features/legacy.rs +++ b/codex-rs/core/src/features/legacy.rs @@ -17,10 +17,6 @@ const ALIASES: &[Alias] = &[ legacy_key: "experimental_use_unified_exec_tool", feature: Feature::UnifiedExec, }, - Alias { - legacy_key: "experimental_use_rmcp_client", - feature: Feature::RmcpClient, - }, Alias { legacy_key: "experimental_use_freeform_apply_patch", feature: Feature::ApplyPatchFreeform, @@ -50,7 +46,6 @@ pub struct LegacyFeatureToggles { pub include_apply_patch_tool: Option, pub experimental_use_freeform_apply_patch: Option, pub experimental_use_unified_exec_tool: Option, - pub experimental_use_rmcp_client: Option, pub tools_web_search: Option, pub tools_view_image: Option, } @@ -75,12 +70,6 @@ impl LegacyFeatureToggles { self.experimental_use_unified_exec_tool, "experimental_use_unified_exec_tool", ); - set_if_some( - features, - Feature::RmcpClient, - self.experimental_use_rmcp_client, - "experimental_use_rmcp_client", - ); set_if_some( features, Feature::WebSearchRequest, diff --git a/codex-rs/core/tests/suite/rmcp_client.rs b/codex-rs/core/tests/suite/rmcp_client.rs index ef2fc16ede..617b3b8a21 100644 --- a/codex-rs/core/tests/suite/rmcp_client.rs +++ b/codex-rs/core/tests/suite/rmcp_client.rs @@ -10,7 +10,6 @@ use std::time::UNIX_EPOCH; use codex_core::config::types::McpServerConfig; use codex_core::config::types::McpServerTransportConfig; -use codex_core::features::Feature; use codex_core::protocol::AskForApproval; use codex_core::protocol::EventMsg; @@ -79,7 +78,6 @@ async fn stdio_server_round_trip() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -217,7 +215,6 @@ async fn stdio_image_responses_round_trip() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -413,7 +410,6 @@ async fn stdio_image_completions_round_trip() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { config.model_provider.wire_api = codex_core::WireApi::Chat; - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -560,7 +556,6 @@ async fn stdio_server_propagates_whitelisted_env_vars() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -710,7 +705,6 @@ async fn streamable_http_tool_call_round_trip() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -891,7 +885,6 @@ async fn streamable_http_with_oauth_round_trip() -> anyhow::Result<()> { let fixture = test_codex() .with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { diff --git a/codex-rs/core/tests/suite/truncation.rs b/codex-rs/core/tests/suite/truncation.rs index e5ab28a5eb..4b916e51b4 100644 --- a/codex-rs/core/tests/suite/truncation.rs +++ b/codex-rs/core/tests/suite/truncation.rs @@ -5,7 +5,6 @@ use anyhow::Context; use anyhow::Result; use codex_core::config::types::McpServerConfig; use codex_core::config::types::McpServerTransportConfig; -use codex_core::features::Feature; use codex_core::protocol::AskForApproval; use codex_core::protocol::EventMsg; use codex_core::protocol::Op; @@ -421,7 +420,6 @@ async fn mcp_tool_call_output_exceeds_limit_truncated_for_model() -> Result<()> .into_owned(); let mut builder = test_codex().with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), codex_core::config::types::McpServerConfig { @@ -511,7 +509,6 @@ async fn mcp_image_output_preserves_image_and_no_text_summary() -> Result<()> { let openai_png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMB/ee9bQAAAABJRU5ErkJggg=="; let mut builder = test_codex().with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.mcp_servers.insert( server_name.to_string(), McpServerConfig { @@ -774,7 +771,6 @@ async fn mcp_tool_call_output_not_truncated_with_custom_limit() -> Result<()> { .into_owned(); let mut builder = test_codex().with_config(move |config| { - config.features.enable(Feature::RmcpClient); config.tool_output_token_limit = Some(50_000); config.mcp_servers.insert( server_name.to_string(), diff --git a/docs/config.md b/docs/config.md index 691f436068..0101cb1036 100644 --- a/docs/config.md +++ b/docs/config.md @@ -42,7 +42,6 @@ Supported features: | Key | Default | Stage | Description | | ------------------------------------- | :-----: | ------------ | ----------------------------------------------------- | | `unified_exec` | false | Experimental | Use the unified PTY-backed exec tool | -| `rmcp_client` | false | Experimental | Enable oauth support for streamable HTTP MCP servers | | `apply_patch_freeform` | false | Beta | Include the freeform `apply_patch` tool | | `view_image_tool` | true | Stable | Include the `view_image` tool | | `web_search_request` | false | Stable | Allow the model to issue web searches | @@ -465,14 +464,7 @@ http_headers = { "HEADER_NAME" = "HEADER_VALUE" } env_http_headers = { "HEADER_NAME" = "ENV_VAR" } ``` -Streamable HTTP connections always use the experimental Rust MCP client under the hood, so expect occasional rough edges. OAuth login flows are gated on the `rmcp_client = true` flag: - -```toml -[features] -rmcp_client = true -``` - -After enabling it, run `codex mcp login ` when the server supports OAuth. +Streamable HTTP connections always use the Rust MCP client under the hood. Run `codex mcp login ` to authenticate for servers supporting OAuth. #### Other configuration options diff --git a/docs/example-config.md b/docs/example-config.md index c5e1840544..f185aaa2ae 100644 --- a/docs/example-config.md +++ b/docs/example-config.md @@ -214,7 +214,6 @@ view_image = true [features] # Leave this table empty to accept defaults. Set explicit booleans to opt in/out. unified_exec = false -rmcp_client = false apply_patch_freeform = false view_image_tool = true web_search_request = false