diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 4382dee292..929d1b8654 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -918,7 +918,9 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> { )?; // Propagate any root-level config overrides (e.g. `-c key=value`). prepend_config_flags(&mut mcp_cli.config_overrides, root_config_overrides.clone()); - mcp_cli.run().await?; + let loader_overrides = + loader_overrides_for_profile(interactive.config_profile_v2.as_ref())?; + mcp_cli.run(loader_overrides).await?; } Some(Subcommand::Plugin(plugin_cli)) => { reject_remote_mode_for_subcommand( @@ -1459,11 +1461,12 @@ fn profile_v2_for_subcommand<'a>( | Subcommand::Review(_) | Subcommand::Resume(_) | Subcommand::Fork(_) + | Subcommand::Mcp(_) | Subcommand::Debug(DebugCommand { subcommand: DebugSubcommand::PromptInput(_), }) => Ok(Some(profile_v2)), _ => anyhow::bail!( - "--profile only applies to runtime commands: `codex`, `codex exec`, `codex review`, `codex resume`, `codex fork`, and `codex debug prompt-input`." + "--profile only applies to runtime commands and `codex mcp`: `codex`, `codex exec`, `codex review`, `codex resume`, `codex fork`, `codex mcp`, and `codex debug prompt-input`." ), } } @@ -2264,6 +2267,12 @@ mod tests { .as_deref(), Some("work") ); + assert_eq!( + profile_v2_for_args(&["codex", "--profile", "work", "mcp", "list"]) + .expect("mcp supports profile-v2") + .as_deref(), + Some("work") + ); } #[test] diff --git a/codex-rs/cli/src/mcp_cmd.rs b/codex-rs/cli/src/mcp_cmd.rs index f52d24160b..3104262c23 100644 --- a/codex-rs/cli/src/mcp_cmd.rs +++ b/codex-rs/cli/src/mcp_cmd.rs @@ -11,6 +11,8 @@ use codex_config::types::McpServerConfig; use codex_config::types::McpServerTransportConfig; use codex_core::McpManager; use codex_core::config::Config; +use codex_core::config::ConfigBuilder; +use codex_core::config::LoaderOverrides; use codex_core::config::edit::ConfigEditsBuilder; use codex_core::config::find_codex_home; use codex_core::config::load_global_mcp_servers; @@ -157,12 +159,16 @@ pub struct LogoutArgs { } impl McpCli { - pub async fn run(self) -> Result<()> { + pub async fn run(self, loader_overrides: LoaderOverrides) -> Result<()> { let McpCli { config_overrides, subcommand, } = self; + if loader_overrides.user_config_profile.is_some() { + validate_profile_v2_migration(&config_overrides, loader_overrides).await?; + } + match subcommand { McpSubcommand::List(args) => { run_list(&config_overrides, args).await?; @@ -239,6 +245,22 @@ async fn perform_oauth_login_retry_without_scopes( } } +async fn validate_profile_v2_migration( + config_overrides: &CliConfigOverrides, + loader_overrides: LoaderOverrides, +) -> Result<()> { + let overrides = config_overrides + .parse_overrides() + .map_err(anyhow::Error::msg)?; + ConfigBuilder::default() + .cli_overrides(overrides) + .loader_overrides(loader_overrides) + .build() + .await + .context("failed to load configuration")?; + Ok(()) +} + async fn run_add(config_overrides: &CliConfigOverrides, add_args: AddArgs) -> Result<()> { // Validate any provided overrides even though they are not currently applied. let overrides = config_overrides diff --git a/codex-rs/cli/tests/mcp_add_remove.rs b/codex-rs/cli/tests/mcp_add_remove.rs index 15afaf0828..ecfbed1264 100644 --- a/codex-rs/cli/tests/mcp_add_remove.rs +++ b/codex-rs/cli/tests/mcp_add_remove.rs @@ -68,6 +68,28 @@ async fn add_and_remove_server_updates_global_config() -> Result<()> { Ok(()) } +#[tokio::test] +async fn profile_mcp_reports_legacy_profile_migration() -> Result<()> { + let codex_home = TempDir::new()?; + std::fs::write( + codex_home.path().join("config.toml"), + r#"[profiles.work] +model = "gpt-5" +"#, + )?; + + let mut list_cmd = codex_command(codex_home.path())?; + list_cmd + .args(["--profile", "work", "mcp", "list"]) + .assert() + .failure() + .stderr(contains("--profile `work` cannot be used")) + .stderr(contains("[profiles.work]")) + .stderr(contains("work.config.toml")); + + Ok(()) +} + #[tokio::test] async fn add_with_env_preserves_key_order_and_values() -> Result<()> { let codex_home = TempDir::new()?;