Use shell to launch MCP and ACP servers (#42382)

`npx`, and any `npm install`-ed programs, exist as batch
scripts/PowerShell scripts on the PATH. We have to use a shell to launch
these programs.

Fixes https://github.com/zed-industries/zed/issues/41435
Closes https://github.com/zed-industries/zed/pull/42651


Release Notes:

- windows: Custom MCP and ACP servers installed through `npm` now launch
correctly.

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
This commit is contained in:
John Tur
2025-12-10 12:08:37 -05:00
committed by GitHub
co-authored by Lukas Wirth
parent 8ee85eab3c
commit d83201256d
12 changed files with 389 additions and 43 deletions
+13 -2
View File
@@ -31,7 +31,8 @@ use tempfile::TempDir;
use util::{
paths::{PathStyle, RemotePathBuf},
rel_path::RelPath,
shell::ShellKind,
shell::{Shell, ShellKind},
shell_builder::ShellBuilder,
};
pub(crate) struct SshRemoteConnection {
@@ -1362,6 +1363,8 @@ fn build_command(
} else {
write!(exec, "{ssh_shell} -l")?;
};
let (command, command_args) = ShellBuilder::new(&Shell::Program(ssh_shell.to_owned()), false)
.build(Some(exec.clone()), &[]);
let mut args = Vec::new();
args.extend(ssh_args);
@@ -1372,7 +1375,9 @@ fn build_command(
}
args.push("-t".into());
args.push(exec);
args.push(command);
args.extend(command_args);
Ok(CommandTemplate {
program: "ssh".into(),
args,
@@ -1411,6 +1416,9 @@ mod tests {
"-p",
"2222",
"-t",
"/bin/fish",
"-i",
"-c",
"cd \"$HOME/work\" && exec env INPUT_VA=val remote_program arg1 arg2"
]
);
@@ -1443,6 +1451,9 @@ mod tests {
"-L",
"1:foo:2",
"-t",
"/bin/fish",
"-i",
"-c",
"cd && exec env INPUT_VA=val /bin/fish -l"
]
);
+8 -8
View File
@@ -23,7 +23,8 @@ use std::{
use util::{
paths::{PathStyle, RemotePathBuf},
rel_path::RelPath,
shell::ShellKind,
shell::{Shell, ShellKind},
shell_builder::ShellBuilder,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Deserialize, schemars::JsonSchema)]
@@ -453,8 +454,10 @@ impl RemoteConnection for WslRemoteConnection {
} else {
write!(&mut exec, "{} -l", self.shell)?;
}
let (command, args) =
ShellBuilder::new(&Shell::Program(self.shell.clone()), false).build(Some(exec), &[]);
let wsl_args = if let Some(user) = &self.connection_options.user {
let mut wsl_args = if let Some(user) = &self.connection_options.user {
vec![
"--distribution".to_string(),
self.connection_options.distro_name.clone(),
@@ -463,9 +466,7 @@ impl RemoteConnection for WslRemoteConnection {
"--cd".to_string(),
working_dir,
"--".to_string(),
self.shell.clone(),
"-c".to_string(),
exec,
command,
]
} else {
vec![
@@ -474,11 +475,10 @@ impl RemoteConnection for WslRemoteConnection {
"--cd".to_string(),
working_dir,
"--".to_string(),
self.shell.clone(),
"-c".to_string(),
exec,
command,
]
};
wsl_args.extend(args);
Ok(CommandTemplate {
program: "wsl.exe".to_string(),