{"record":{"id":"9af283926f76234f","repo":"zed-industries/zed","slug":"e","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/agent/src/tools/context_server_registry.rs","lineNumber":358,"sourceCode":"        input: ToolInput<serde_json::Value>,\n        event_stream: ToolCallEventStream,\n        cx: &mut App,\n    ) -> Task<Result<AgentToolOutput, AgentToolOutput>> {\n        let Some(server) = self.store.read(cx).get_running_server(&self.server_id) else {\n            return Task::ready(Err(anyhow::anyhow!(\"Context server not found\").into()));\n        };\n        let tool_name = self.tool.name.clone();\n        let tool_id = mcp_tool_id(&self.server_id.0, &self.tool.name);\n        let display_name = self.tool.name.clone();\n        let initial_title = self.initial_title(serde_json::Value::Null, cx);\n        let authorize =\n            event_stream.authorize_third_party_tool(initial_title, tool_id, display_name, cx);\n\n        cx.spawn(async move |cx| {\n            let input = input\n                .recv()\n                .await\n                .map_err(|e| anyhow::anyhow!(e.to_string()))?;\n\n            authorize\n                .await\n                .map_err(|e| anyhow::anyhow!(e.to_string()))?;\n\n            let Some(protocol) = server.client() else {\n                return Err(anyhow::anyhow!(\"Context server not initialized\").into());\n            };\n\n            let arguments = if let serde_json::Value::Object(map) = input {\n                Some(map.into_iter().collect())\n            } else {\n                None\n            };\n\n            log::trace!(\n                \"Running tool: {} with arguments: {:?}\",\n                tool_name,","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/agent/src/tools/context_server_registry.rs#L340-L376","documentation":"The MCP tool's input never arrived: `input.recv()` failed because the sending side of the tool-input channel was dropped without sending a value. The error string is the receive error ('channel closed'). In practice the agent loop aborted the tool call — run cancelled, thread shutdown, or the call discarded upstream — before delivering input.","triggerScenarios":"Cancelling the agent run or dropping the `ToolInput` sender between tool dispatch and input delivery; upstream errors that abandon the call; tests that construct the tool without ever providing input.","commonSituations":"Stop pressed right as a tool call starts; agent thread torn down mid-dispatch; streaming-input pipelines that error before the first value.","solutions":["Map it to 'tool call aborted' — never retry the MCP call with empty or guessed input.","Ensure callers either send input or cancel explicitly, and that cancellation propagates cleanly.","In tests, always supply a ready input value instead of a dropped channel."],"exampleFix":"// before\nlet input = input.recv().await.map_err(|e| anyhow::anyhow!(e.to_string()))?;\n// after\nlet input = match input.recv().await {\n    Ok(value) => value,\n    Err(_) => return Err(anyhow::anyhow!(\"tool input dropped — call was aborted\").into()),\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let input = match input.recv().await {\n    Ok(value) => value,\n    Err(_) => return Err(anyhow::anyhow!(\"tool call aborted before input arrived\").into()),\n};","preventionTips":["Always send a ToolInput value or cancel the call explicitly.","In tests, provide ready input instead of a dropped channel.","Propagate cancellation instead of silently dropping input senders."],"tags":["mcp","agent","channel","cancellation","async"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}