Ensure context servers are spawned in the workspace directory (#35271)

This fixes an issue where we were not setting the context server working
directory at all.

Release Notes:

- Context servers will now be spawned in the currently active project
root.

---------

Co-authored-by: Danilo Leal <danilo@zed.dev>
This commit is contained in:
Finn Evers 2025-07-29 18:03:43 +02:00 committed by GitHub
parent d43f464174
commit 397b5f9301
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 97 additions and 29 deletions

View file

@ -158,6 +158,7 @@ impl Client {
pub fn stdio(
server_id: ContextServerId,
binary: ModelContextServerBinary,
working_directory: &Option<PathBuf>,
cx: AsyncApp,
) -> Result<Self> {
log::info!(
@ -172,7 +173,7 @@ impl Client {
.map(|name| name.to_string_lossy().to_string())
.unwrap_or_else(String::new);
let transport = Arc::new(StdioTransport::new(binary, &cx)?);
let transport = Arc::new(StdioTransport::new(binary, working_directory, &cx)?);
Self::new(server_id, server_name.into(), transport, cx)
}

View file

@ -53,7 +53,7 @@ impl std::fmt::Debug for ContextServerCommand {
}
enum ContextServerTransport {
Stdio(ContextServerCommand),
Stdio(ContextServerCommand, Option<PathBuf>),
Custom(Arc<dyn crate::transport::Transport>),
}
@ -64,11 +64,18 @@ pub struct ContextServer {
}
impl ContextServer {
pub fn stdio(id: ContextServerId, command: ContextServerCommand) -> Self {
pub fn stdio(
id: ContextServerId,
command: ContextServerCommand,
working_directory: Option<Arc<Path>>,
) -> Self {
Self {
id,
client: RwLock::new(None),
configuration: ContextServerTransport::Stdio(command),
configuration: ContextServerTransport::Stdio(
command,
working_directory.map(|directory| directory.to_path_buf()),
),
}
}
@ -90,13 +97,14 @@ impl ContextServer {
pub async fn start(self: Arc<Self>, cx: &AsyncApp) -> Result<()> {
let client = match &self.configuration {
ContextServerTransport::Stdio(command) => Client::stdio(
ContextServerTransport::Stdio(command, working_directory) => Client::stdio(
client::ContextServerId(self.id.0.clone()),
client::ModelContextServerBinary {
executable: Path::new(&command.path).to_path_buf(),
args: command.args.clone(),
env: command.env.clone(),
},
working_directory,
cx.clone(),
)?,
ContextServerTransport::Custom(transport) => Client::new(

View file

@ -1,3 +1,4 @@
use std::path::PathBuf;
use std::pin::Pin;
use anyhow::{Context as _, Result};
@ -22,7 +23,11 @@ pub struct StdioTransport {
}
impl StdioTransport {
pub fn new(binary: ModelContextServerBinary, cx: &AsyncApp) -> Result<Self> {
pub fn new(
binary: ModelContextServerBinary,
working_directory: &Option<PathBuf>,
cx: &AsyncApp,
) -> Result<Self> {
let mut command = util::command::new_smol_command(&binary.executable);
command
.args(&binary.args)
@ -32,6 +37,10 @@ impl StdioTransport {
.stderr(std::process::Stdio::piped())
.kill_on_drop(true);
if let Some(working_directory) = working_directory {
command.current_dir(working_directory);
}
let mut server = command.spawn().with_context(|| {
format!(
"failed to spawn command. (path={:?}, args={:?})",