fix: Exclude MCP App tools from Code Mode callbacks (#10290)

This commit is contained in:
Rob Gray
2026-07-13 17:18:18 -07:00
committed by GitHub
parent da0cd42513
commit 662aad0504
3 changed files with 60 additions and 5 deletions
+52 -3
View File
@@ -309,7 +309,7 @@ fn get_tool_meta_value(tool: &Tool) -> Option<Value> {
tool.meta.as_ref().map(|meta| Value::Object(meta.0.clone()))
}
fn get_tool_resource_uri(tool: &Tool) -> Option<String> {
pub(crate) fn get_tool_resource_uri(tool: &Tool) -> Option<String> {
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<CallToolResult, Error> {
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();
@@ -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) {
+3 -1
View File
@@ -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