agent: Namespace MCP server tools (#30600)

Bennet Bo Fenner created

This fixes an issue where requests were failing when MCP servers were
registering tools with the same name.
We now prefix the tool names with the context server name, in the UI we
still show the name that the MCP server gives us

Release Notes:

- agent: Fix an error were requests would fail if two MCP servers were
using an identical tool name

Change summary

crates/agent/src/agent_configuration.rs             | 2 +-
crates/agent/src/agent_configuration/tool_picker.rs | 4 ++--
crates/agent/src/context_server_tool.rs             | 4 ++++
crates/assistant_tool/src/assistant_tool.rs         | 5 +++++
4 files changed, 12 insertions(+), 3 deletions(-)

Detailed changes

crates/agent/src/agent_configuration.rs 🔗

@@ -637,7 +637,7 @@ impl AgentConfiguration {
                             .hover(|style| style.bg(cx.theme().colors().element_hover))
                             .rounded_sm()
                             .child(
-                                Label::new(tool.name())
+                                Label::new(tool.ui_name())
                                     .buffer_font(cx)
                                     .size(LabelSize::Small),
                             )

crates/agent/src/agent_configuration/tool_picker.rs 🔗

@@ -117,7 +117,7 @@ impl ToolPickerDelegate {
                 ToolSource::Native => {
                     if mode == ToolPickerMode::BuiltinTools {
                         items.extend(tools.into_iter().map(|tool| PickerItem::Tool {
-                            name: tool.name().into(),
+                            name: tool.ui_name().into(),
                             server_id: None,
                         }));
                     }
@@ -129,7 +129,7 @@ impl ToolPickerDelegate {
                             server_id: server_id.clone(),
                         });
                         items.extend(tools.into_iter().map(|tool| PickerItem::Tool {
-                            name: tool.name().into(),
+                            name: tool.ui_name().into(),
                             server_id: Some(server_id.clone()),
                         }));
                     }

crates/agent/src/context_server_tool.rs 🔗

@@ -30,6 +30,10 @@ impl ContextServerTool {
 
 impl Tool for ContextServerTool {
     fn name(&self) -> String {
+        format!("{}-{}", self.server_id, self.tool.name)
+    }
+
+    fn ui_name(&self) -> String {
         self.tool.name.clone()
     }
 

crates/assistant_tool/src/assistant_tool.rs 🔗

@@ -203,6 +203,11 @@ pub trait Tool: 'static + Send + Sync {
     /// Returns the name of the tool.
     fn name(&self) -> String;
 
+    /// Returns the name to be displayed in the UI for this tool.
+    fn ui_name(&self) -> String {
+        self.name()
+    }
+
     /// Returns the description of the tool.
     fn description(&self) -> String;