1use std::collections::HashMap;
2
3use codex_config::AppToolApproval;
4use codex_config::McpServerConfig;
5use codex_config::McpServerTransportConfig;
6
7#[derive(Debug, Clone)]
9pub(crate) enum McpServerLaunch {
10 Configured(Box<McpServerConfig>),
11}
12
13#[derive(Debug, Clone)]
15pub struct EffectiveMcpServer {
16 launch: McpServerLaunch,
17}
18
19impl EffectiveMcpServer {
20 pub fn configured(config: McpServerConfig) -> Self {
21 Self {
22 launch: McpServerLaunch::Configured(Box::new(config)),
23 }
24 }
25
26 pub(crate) fn launch(&self) -> &McpServerLaunch {
27 &self.launch
28 }
29
30 pub fn configured_config(&self) -> Option<&McpServerConfig> {
31 match &self.launch {
32 McpServerLaunch::Configured(config) => Some(config.as_ref()),
33 }
34 }
35
36 pub fn enabled(&self) -> bool {
37 match &self.launch {
38 McpServerLaunch::Configured(config) => config.enabled,
39 }
40 }
41
42 pub fn required(&self) -> bool {
43 match &self.launch {
44 McpServerLaunch::Configured(config) => config.required,
45 }
46 }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq)]
51pub(crate) enum McpServerOrigin {
52 Stdio,
53 StreamableHttp(String),
54}
55
56impl McpServerOrigin {
57 pub fn as_str(&self) -> &str {
58 match self {
59 Self::Stdio => "stdio",
60 Self::StreamableHttp(origin) => origin,
61 }
62 }
63
64 fn from_transport(transport: &McpServerTransportConfig) -> Option<Self> {
65 match transport {
66 McpServerTransportConfig::StreamableHttp { url, .. } => {
67 let parsed = url::Url::parse(url).ok()?;
68 Some(Self::StreamableHttp(parsed.origin().ascii_serialization()))
69 }
70 McpServerTransportConfig::Stdio { .. } => Some(Self::Stdio),
71 }
72 }
73}
74
75#[derive(Debug, Clone)]
77pub(crate) struct McpServerMetadata {
78 pub environment_id: String,
79 pub pollutes_memory: bool,
80 pub origin: Option<McpServerOrigin>,
81 pub supports_parallel_tool_calls: bool,
82 pub default_tools_approval_mode: Option<AppToolApproval>,
83 pub tool_approval_modes: HashMap<String, AppToolApproval>,
84}
85
86impl McpServerMetadata {
87 pub fn tool_approval_mode(&self, tool_name: &str) -> AppToolApproval {
88 self.tool_approval_modes
89 .get(tool_name)
90 .copied()
91 .or(self.default_tools_approval_mode)
92 .unwrap_or_default()
93 }
94}
95
96impl From<&EffectiveMcpServer> for McpServerMetadata {
97 fn from(server: &EffectiveMcpServer) -> Self {
98 match server.launch() {
99 McpServerLaunch::Configured(config) => Self {
100 environment_id: config.environment_id.clone(),
101 pollutes_memory: true,
102 origin: McpServerOrigin::from_transport(&config.transport),
103 supports_parallel_tool_calls: config.supports_parallel_tool_calls,
104 default_tools_approval_mode: config.default_tools_approval_mode,
105 tool_approval_modes: config
106 .tools
107 .iter()
108 .filter_map(|(name, config)| {
109 config
110 .approval_mode
111 .map(|approval_mode| (name.clone(), approval_mode))
112 })
113 .collect(),
114 },
115 }
116 }
117}