-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat: improved UX for tool calls via execute_code #6205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,10 +31,25 @@ type ToolCallRequest = ( | |
| tokio::sync::oneshot::Sender<Result<String, String>>, | ||
| ); | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] | ||
| struct ToolGraphNode { | ||
| /// Tool name in format "server/tool" (e.g., "developer/shell") | ||
| tool: String, | ||
| /// Brief description of what this call does (e.g., "list files in /src") | ||
| description: String, | ||
| /// Indices of nodes this depends on (empty if no dependencies) | ||
| #[serde(default)] | ||
| depends_on: Vec<usize>, | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize, Deserialize, JsonSchema)] | ||
| struct ExecuteCodeParams { | ||
| /// JavaScript code with ES6 imports for MCP tools. | ||
| code: String, | ||
| /// DAG of tool calls showing execution flow. Each node represents a tool call. | ||
| /// Use depends_on to show data flow (e.g., node 1 uses output from node 0). | ||
| #[serde(default)] | ||
| tool_graph: Vec<ToolGraphNode>, | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize, Deserialize, JsonSchema)] | ||
|
|
@@ -701,6 +716,7 @@ impl McpClientTrait for CodeExecutionClient { | |
| Err(Error::TransportClosed) | ||
| } | ||
|
|
||
| #[allow(clippy::too_many_lines)] | ||
| async fn list_tools( | ||
| &self, | ||
| _next_cursor: Option<String>, | ||
|
|
@@ -746,6 +762,15 @@ impl McpClientTrait for CodeExecutionClient { | |
| - Last expression is the result | ||
| - No comments in code | ||
|
|
||
| TOOL_GRAPH: Always provide tool_graph to describe the execution flow for the UI. | ||
| Each node has: tool (server/name), description (what it does), depends_on (indices of dependencies). | ||
| Example for chained operations: | ||
| [ | ||
| {"tool": "developer/shell", "description": "list files", "depends_on": []}, | ||
| {"tool": "developer/text_editor", "description": "read README.md", "depends_on": []}, | ||
| {"tool": "developer/text_editor", "description": "write output.txt", "depends_on": [0, 1]} | ||
| ] | ||
|
Comment on lines
+765
to
+772
|
||
|
|
||
| BEFORE CALLING: Use the read_module tool to check required parameters. | ||
| "#} | ||
| .to_string(), | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,12 @@ import MCPUIResourceRenderer from './MCPUIResourceRenderer'; | |||||||||||||||||||||||
| import { isUIResource } from '@mcp-ui/client'; | ||||||||||||||||||||||||
| import { CallToolResponse, Content, EmbeddedResource } from '../api'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| interface ToolGraphNode { | ||||||||||||||||||||||||
| tool: string; | ||||||||||||||||||||||||
| description: string; | ||||||||||||||||||||||||
| depends_on: number[]; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| interface ToolCallWithResponseProps { | ||||||||||||||||||||||||
| isCancelledMessage: boolean; | ||||||||||||||||||||||||
| toolRequest: ToolRequestMessageContent; | ||||||||||||||||||||||||
|
|
@@ -410,6 +416,20 @@ function ToolCallView({ | |||||||||||||||||||||||
| case 'computer_control': | ||||||||||||||||||||||||
| return `poking around...`; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| case 'execute_code': { | ||||||||||||||||||||||||
| const toolGraph = args.tool_graph as unknown as ToolGraphNode[] | undefined; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| if (toolGraph && Array.isArray(toolGraph) && toolGraph.length > 0) { | ||||||||||||||||||||||||
| if (toolGraph.length === 1) { | ||||||||||||||||||||||||
| return `${toolGraph[0].description}`; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| if (toolGraph.length === 2) { | ||||||||||||||||||||||||
| return `${toolGraph[0].tool}, ${toolGraph[1].tool}`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| return `${toolGraph[0].tool}, ${toolGraph[1].tool}`; | |
| const firstLabel = toolGraph[0].description || toolGraph[0].tool; | |
| const secondLabel = toolGraph[1].description || toolGraph[1].tool; | |
| return `${firstLabel}, ${secondLabel}`; |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The double cast through unknown bypasses TypeScript's type safety. Consider defining a proper type guard function or adding a runtime validation function that checks the structure matches ToolGraphNode[] before casting.
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dependency indices are displayed without validation. If a dependency index is out of bounds (>= toolGraph.length) or references a later node (>= current index), the displayed number will be misleading. Consider adding validation or at least bounds checking before displaying.
| const deps = | |
| node.depends_on.length > 0 ? ` (uses ${node.depends_on.map((d) => d + 1).join(', ')})` : ''; | |
| const validDeps = node.depends_on.filter( | |
| (d) => | |
| Number.isInteger(d) && | |
| d >= 0 && | |
| d < toolGraph.length && | |
| d < index, | |
| ); | |
| const deps = | |
| validDeps.length > 0 ? ` (uses ${validDeps.map((d) => d + 1).join(', ')})` : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dependency indices are displayed without validation. If a dependency index is out of bounds or references a later node, the displayed number will be misleading. Consider adding validation or at least bounds checking before displaying.