From d4c77b63d57aabfc99dc810a0de8f3c9ea542435 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 6 Feb 2026 20:46:05 +0000 Subject: [PATCH] fix: include both file paths and raw base64 data in MCP image responses Pass both source_path and raw base64 data URLs to the LLM in MCP tool image responses. This ensures the model can analyze images in the current turn (via base64 data) while still benefiting from path-based persistence for future context (via source_path). --- src/core/tools/UseMcpToolTool.ts | 9 +++++---- .../tools/__tests__/useMcpToolTool.spec.ts | 20 ++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/core/tools/UseMcpToolTool.ts b/src/core/tools/UseMcpToolTool.ts index 4534a8fed8..66a66b0dae 100644 --- a/src/core/tools/UseMcpToolTool.ts +++ b/src/core/tools/UseMcpToolTool.ts @@ -325,17 +325,18 @@ export class UseMcpToolTool extends BaseTool<"use_mcp_tool"> { // Build the result text let resultText = outputText || "" - // If there are images, save them to temp storage and provide file paths to the LLM - // This avoids passing raw base64 through LLM context which causes corruption and high costs + // If there are images, save them to temp storage and provide both file paths and raw data to the LLM. + // File paths enable efficient persistence for future context, while raw base64 data allows + // the model to analyze images in the current turn. if (images.length > 0) { const savedImagePaths = await this.saveImagesToTempStorage(task, images, serverName, toolName) const imagePathsSection = savedImagePaths .map( (imgPath, index) => - `\n ${imgPath}\n`, + `\n ${imgPath}\n ${images[index]}\n`, ) .join("\n\n") - const imageInfo = `\n\n[${images.length} image(s) received and saved to temporary storage. Use save_image tool with source_path to save to your desired location.]\n\n${imagePathsSection}` + const imageInfo = `\n\n[${images.length} image(s) received and saved to temporary storage. Use save_image tool with source_path (preferred) or data to save to your desired location.]\n\n${imagePathsSection}` resultText = resultText ? resultText + imageInfo : imageInfo.trim() } diff --git a/src/core/tools/__tests__/useMcpToolTool.spec.ts b/src/core/tools/__tests__/useMcpToolTool.spec.ts index fc81b17978..402b4454d6 100644 --- a/src/core/tools/__tests__/useMcpToolTool.spec.ts +++ b/src/core/tools/__tests__/useMcpToolTool.spec.ts @@ -658,16 +658,21 @@ describe("useMcpToolTool", () => { expect(mockTask.say).toHaveBeenCalledWith( "mcp_server_response", expect.stringContaining( - "[1 image(s) received and saved to temporary storage. Use save_image tool with source_path to save to your desired location.]", + "[1 image(s) received and saved to temporary storage. Use save_image tool with source_path (preferred) or data to save to your desired location.]", ), ["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ"], ) - // Text response should contain source_path XML tags, not raw base64 + // Text response should contain both source_path and data XML tags expect(mockTask.say).toHaveBeenCalledWith( "mcp_server_response", expect.stringContaining(""), expect.anything(), ) + expect(mockTask.say).toHaveBeenCalledWith( + "mcp_server_response", + expect.stringContaining(""), + expect.anything(), + ) expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("with 1 image(s)")) }) @@ -726,12 +731,17 @@ describe("useMcpToolTool", () => { expect.stringContaining("Node name: Button"), ["data:image/png;base64,base64imagedata"], ) - // Text response should contain source_path, not raw base64 + // Text response should contain both source_path and data XML tags expect(mockTask.say).toHaveBeenCalledWith( "mcp_server_response", expect.stringContaining(""), expect.anything(), ) + expect(mockTask.say).toHaveBeenCalledWith( + "mcp_server_response", + expect.stringContaining(""), + expect.anything(), + ) expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("with 1 image(s)")) }) @@ -788,7 +798,7 @@ describe("useMcpToolTool", () => { expect(mockTask.say).toHaveBeenCalledWith( "mcp_server_response", expect.stringContaining( - "[1 image(s) received and saved to temporary storage. Use save_image tool with source_path to save to your desired location.]", + "[1 image(s) received and saved to temporary storage. Use save_image tool with source_path (preferred) or data to save to your desired location.]", ), ["data:image/jpeg;base64,/9j/4AAQSkZJRg=="], ) @@ -851,7 +861,7 @@ describe("useMcpToolTool", () => { expect(mockTask.say).toHaveBeenCalledWith( "mcp_server_response", expect.stringContaining( - "[2 image(s) received and saved to temporary storage. Use save_image tool with source_path to save to your desired location.]", + "[2 image(s) received and saved to temporary storage. Use save_image tool with source_path (preferred) or data to save to your desired location.]", ), ["data:image/png;base64,image1data", "data:image/png;base64,image2data"], )