Skip to content

Commit e03e01e

Browse files
committed
fix: preserve complete MCP call tool results
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c1bda9c commit e03e01e

2 files changed

Lines changed: 58 additions & 10 deletions

File tree

core/src/main/java/com/google/adk/tools/mcp/AbstractMcpTool.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,11 @@ protected static Map<String, Object> wrapCallResult(
131131
return ImmutableMap.of("error", errorMessage);
132132
}
133133

134+
Map<String, Object> resultMap =
135+
objectMapper.convertValue(callResult, new TypeReference<Map<String, Object>>() {});
136+
134137
if (contents == null || contents.isEmpty()) {
135-
return ImmutableMap.of();
138+
return resultMap;
136139
}
137140

138141
List<String> textOutputs = new ArrayList<>();
@@ -145,11 +148,7 @@ protected static Map<String, Object> wrapCallResult(
145148
}
146149

147150
if (textOutputs.isEmpty()) {
148-
return ImmutableMap.of(
149-
"error",
150-
"Tool '" + mcpToolName + "' returned content that is not TextContent.",
151-
"content_details",
152-
contents.toString());
151+
return resultMap;
153152
}
154153

155154
List<Map<String, Object>> resultMaps = new ArrayList<>();
@@ -161,6 +160,7 @@ protected static Map<String, Object> wrapCallResult(
161160
resultMaps.add(ImmutableMap.of("text", textOutput));
162161
}
163162
}
164-
return ImmutableMap.of("text_output", resultMaps);
163+
resultMap.put("text_output", resultMaps);
164+
return resultMap;
165165
}
166166
}

core/src/test/java/com/google/adk/tools/mcp/AbstractMcpToolTest.java

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import io.modelcontextprotocol.client.McpSyncClient;
2626
import io.modelcontextprotocol.spec.McpSchema;
2727
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
28+
import io.modelcontextprotocol.spec.McpSchema.ImageContent;
2829
import io.modelcontextprotocol.spec.McpSchema.TextContent;
2930
import java.util.List;
3031
import java.util.Map;
@@ -53,14 +54,61 @@ public void testWrapCallResult_success() {
5354

5455
Map<String, Object> map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result);
5556

57+
assertThat(map).containsEntry("isError", false);
5658
assertThat(map).containsKey("text_output");
57-
List<?> content = (List<?>) map.get("text_output");
58-
assertThat(content).hasSize(1);
59+
List<?> textOutput = (List<?>) map.get("text_output");
60+
assertThat(textOutput).hasSize(1);
5961

60-
Map<?, ?> contentItem = (Map<?, ?>) content.get(0);
62+
Map<?, ?> contentItem = (Map<?, ?>) textOutput.get(0);
6163
assertThat(contentItem).containsEntry("text", "success");
6264
}
6365

66+
@Test
67+
public void testWrapCallResult_mixedContent_success() {
68+
CallToolResult result =
69+
new CallToolResult(
70+
ImmutableList.of(
71+
new TextContent("first"), new ImageContent(null, "aW1hZ2U=", "image/png", null)),
72+
false,
73+
Map.of("count", 2),
74+
Map.of("traceId", "trace-123"));
75+
76+
Map<String, Object> map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result);
77+
78+
assertThat(map).containsEntry("isError", false);
79+
assertThat(map).containsEntry("structuredContent", Map.of("count", 2));
80+
assertThat(map).containsEntry("_meta", Map.of("traceId", "trace-123"));
81+
82+
List<?> content = (List<?>) map.get("content");
83+
assertThat(content).hasSize(2);
84+
Map<?, ?> textContent = (Map<?, ?>) content.get(0);
85+
assertThat(textContent).containsEntry("type", "text");
86+
assertThat(textContent).containsEntry("text", "first");
87+
Map<?, ?> imageContent = (Map<?, ?>) content.get(1);
88+
assertThat(imageContent).containsEntry("type", "image");
89+
assertThat(imageContent).containsEntry("data", "aW1hZ2U=");
90+
assertThat(imageContent).containsEntry("mimeType", "image/png");
91+
92+
List<?> textOutput = (List<?>) map.get("text_output");
93+
assertThat(textOutput).containsExactly(Map.of("text", "first"));
94+
}
95+
96+
@Test
97+
public void testWrapCallResult_nonTextContent_success() {
98+
CallToolResult result =
99+
new CallToolResult(
100+
ImmutableList.of(new ImageContent(null, "aW1hZ2U=", "image/png", null)),
101+
false,
102+
null,
103+
null);
104+
105+
Map<String, Object> map = AbstractMcpTool.wrapCallResult(objectMapper, "my_tool", result);
106+
107+
assertThat(map).doesNotContainKey("error");
108+
assertThat(map).containsEntry("isError", false);
109+
assertThat((List<?>) map.get("content")).hasSize(1);
110+
}
111+
64112
@Test
65113
public void instantiateWithToolBuilder_nullDescription_succeeds() {
66114
McpSyncClient sessionMock = mock(McpSyncClient.class);

0 commit comments

Comments
 (0)