use std::path::Path; use anyhow::Result; use codex_core::config::load_global_mcp_servers; use codex_core::config_types::McpServerTransportConfig; use predicates::str::contains; use pretty_assertions::assert_eq; use tempfile::TempDir; fn codex_command(codex_home: &Path) -> Result { let mut cmd = assert_cmd::Command::cargo_bin("codex")?; cmd.env("CODEX_HOME", codex_home); Ok(cmd) } #[tokio::test] async fn add_and_remove_server_updates_global_config() -> Result<()> { let codex_home = TempDir::new()?; let mut add_cmd = codex_command(codex_home.path())?; add_cmd .args(["mcp", "add", "docs", "--", "echo", "hello"]) .assert() .success() .stdout(contains("Added global MCP server 'docs'.")); let servers = load_global_mcp_servers(codex_home.path()).await?; assert_eq!(servers.len(), 1); let docs = servers.get("docs").expect("server should exist"); match &docs.transport { McpServerTransportConfig::Stdio { command, args, env } => { assert_eq!(command, "echo"); assert_eq!(args, &vec!["hello".to_string()]); assert!(env.is_none()); } other => panic!("unexpected transport: {other:?}"), } let mut remove_cmd = codex_command(codex_home.path())?; remove_cmd .args(["mcp", "remove", "docs"]) .assert() .success() .stdout(contains("Removed global MCP server 'docs'.")); let servers = load_global_mcp_servers(codex_home.path()).await?; assert!(servers.is_empty()); let mut remove_again_cmd = codex_command(codex_home.path())?; remove_again_cmd .args(["mcp", "remove", "docs"]) .assert() .success() .stdout(contains("No MCP server named 'docs' found.")); let servers = load_global_mcp_servers(codex_home.path()).await?; assert!(servers.is_empty()); Ok(()) } #[tokio::test] async fn add_with_env_preserves_key_order_and_values() -> Result<()> { let codex_home = TempDir::new()?; let mut add_cmd = codex_command(codex_home.path())?; add_cmd .args([ "mcp", "add", "envy", "--env", "FOO=bar", "--env", "ALPHA=beta", "--", "python", "server.py", ]) .assert() .success(); let servers = load_global_mcp_servers(codex_home.path()).await?; let envy = servers.get("envy").expect("server should exist"); let env = match &envy.transport { McpServerTransportConfig::Stdio { env: Some(env), .. } => env, other => panic!("unexpected transport: {other:?}"), }; assert_eq!(env.len(), 2); assert_eq!(env.get("FOO"), Some(&"bar".to_string())); assert_eq!(env.get("ALPHA"), Some(&"beta".to_string())); Ok(()) }