mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
790213ded0
Scope MCP sandbox metadata to the MCP server's owning environment. Previously, `codex/sandbox-state-meta` always used the turn's primary cwd and rebuilt a legacy sandbox policy from that cwd. That can be wrong for MCP servers owned by a different execution environment. This now sends the owning environment cwd as a `file:` URI in `sandboxCwd`, keeps `permissionProfile` as the permission source of truth, and omits sandbox-state metadata when a non-default server environment is not selected for the turn. Local/default MCP servers keep the existing fallback cwd behavior. Tests: - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` - `just test -p codex-mcp` - `just test -p codex-core mcp_sandbox_cwd` - `cargo build -p codex-rmcp-client --bin test_stdio_server` - `just test -p codex-core stdio_mcp_tool_call_includes_sandbox_state_meta`
118 lines
3.5 KiB
Rust
118 lines
3.5 KiB
Rust
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 environment_id: String,
|
|
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 {
|
|
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(),
|
|
},
|
|
}
|
|
}
|
|
}
|