Codex Handbook
ext/mcp/tests/executor_plugin_mcp.rs 139 lines
use codex_config::test_support::CloudConfigBundleFixture;use codex_core::config::Config;use codex_core::config::ConfigBuilder;use codex_exec_server::EnvironmentManager;use codex_exec_server::LOCAL_ENVIRONMENT_ID;use codex_extension_api::ExtensionDataInit;use codex_extension_api::ExtensionRegistryBuilder;use codex_extension_api::McpServerContribution;use codex_extension_api::McpServerContributionContext;use codex_protocol::capabilities::CapabilityRootLocation;use codex_protocol::capabilities::SelectedCapabilityRoot;use pretty_assertions::assert_eq;use std::sync::Arc;type TestResult = Result<(), Box<dyn std::error::Error>>;#[derive(Debug, PartialEq, Eq)]struct ContributionSummary {    name: String,    plugin_id: String,    plugin_display_name: String,    selection_order: usize,    enabled: bool,}#[tokio::test]async fn selected_plugin_servers_use_managed_requirements_for_the_selected_root_id() -> TestResult {    let codex_home = tempfile::tempdir()?;    let plugin_root = tempfile::tempdir()?;    std::fs::create_dir_all(plugin_root.path().join(".codex-plugin"))?;    std::fs::write(        plugin_root.path().join(".codex-plugin/plugin.json"),        r#"{"name":"different-manifest-name","interface":{"displayName":"Selected Demo"}}"#,    )?;    std::fs::write(        plugin_root.path().join(".mcp.json"),        r#"{  "mcpServers": {    "allowed": {"command":"allowed-command"},    "mismatched": {"command":"wrong-command"},    "unlisted": {"command":"unlisted-command"}  }}"#,    )?;    let config = ConfigBuilder::default()        .codex_home(codex_home.path().to_path_buf())        .fallback_cwd(Some(codex_home.path().to_path_buf()))        .cloud_config_bundle(            CloudConfigBundleFixture::loader_with_enterprise_requirement(                r#"[plugins."selected-root".mcp_servers.allowed.identity]command = "allowed-command"[plugins."selected-root".mcp_servers.mismatched.identity]command = "expected-command""#,            ),        )        .build()        .await?;    let contributions = selected_plugin_contributions(&config, plugin_root.path()).await;    assert_eq!(        contributions,        vec![            ContributionSummary {                name: "allowed".to_string(),                plugin_id: "selected-root".to_string(),                plugin_display_name: "Selected Demo".to_string(),                selection_order: 0,                enabled: true,            },            ContributionSummary {                name: "mismatched".to_string(),                plugin_id: "selected-root".to_string(),                plugin_display_name: "Selected Demo".to_string(),                selection_order: 0,                enabled: false,            },            ContributionSummary {                name: "unlisted".to_string(),                plugin_id: "selected-root".to_string(),                plugin_display_name: "Selected Demo".to_string(),                selection_order: 0,                enabled: false,            },        ]    );    Ok(())}async fn selected_plugin_contributions(    config: &Config,    plugin_root: &std::path::Path,) -> Vec<ContributionSummary> {    let mut builder = ExtensionRegistryBuilder::new();    codex_mcp_extension::install_executor_plugins(        &mut builder,        Arc::new(EnvironmentManager::default_for_tests()),    );    let registry = builder.build();    let mut thread_init = ExtensionDataInit::new();    thread_init.insert(vec![SelectedCapabilityRoot {        id: "selected-root".to_string(),        location: CapabilityRootLocation::Environment {            environment_id: LOCAL_ENVIRONMENT_ID.to_string(),            path: plugin_root.to_string_lossy().into_owned(),        },    }]);    codex_mcp_extension::initialize_executor_plugin_thread_data(&mut thread_init);    registry.mcp_server_contributors()[0]        .contribute(McpServerContributionContext::for_thread(            config,            &thread_init,        ))        .await        .into_iter()        .map(|contribution| match contribution {            McpServerContribution::SelectedPlugin {                name,                plugin_id,                plugin_display_name,                selection_order,                config,            } => ContributionSummary {                name,                plugin_id,                plugin_display_name,                selection_order,                enabled: config.enabled,            },            McpServerContribution::Set { .. } | McpServerContribution::Remove { .. } => {                panic!("expected selected plugin contribution")            }        })        .collect()}