mirror of
https://github.com/openai/codex.git
synced 2026-09-15 12:08:01 +00:00
Covert to use absolutePathBuf for mcp cwd
This commit is contained in:
@@ -1104,7 +1104,11 @@
|
||||
},
|
||||
"cwd": {
|
||||
"default": null,
|
||||
"type": "string"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
}
|
||||
]
|
||||
},
|
||||
"disabled_tools": {
|
||||
"default": null,
|
||||
|
||||
@@ -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:?}"),
|
||||
}
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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)))
|
||||
|
||||
Reference in New Issue
Block a user