From 9c85e57ac2c7045908bfc456fad0d5a6e51bbb23 Mon Sep 17 00:00:00 2001 From: meldrey Date: Sat, 23 May 2026 20:44:33 -0500 Subject: [PATCH] Fix: Render MCP tool output identically to built-in tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two gates prevented MCP tool results from displaying to users: 1. toolExecution.ts: isMcpTool() guard routed MCP tools through a separate code path that skipped addToolResult(), the function that stores results for UI rendering. Built-in tools called it; MCP tools didn't. Removed the guard so all tools use the same rendering path. Also removed the duplicate MCP-only addToolResult() call that would have double-rendered. 2. MCPTool.ts: outputSchema was z.string(), but MCP tool results arrive as content arrays (objects), not strings. UserToolSuccessMessage validates results against outputSchema before rendering — string validation on an array silently returns null, killing the render. Changed to z.any(). The Anthropic dev left a guilty TODO on gate #1: 'TOOD(hackyon): refactor so we don't have different experiences for MCP tools' Now they don't. Co-Authored-By: J5 --- src/services/tools/toolExecution.ts | 10 ++-------- src/tools/MCPTool/MCPTool.ts | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/services/tools/toolExecution.ts b/src/services/tools/toolExecution.ts index d2d6d90..ccf98a8 100644 --- a/src/services/tools/toolExecution.ts +++ b/src/services/tools/toolExecution.ts @@ -1473,10 +1473,8 @@ async function checkPermissionsAndCallTool( }) } - // TOOD(hackyon): refactor so we don't have different experiences for MCP tools - if (!isMcpTool(tool)) { - await addToolResult(toolOutput, mappedToolResultBlock) - } + // All tools get the same rendering path — no MCP/built-in bifurcation + await addToolResult(toolOutput, mappedToolResultBlock) const postToolHookInfos: StopHookInfo[] = [] const postToolHookStart = Date.now() @@ -1537,10 +1535,6 @@ async function checkPermissionsAndCallTool( ) } - if (isMcpTool(tool)) { - await addToolResult(toolOutput) - } - // Show PostToolUse hook timing inline below tool result when > 500ms. // Use wall-clock time (not sum of individual durations) since hooks run in parallel. if (process.env.USER_TYPE === 'ant' && postToolHookInfos.length > 0) { diff --git a/src/tools/MCPTool/MCPTool.ts b/src/tools/MCPTool/MCPTool.ts index 3896868..9f80983 100644 --- a/src/tools/MCPTool/MCPTool.ts +++ b/src/tools/MCPTool/MCPTool.ts @@ -15,7 +15,7 @@ export const inputSchema = lazySchema(() => z.object({}).passthrough()) type InputSchema = ReturnType export const outputSchema = lazySchema(() => - z.string().describe('MCP tool execution result'), + z.any().describe('MCP tool execution result'), ) type OutputSchema = ReturnType