Skip to content

Commit 5dbad11

Browse files
committed
refactor: fix the return format of CallToolResult
- corrected the return format for structured content results, following the MCP protocol. - fix variable name
1 parent 1bac33d commit 5dbad11

File tree

2 files changed

+26
-14
lines changed

2 files changed

+26
-14
lines changed

mcp-annotations/src/main/java/org/springaicommunity/mcp/method/tool/AbstractMcpToolMethodCallback.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import java.util.Objects;
2424
import java.util.stream.Stream;
2525

26-
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
27-
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
26+
import io.modelcontextprotocol.spec.McpSchema.*;
27+
import io.modelcontextprotocol.spec.McpSchema.CallToolResult.*;
2828
import org.springaicommunity.mcp.annotation.McpMeta;
2929
import org.springaicommunity.mcp.annotation.McpProgressToken;
3030
import org.springaicommunity.mcp.annotation.McpTool;
@@ -144,36 +144,48 @@ protected Object buildTypedArgument(Object value, Type type) {
144144
* @return A CallToolResult representing the processed result
145145
*/
146146
protected CallToolResult convertValueToCallToolResult(Object result) {
147+
Builder callToolResultBuilder = CallToolResult.builder();
148+
149+
// According to the MCP protocol For backwards compatibility, a tool that returns
150+
// structured content SHOULD also return the serialized JSON in a TextContent
151+
// block.
152+
if (this.returnMode == ReturnMode.STRUCTURED) {
153+
String jsonOutput = JsonParser.toJson(result);
154+
Object structuredOutput = JsonParser.fromJson(jsonOutput, Object.class);
155+
callToolResultBuilder.structuredContent(structuredOutput);
156+
}
157+
147158
// Return the result if it's already a CallToolResult
148159
if (result instanceof CallToolResult) {
149160
return (CallToolResult) result;
150161
}
162+
else if (result instanceof TextContent textContent) {
163+
// Structured content is only supported in TextContent
164+
return callToolResultBuilder.addContent(textContent).isError(false).meta(null).build();
165+
}
166+
else if (result instanceof Content content) {
167+
return CallToolResult.builder().addContent(content).isError(false).meta(null).build();
168+
}
151169

152170
Type returnType = this.toolMethod.getGenericReturnType();
153171

154172
if (returnMode == ReturnMode.VOID || returnType == Void.TYPE || returnType == void.class) {
155-
return CallToolResult.builder().addTextContent(JsonParser.toJson("Done")).build();
156-
}
157-
158-
if (this.returnMode == ReturnMode.STRUCTURED) {
159-
String jsonOutput = JsonParser.toJson(result);
160-
Object structuredOutput = JsonParser.fromJson(jsonOutput, Object.class);
161-
return CallToolResult.builder().structuredContent(structuredOutput).build();
173+
return callToolResultBuilder.addTextContent(JsonParser.toJson("Done")).build();
162174
}
163175

164176
// Default to text output
165177
if (result == null) {
166-
return CallToolResult.builder().addTextContent("null").build();
178+
return callToolResultBuilder.addTextContent("null").build();
167179
}
168180

169181
// For string results in TEXT mode, return the string directly without JSON
170182
// serialization
171183
if (result instanceof String) {
172-
return CallToolResult.builder().addTextContent((String) result).build();
184+
return callToolResultBuilder.addTextContent((String) result).build();
173185
}
174186

175187
// For other types, serialize to JSON
176-
return CallToolResult.builder().addTextContent(JsonParser.toJson(result)).build();
188+
return callToolResultBuilder.addTextContent(JsonParser.toJson(result)).build();
177189
}
178190

179191
/**

mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncMcpToolProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,9 @@ public List<SyncToolSpecification> getToolSpecifications() {
120120

121121
var tool = toolBuilder.build();
122122

123-
boolean useStructuredOtput = tool.outputSchema() != null;
123+
boolean useStructuredOutput = tool.outputSchema() != null;
124124

125-
ReturnMode returnMode = useStructuredOtput ? ReturnMode.STRUCTURED
125+
ReturnMode returnMode = useStructuredOutput ? ReturnMode.STRUCTURED
126126
: (methodReturnType == Void.TYPE || methodReturnType == void.class ? ReturnMode.VOID
127127
: ReturnMode.TEXT);
128128

0 commit comments

Comments
 (0)