Covert to use absolutePathBuf for mcp cwd

This commit is contained in:
shijie-openai
2026-01-20 18:12:25 -08:00
parent 8a7ee646c5
commit 620164e511
4 changed files with 24 additions and 34 deletions

View File

@@ -1104,7 +1104,11 @@
},
"cwd": {
"default": null,
"type": "string"
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
}
]
},
"disabled_tools": {
"default": null,

View File

@@ -2864,7 +2864,7 @@ ZIG_VAR = "3"
async fn replace_mcp_servers_serializes_cwd() -> anyhow::Result<()> {
let codex_home = TempDir::new()?;
let cwd_path = PathBuf::from("/tmp/codex-mcp");
let cwd_path = AbsolutePathBuf::from_absolute_path("/tmp/codex-mcp").expect("expected cwd");
let servers = BTreeMap::from([(
"docs".to_string(),
McpServerConfig {
@@ -2901,7 +2901,10 @@ ZIG_VAR = "3"
let docs = loaded.get("docs").expect("docs entry");
match &docs.transport {
McpServerTransportConfig::Stdio { cwd, .. } => {
assert_eq!(cwd.as_deref(), Some(Path::new("/tmp/codex-mcp")));
assert_eq!(
cwd.as_ref().map(AbsolutePathBuf::as_path),
Some(Path::new("/tmp/codex-mcp"))
);
}
other => panic!("unexpected transport {other:?}"),
}

View File

@@ -10,7 +10,6 @@ use codex_utils_absolute_path::AbsolutePathBuf;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt;
use std::path::PathBuf;
use std::time::Duration;
use wildmatch::WildMatchPattern;
@@ -88,7 +87,7 @@ pub(crate) struct RawMcpServerConfig {
#[serde(default)]
pub env_vars: Option<Vec<String>>,
#[serde(default)]
pub cwd: Option<PathBuf>,
pub cwd: Option<AbsolutePathBuf>,
pub http_headers: Option<HashMap<String, String>>,
#[serde(default)]
pub env_http_headers: Option<HashMap<String, String>>,
@@ -161,7 +160,7 @@ impl<'de> Deserialize<'de> for McpServerConfig {
args: raw.args.clone().unwrap_or_default(),
env: raw.env.clone(),
env_vars: raw.env_vars.clone().unwrap_or_default(),
cwd: raw.cwd.take().map(expand_tilde_pathbuf),
cwd: raw.cwd.take(),
}
} else if let Some(url) = raw.url.clone() {
throw_if_set("streamable_http", "args", raw.args.as_ref())?;
@@ -195,30 +194,6 @@ const fn default_enabled() -> bool {
true
}
fn expand_tilde_pathbuf(path: PathBuf) -> PathBuf {
let Some(path_str) = path.to_str() else {
return path;
};
if cfg!(target_os = "windows") {
return path;
}
let Some(home) = home_dir() else {
return path;
};
if path_str == "~" {
return home;
}
if let Some(rest) = path_str.strip_prefix("~/") {
return home.join(rest);
}
path
}
fn expand_tilde_string(value: String) -> String {
if cfg!(target_os = "windows") {
return value;
@@ -252,7 +227,7 @@ pub enum McpServerTransportConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
env_vars: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cwd: Option<PathBuf>,
cwd: Option<AbsolutePathBuf>,
},
/// https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http
StreamableHttp {
@@ -804,6 +779,7 @@ pub enum Personality {
#[cfg(test)]
mod tests {
use super::*;
use codex_utils_absolute_path::AbsolutePathBufGuard;
use pretty_assertions::assert_eq;
#[test]
@@ -916,13 +892,17 @@ mod tests {
args: vec![],
env: None,
env_vars: Vec::new(),
cwd: Some(PathBuf::from("/tmp")),
cwd: Some(
AbsolutePathBuf::from_absolute_path("/tmp").expect("expected absolute mcp cwd"),
),
}
);
}
#[test]
fn deserialize_stdio_command_server_config_expands_tilde_cwd() {
let base_dir = std::env::temp_dir();
let _guard = AbsolutePathBufGuard::new(&base_dir);
let cfg: McpServerConfig = toml::from_str(
r#"
command = "echo"
@@ -932,12 +912,14 @@ mod tests {
.expect("should deserialize command config with tilde cwd");
let expected_cwd = if cfg!(target_os = "windows") {
PathBuf::from("~/tmp")
AbsolutePathBuf::resolve_path_against_base("~/tmp", &base_dir)
.expect("expected absolute mcp cwd")
} else {
let Some(home) = home_dir() else {
return;
};
home.join("tmp")
AbsolutePathBuf::from_absolute_path(home.join("tmp"))
.expect("expected absolute mcp cwd")
};
assert_eq!(

View File

@@ -865,6 +865,7 @@ async fn make_rmcp_client(
} => {
let command_os: OsString = command.into();
let args_os: Vec<OsString> = args.into_iter().map(Into::into).collect();
let cwd = cwd.map(codex_utils_absolute_path::AbsolutePathBuf::into_path_buf);
RmcpClient::new_stdio_client(command_os, args_os, env, &env_vars, cwd)
.await
.map_err(|err| StartupOutcomeError::from(anyhow!(err)))