feat: MCP stdio 传输支持工作目录配置

This commit is contained in:
oudecheng 2026-07-03 16:32:09 +08:00
parent b206e077e2
commit a78f5c5512

View File

@ -63,6 +63,9 @@ pub struct McpServerConfig {
/// Environment variables for stdio transport /// Environment variables for stdio transport
#[serde(default)] #[serde(default)]
pub env: Option<HashMap<String, String>>, pub env: Option<HashMap<String, String>>,
/// Working directory for stdio transport (optional). If set, child process runs in this dir.
#[serde(default)]
pub cwd: Option<String>,
// HTTP transport fields // HTTP transport fields
/// Base URL for HTTP transport (Claude Desktop compatible naming) /// Base URL for HTTP transport (Claude Desktop compatible naming)
@ -99,6 +102,7 @@ impl McpServerConfig {
command, command,
args: self.args.clone().unwrap_or_default(), args: self.args.clone().unwrap_or_default(),
env: self.env.clone().unwrap_or_default(), env: self.env.clone().unwrap_or_default(),
cwd: self.cwd.as_ref().map(|s| std::path::PathBuf::from(s)),
}) })
} }
"http" | "streamableHttp" => { "http" | "streamableHttp" => {
@ -124,6 +128,7 @@ impl McpServerConfig {
command: Some(command.into()), command: Some(command.into()),
args: Some(args), args: Some(args),
env: Some(HashMap::new()), env: Some(HashMap::new()),
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -139,6 +144,7 @@ impl McpServerConfig {
command: None, command: None,
args: None, args: None,
env: None, env: None,
cwd: None,
base_url: Some(url.into()), base_url: Some(url.into()),
headers: Some(HashMap::new()), headers: Some(HashMap::new()),
description: None, description: None,
@ -154,6 +160,7 @@ pub enum McpTransportConfig {
command: String, command: String,
args: Vec<String>, args: Vec<String>,
env: HashMap<String, String>, env: HashMap<String, String>,
cwd: Option<std::path::PathBuf>,
}, },
/// HTTP transport: connect to a remote server (Streamable HTTP) /// HTTP transport: connect to a remote server (Streamable HTTP)
Http { Http {
@ -300,6 +307,7 @@ mod tests {
command: Some("npx".to_string()), command: Some("npx".to_string()),
args: Some(vec!["-y".to_string(), "server".to_string()]), args: Some(vec!["-y".to_string(), "server".to_string()]),
env: None, env: None,
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -317,6 +325,7 @@ mod tests {
command: Some("npx".to_string()), command: Some("npx".to_string()),
args: Some(vec!["-y".to_string(), "server".to_string()]), args: Some(vec!["-y".to_string(), "server".to_string()]),
env: None, env: None,
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -335,6 +344,7 @@ mod tests {
command: None, command: None,
args: None, args: None,
env: None, env: None,
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -349,6 +359,7 @@ mod tests {
command: None, command: None,
args: None, args: None,
env: None, env: None,
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -363,6 +374,7 @@ mod tests {
command: Some("cmd".to_string()), command: Some("cmd".to_string()),
args: None, args: None,
env: None, env: None,
cwd: None,
base_url: None, base_url: None,
headers: None, headers: None,
description: None, description: None,
@ -385,4 +397,27 @@ mod tests {
assert!(matches!(transport_http, McpTransportConfig::Http { .. })); assert!(matches!(transport_http, McpTransportConfig::Http { .. }));
assert!(matches!(transport_streamable, McpTransportConfig::Http { .. })); assert!(matches!(transport_streamable, McpTransportConfig::Http { .. }));
} }
#[test]
fn test_stdio_cwd_field() {
let json = r#"{"mcpServers": {"test": {"type": "stdio", "command": "uv", "args": ["run", "server.py"], "cwd": "/some/path", "isActive": true}}}"#;
let config: McpConfig = serde_json::from_str(json).unwrap();
let server = config.mcp_servers.get("test").unwrap();
assert_eq!(server.cwd.as_deref(), Some("/some/path"));
let transport = server.transport().unwrap();
match transport {
McpTransportConfig::Stdio { cwd, .. } => {
assert_eq!(cwd, Some(std::path::PathBuf::from("/some/path")));
}
_ => panic!("Expected stdio transport"),
}
}
#[test]
fn test_stdio_cwd_defaults_to_none() {
let json = r#"{"mcpServers": {"test": {"type": "stdio", "command": "uv", "args": ["run", "server.py"]}}}"#;
let config: McpConfig = serde_json::from_str(json).unwrap();
let server = config.mcp_servers.get("test").unwrap();
assert!(server.cwd.is_none());
}
} }