mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
mcp: surface profile migration guidance under --profile (#23890)
## Why `codex --profile <name> mcp ...` should reach the same profile-v2 migration guard as runtime commands. Otherwise legacy `[profiles.<name>]` users see the generic command-scope rejection instead of the existing guidance to move settings into `$CODEX_HOME/<name>.config.toml`. ## What - Allow `codex mcp` through the `--profile` subcommand gate. - Pass profile loader overrides into the MCP entry point only to validate profile-v2 migration when a profile is present. - Keep MCP add/remove/list/get/login/logout behavior otherwise unchanged; this does not add profile-scoped MCP server management. - Cover the legacy profile migration error for `codex --profile work mcp list`. ## Testing - `cargo test -p codex-cli`
This commit is contained in:
committed by
GitHub
Unverified
parent
b14f11d3d2
commit
ed80e5f558
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
Reference in New Issue
Block a user