diff --git a/core/src/main/java/com/google/adk/tools/mcp/AbstractMcpTool.java b/core/src/main/java/com/google/adk/tools/mcp/AbstractMcpTool.java index 0fcb74846..0c83cdc00 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/AbstractMcpTool.java +++ b/core/src/main/java/com/google/adk/tools/mcp/AbstractMcpTool.java @@ -131,8 +131,11 @@ protected static Map wrapCallResult( return ImmutableMap.of("error", errorMessage); } + Map resultMap = + objectMapper.convertValue(callResult, new TypeReference>() {}); + if (contents == null || contents.isEmpty()) { - return ImmutableMap.of(); + return resultMap; } List textOutputs = new ArrayList<>(); @@ -145,11 +148,7 @@ protected static Map wrapCallResult( } if (textOutputs.isEmpty()) { - return ImmutableMap.of( - "error", - "Tool '" + mcpToolName + "' returned content that is not TextContent.", - "content_details", - contents.toString()); + return resultMap; } List> resultMaps = new ArrayList<>(); @@ -161,6 +160,7 @@ protected static Map wrapCallResult( resultMaps.add(ImmutableMap.of("text", textOutput)); } } - return ImmutableMap.of("text_output", resultMaps); + resultMap.put("text_output", resultMaps); + return resultMap; } } diff --git a/core/src/test/java/com/google/adk/tools/mcp/AbstractMcpToolTest.java b/core/src/test/java/com/google/adk/tools/mcp/AbstractMcpToolTest.java index 4c633c660..6ef832aea 100644 --- a/core/src/test/java/com/google/adk/tools/mcp/AbstractMcpToolTest.java +++ b/core/src/test/java/com/google/adk/tools/mcp/AbstractMcpToolTest.java @@ -25,6 +25,7 @@ import io.modelcontextprotocol.client.McpSyncClient; import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema.CallToolResult; +import io.modelcontextprotocol.spec.McpSchema.ImageContent; import io.modelcontextprotocol.spec.McpSchema.TextContent; import java.util.List; import java.util.Map; @@ -53,14 +54,61 @@ public void testWrapCallResult_success() { Map map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result); + assertThat(map).containsEntry("isError", false); assertThat(map).containsKey("text_output"); - List content = (List) map.get("text_output"); - assertThat(content).hasSize(1); + List textOutput = (List) map.get("text_output"); + assertThat(textOutput).hasSize(1); - Map contentItem = (Map) content.get(0); + Map contentItem = (Map) textOutput.get(0); assertThat(contentItem).containsEntry("text", "success"); } + @Test + public void testWrapCallResult_mixedContent_success() { + CallToolResult result = + new CallToolResult( + ImmutableList.of( + new TextContent("first"), new ImageContent(null, "aW1hZ2U=", "image/png", null)), + false, + Map.of("count", 2), + Map.of("traceId", "trace-123")); + + Map map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result); + + assertThat(map).containsEntry("isError", false); + assertThat(map).containsEntry("structuredContent", Map.of("count", 2)); + assertThat(map).containsEntry("_meta", Map.of("traceId", "trace-123")); + + List content = (List) map.get("content"); + assertThat(content).hasSize(2); + Map textContent = (Map) content.get(0); + assertThat(textContent).containsEntry("type", "text"); + assertThat(textContent).containsEntry("text", "first"); + Map imageContent = (Map) content.get(1); + assertThat(imageContent).containsEntry("type", "image"); + assertThat(imageContent).containsEntry("data", "aW1hZ2U="); + assertThat(imageContent).containsEntry("mimeType", "image/png"); + + List textOutput = (List) map.get("text_output"); + assertThat(textOutput).containsExactly(Map.of("text", "first")); + } + + @Test + public void testWrapCallResult_nonTextContent_success() { + CallToolResult result = + new CallToolResult( + ImmutableList.of(new ImageContent(null, "aW1hZ2U=", "image/png", null)), + false, + null, + null); + + Map map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result); + + assertThat(map).doesNotContainKey("error"); + assertThat(map).containsEntry("isError", false); + assertThat((List) map.get("content")).hasSize(1); + } + @Test public void instantiateWithToolBuilder_nullDescription_succeeds() { McpSyncClient sessionMock = mock(McpSyncClient.class);