mcp over acp

Conrad Irwin created

Change summary

Cargo.lock                             |  4 +-
Cargo.toml                             |  2 
crates/acp_thread/src/acp_thread.rs    | 34 +++++++++++++++++++++++++++
crates/agent_servers/src/claude.rs     | 20 ++++++++++++++-
crates/agent_servers/src/e2e_tests.rs  |  2 
crates/agent_ui/src/acp/thread_view.rs |  2 
6 files changed, 56 insertions(+), 8 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -279,9 +279,9 @@ dependencies = [
 
 [[package]]
 name = "agentic-coding-protocol"
-version = "0.0.9"
+version = "0.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e276b798eddd02562a339340a96919d90bbfcf78de118fdddc932524646fac7"
+checksum = "48322590276f36cf49197898cde1c54645991c96c0c83722ef321da7f2b0ae42"
 dependencies = [
  "anyhow",
  "chrono",

Cargo.toml 🔗

@@ -410,7 +410,7 @@ zlog_settings = { path = "crates/zlog_settings" }
 # External crates
 #
 
-agentic-coding-protocol = "0.0.9"
+agentic-coding-protocol = "0.0.11"
 aho-corasick = "1.1"
 alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", branch = "add-hush-login-flag" }
 any_vec = "0.14"

crates/acp_thread/src/acp_thread.rs 🔗

@@ -869,9 +869,34 @@ impl AcpThread {
         false
     }
 
-    pub fn initialize(&self) -> impl use<> + Future<Output = Result<acp::InitializeResponse>> {
+    pub fn initialize(
+        &self,
+        cx: &mut Context<Self>,
+    ) -> impl use<> + Future<Output = Result<acp::InitializeResponse>> {
+        let context_server_store = self.project.read(cx).context_server_store().read(cx);
+        let mut context_servers = HashMap::new();
+        for id in context_server_store.all_server_ids() {
+            let Some(configuration) = context_server_store.configuration_for_server(&id) else {
+                continue;
+            };
+            let command = configuration.command();
+            context_servers.insert(
+                id.0.to_string(),
+                acp::ContextServer::Stdio {
+                    command: command.path.clone(),
+                    args: command.args.clone(),
+                    env: command
+                        .env
+                        .iter()
+                        .flatten()
+                        .map(|(k, v)| (k.clone(), v.clone()))
+                        .collect(),
+                },
+            );
+        }
         self.request(acp::InitializeParams {
             protocol_version: ProtocolVersion::latest(),
+            context_servers,
         })
     }
 
@@ -1187,6 +1212,13 @@ impl acp::Client for AcpClientDelegate {
         Ok(())
     }
 
+    async fn update_plan(
+        &self,
+        _request: agentic_coding_protocol::UpdatePlanParams,
+    ) -> Result<(), acp::Error> {
+        Ok(())
+    }
+
     async fn request_tool_call_confirmation(
         &self,
         request: acp::RequestToolCallConfirmationParams,

crates/agent_servers/src/claude.rs 🔗

@@ -65,6 +65,22 @@ impl AgentServer for ClaudeCode {
         let project = project.clone();
         let root_dir = root_dir.to_path_buf();
         let title = self.name().into();
+        let context_server_store = project.read(cx).context_server_store().read(cx);
+        let mut mcp_servers = HashMap::default();
+        for id in context_server_store.all_server_ids() {
+            let Some(configuration) = context_server_store.configuration_for_server(&id) else {
+                continue;
+            };
+            let command = configuration.command();
+            mcp_servers.insert(
+                id.0.to_string(),
+                McpServerConfig {
+                    command: command.path.clone(),
+                    args: command.args.clone(),
+                    env: command.env.clone(),
+                },
+            );
+        }
         cx.spawn(async move |cx| {
             let (mut delegate_tx, delegate_rx) = watch::channel(None);
             let tool_id_map = Rc::new(RefCell::new(HashMap::default()));
@@ -72,11 +88,11 @@ impl AgentServer for ClaudeCode {
             let permission_mcp_server =
                 ClaudeMcpServer::new(delegate_rx, tool_id_map.clone(), cx).await?;
 
-            let mut mcp_servers = HashMap::default();
             mcp_servers.insert(
                 mcp_server::SERVER_NAME.to_string(),
                 permission_mcp_server.server_config()?,
             );
+            dbg!(&mcp_servers);
             let mcp_config = McpConfig { mcp_servers };
 
             let mcp_config_file = tempfile::NamedTempFile::new()?;
@@ -567,7 +583,7 @@ struct McpConfig {
     mcp_servers: HashMap<String, McpServerConfig>,
 }
 
-#[derive(Serialize)]
+#[derive(Serialize, Debug)]
 #[serde(rename_all = "camelCase")]
 struct McpServerConfig {
     command: String,

crates/agent_servers/src/e2e_tests.rs 🔗

@@ -375,7 +375,7 @@ pub async fn new_test_thread(
         .unwrap();
 
     thread
-        .update(cx, |thread, _| thread.initialize())
+        .update(cx, |thread, cx| thread.initialize(cx))
         .await
         .unwrap();
     thread

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -216,7 +216,7 @@ impl AcpThreadView {
 
             let init_response = async {
                 let resp = thread
-                    .read_with(cx, |thread, _cx| thread.initialize())?
+                    .update(cx, |thread, cx| thread.initialize(cx))?
                     .await?;
                 anyhow::Ok(resp)
             };