Codex Handbook
codex-mcp/src/server.rs 115 lines
use std::collections::HashMap;use codex_config::AppToolApproval;use codex_config::McpServerConfig;use codex_config::McpServerTransportConfig;/// The runtime launch strategy for an effective MCP server.#[derive(Debug, Clone)]pub(crate) enum McpServerLaunch {    Configured(Box<McpServerConfig>),}/// MCP server after runtime additions have been applied.#[derive(Debug, Clone)]pub struct EffectiveMcpServer {    launch: McpServerLaunch,}impl EffectiveMcpServer {    pub fn configured(config: McpServerConfig) -> Self {        Self {            launch: McpServerLaunch::Configured(Box::new(config)),        }    }    pub(crate) fn launch(&self) -> &McpServerLaunch {        &self.launch    }    pub fn configured_config(&self) -> Option<&McpServerConfig> {        match &self.launch {            McpServerLaunch::Configured(config) => Some(config.as_ref()),        }    }    pub fn enabled(&self) -> bool {        match &self.launch {            McpServerLaunch::Configured(config) => config.enabled,        }    }    pub fn required(&self) -> bool {        match &self.launch {            McpServerLaunch::Configured(config) => config.required,        }    }}/// Transport origin retained for metrics and diagnostics after server launch.#[derive(Debug, Clone, PartialEq, Eq)]pub(crate) enum McpServerOrigin {    Stdio,    StreamableHttp(String),}impl McpServerOrigin {    pub fn as_str(&self) -> &str {        match self {            Self::Stdio => "stdio",            Self::StreamableHttp(origin) => origin,        }    }    fn from_transport(transport: &McpServerTransportConfig) -> Option<Self> {        match transport {            McpServerTransportConfig::StreamableHttp { url, .. } => {                let parsed = url::Url::parse(url).ok()?;                Some(Self::StreamableHttp(parsed.origin().ascii_serialization()))            }            McpServerTransportConfig::Stdio { .. } => Some(Self::Stdio),        }    }}/// Semantic metadata that must survive after the server is launched.#[derive(Debug, Clone)]pub(crate) struct McpServerMetadata {    pub pollutes_memory: bool,    pub origin: Option<McpServerOrigin>,    pub supports_parallel_tool_calls: bool,    pub default_tools_approval_mode: Option<AppToolApproval>,    pub tool_approval_modes: HashMap<String, AppToolApproval>,}impl McpServerMetadata {    pub fn tool_approval_mode(&self, tool_name: &str) -> AppToolApproval {        self.tool_approval_modes            .get(tool_name)            .copied()            .or(self.default_tools_approval_mode)            .unwrap_or_default()    }}impl From<&EffectiveMcpServer> for McpServerMetadata {    fn from(server: &EffectiveMcpServer) -> Self {        match server.launch() {            McpServerLaunch::Configured(config) => Self {                pollutes_memory: true,                origin: McpServerOrigin::from_transport(&config.transport),                supports_parallel_tool_calls: config.supports_parallel_tool_calls,                default_tools_approval_mode: config.default_tools_approval_mode,                tool_approval_modes: config                    .tools                    .iter()                    .filter_map(|(name, config)| {                        config                            .approval_mode                            .map(|approval_mode| (name.clone(), approval_mode))                    })                    .collect(),            },        }    }}