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), } /// 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 { 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 environment_id: String, pub pollutes_memory: bool, pub origin: Option, pub supports_parallel_tool_calls: bool, pub default_tools_approval_mode: Option, pub tool_approval_modes: HashMap, } 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 { environment_id: config.environment_id.clone(), 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(), }, } } }