diff --git a/crates/goose/src/agents/extension_manager.rs b/crates/goose/src/agents/extension_manager.rs index 19762dda0..7309e8614 100644 --- a/crates/goose/src/agents/extension_manager.rs +++ b/crates/goose/src/agents/extension_manager.rs @@ -309,7 +309,7 @@ fn get_tool_meta_value(tool: &Tool) -> Option { tool.meta.as_ref().map(|meta| Value::Object(meta.0.clone())) } -fn get_tool_resource_uri(tool: &Tool) -> Option { +pub(crate) fn get_tool_resource_uri(tool: &Tool) -> Option { tool.meta .as_ref() .and_then(|meta| meta.0.get("ui")) @@ -2200,6 +2200,20 @@ mod tests { "hidden tool".to_string(), Arc::new(json!({}).as_object().unwrap().clone()), ), + { + let mut t = Tool::new( + "render_chart".to_string(), + "Render a chart".to_string(), + Arc::new(json!({}).as_object().unwrap().clone()), + ); + t.meta = Some(Meta( + json!({ "ui": { "resourceUri": "ui://autovisualiser/chart" } }) + .as_object() + .unwrap() + .clone(), + )); + t + }, ], next_cursor: None, meta: None, @@ -2214,7 +2228,7 @@ mod tests { _cancellation_token: CancellationToken, ) -> Result { match name { - "tool" | "test__tool" | "available_tool" | "hidden_tool" => { + "tool" | "test__tool" | "available_tool" | "hidden_tool" | "render_chart" => { Ok(CallToolResult::success(vec![])) } _ => Err(Error::TransportClosed), @@ -2391,7 +2405,10 @@ mod tests { assert!(tool_names .iter() .any(|name| name == "test_extension__hidden_tool")); - assert!(tool_names.len() == 3); + assert!(tool_names + .iter() + .any(|name| name == "test_extension__render_chart")); + assert!(tool_names.len() == 4); } #[tokio::test] @@ -2584,6 +2601,38 @@ mod tests { assert!(tool_names.iter().any(|n| n.starts_with("ext_b__"))); } + #[tokio::test] + async fn test_mcp_app_tools_identified_for_code_mode_exclusion() { + let temp_dir = tempfile::tempdir().unwrap(); + let extension_manager = + ExtensionManager::new_without_provider(temp_dir.path().to_path_buf()); + + extension_manager + .add_mock_extension("autovisualiser".to_string(), Arc::new(MockClient {})) + .await; + + let tools = extension_manager + .get_prefixed_tools_excluding("test-session-id", "code_execution") + .await + .unwrap(); + + let (mcp_app_tools, regular_tools): (Vec<_>, Vec<_>) = tools + .iter() + .partition(|t| get_tool_resource_uri(t).is_some()); + + assert_eq!(mcp_app_tools.len(), 1, "exactly one MCP app tool"); + assert_eq!( + mcp_app_tools[0].name.as_ref(), + "autovisualiser__render_chart" + ); + assert!( + regular_tools + .iter() + .all(|t| get_tool_resource_uri(t).is_none()), + "non-MCP-app tools have no resourceUri" + ); + } + #[tokio::test] async fn test_get_prefixed_tools_by_extension_name() { let temp_dir = tempfile::tempdir().unwrap(); diff --git a/crates/goose/src/agents/platform_extensions/code_execution.rs b/crates/goose/src/agents/platform_extensions/code_execution.rs index 42f415b00..3c5493921 100644 --- a/crates/goose/src/agents/platform_extensions/code_execution.rs +++ b/crates/goose/src/agents/platform_extensions/code_execution.rs @@ -1,5 +1,5 @@ use crate::agents::extension::PlatformExtensionContext; -use crate::agents::extension_manager::get_tool_owner; +use crate::agents::extension_manager::{get_tool_owner, get_tool_resource_uri}; use crate::agents::mcp_client::{Error, McpClientTrait}; use crate::agents::tool_execution::ToolCallContext; use anyhow::Result; @@ -88,6 +88,10 @@ impl CodeExecutionClient { let mut cfgs = vec![]; for tool in tools { + if get_tool_resource_uri(&tool).is_some() { + continue; + } + let (name, namespace) = if let Some((prefix, tool_name)) = tool.name.split_once("__") { (tool_name.to_string(), Some(prefix.to_string())) } else if let Some(owner) = get_tool_owner(&tool) { diff --git a/crates/goose/src/agents/reply_parts.rs b/crates/goose/src/agents/reply_parts.rs index e504d4856..ff485a308 100644 --- a/crates/goose/src/agents/reply_parts.rs +++ b/crates/goose/src/agents/reply_parts.rs @@ -198,7 +198,9 @@ impl Agent { // from the standard tool list if crate::agents::extension_manager::get_tool_owner(&t).is_some_and(|o| { crate::agents::extension_manager::is_first_class_extension(&o) - }) { + }) || crate::agents::extension_manager::get_tool_resource_uri(&t) + .is_some() + { Some(t) } else { None