Skip to content

Commit 7e950eb

Browse files
authored
refactor: use builder pattern for CallToolResult and Resource (#652)
* use builder pattern for CallToolResult * use builder pattern for Resource * simplify lambda expressions in tests
1 parent c561675 commit 7e950eb

14 files changed

+405
-202
lines changed

mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
2525
import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion;
2626
import io.modelcontextprotocol.spec.McpSchema.ErrorCodes;
27-
import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse;
2827
import io.modelcontextprotocol.spec.McpSchema.LoggingLevel;
2928
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
3029
import io.modelcontextprotocol.spec.McpSchema.PromptReference;
@@ -398,19 +397,23 @@ public Mono<CallToolResult> apply(McpAsyncServerExchange exchange, McpSchema.Cal
398397
// results that conform to this schema.
399398
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
400399
if (result.structuredContent() == null) {
401-
logger.warn(
402-
"Response missing structured content which is expected when calling tool with non-empty outputSchema");
403-
return new CallToolResult(
404-
"Response missing structured content which is expected when calling tool with non-empty outputSchema",
405-
true);
400+
String content = "Response missing structured content which is expected when calling tool with non-empty outputSchema";
401+
logger.warn(content);
402+
return CallToolResult.builder()
403+
.content(List.of(new McpSchema.TextContent(content)))
404+
.isError(true)
405+
.build();
406406
}
407407

408408
// Validate the result against the output schema
409409
var validation = this.jsonSchemaValidator.validate(outputSchema, result.structuredContent());
410410

411411
if (!validation.valid()) {
412412
logger.warn("Tool call result validation failed: {}", validation.errorMessage());
413-
return new CallToolResult(validation.errorMessage(), true);
413+
return CallToolResult.builder()
414+
.content(List.of(new McpSchema.TextContent(validation.errorMessage())))
415+
.isError(true)
416+
.build();
414417
}
415418

416419
if (Utils.isEmpty(result.content())) {

mcp-core/src/main/java/io/modelcontextprotocol/server/McpServer.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@
6767
* McpServer.sync(transportProvider)
6868
* .serverInfo("my-server", "1.0.0")
6969
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
70-
* (exchange, args) -> new CallToolResult("Result: " + calculate(args)))
70+
* (exchange, args) -> CallToolResult.builder()
71+
* .content(List.of(new McpSchema.TextContent("Result: " + calculate(args))))
72+
* .isError(false)
73+
* .build())
7174
* .build();
7275
* }</pre>
7376
*
@@ -76,7 +79,10 @@
7679
* .serverInfo("my-server", "1.0.0")
7780
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
7881
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
79-
* .map(result -> new CallToolResult("Result: " + result)))
82+
* .map(result -> CallToolResult.builder()
83+
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
84+
* .isError(false)
85+
* .build()))
8086
* .build();
8187
* }</pre>
8288
*
@@ -90,12 +96,18 @@
9096
* McpServerFeatures.AsyncToolSpecification.builder()
9197
* .tool(calculatorTool)
9298
* .callTool((exchange, args) -> Mono.fromSupplier(() -> calculate(args.arguments()))
93-
* .map(result -> new CallToolResult("Result: " + result))))
99+
* .map(result -> CallToolResult.builder()
100+
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
101+
* .isError(false)
102+
* .build()))
94103
*. .build(),
95104
* McpServerFeatures.AsyncToolSpecification.builder()
96105
* .tool((weatherTool)
97106
* .callTool((exchange, args) -> Mono.fromSupplier(() -> getWeather(args.arguments()))
98-
* .map(result -> new CallToolResult("Weather: " + result))))
107+
* .map(result -> CallToolResult.builder()
108+
* .content(List.of(new McpSchema.TextContent("Weather: " + result)))
109+
* .isError(false)
110+
* .build()))
99111
* .build()
100112
* )
101113
* // Register resources
@@ -425,7 +437,10 @@ public AsyncSpecification<S> capabilities(McpSchema.ServerCapabilities serverCap
425437
* .tool(
426438
* Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
427439
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
428-
* .map(result -> new CallToolResult("Result: " + result))
440+
* .map(result -> CallToolResult.builder()
441+
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
442+
* .isError(false)
443+
* .build()))
429444
* )
430445
* }</pre>
431446
* @param tool The tool definition including name, description, and schema. Must
@@ -1022,7 +1037,10 @@ public SyncSpecification<S> capabilities(McpSchema.ServerCapabilities serverCapa
10221037
* Example usage: <pre>{@code
10231038
* .tool(
10241039
* Tool.builder().name("calculator").title("Performs calculations".inputSchema(schema).build(),
1025-
* (exchange, args) -> new CallToolResult("Result: " + calculate(args))
1040+
* (exchange, args) -> CallToolResult.builder()
1041+
* .content(List.of(new McpSchema.TextContent("Result: " + calculate(args))))
1042+
* .isError(false)
1043+
* .build())
10261044
* )
10271045
* }</pre>
10281046
* @param tool The tool definition including name, description, and schema. Must

mcp-core/src/main/java/io/modelcontextprotocol/server/McpServerFeatures.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,13 @@ public static Builder builder() {
334334
*
335335
* <pre>{@code
336336
* new McpServerFeatures.AsyncResourceSpecification(
337-
* new Resource("docs", "Documentation files", "text/markdown"),
337+
* Resource.builder()
338+
* .uri("docs")
339+
* .name("Documentation files")
340+
* .title("Documentation files")
341+
* .mimeType("text/markdown")
342+
* .description("Markdown documentation files")
343+
* .build(),
338344
* (exchange, request) -> Mono.fromSupplier(() -> readFile(request.getPath()))
339345
* .map(ReadResourceResult::new))
340346
* }</pre>
@@ -508,7 +514,10 @@ static AsyncCompletionSpecification fromSync(SyncCompletionSpecification complet
508514
* .build()
509515
* .toolHandler((exchange, req) -> {
510516
* String expr = (String) req.arguments().get("expression");
511-
* return new CallToolResult("Result: " + evaluate(expr));
517+
* return CallToolResult.builder()
518+
* .content(List.of(new McpSchema.TextContent("Result: " + evaluate(expr))))
519+
* .isError(false)
520+
* .build();
512521
* }))
513522
* .build();
514523
* }</pre>
@@ -604,7 +613,13 @@ public static Builder builder() {
604613
*
605614
* <pre>{@code
606615
* new McpServerFeatures.SyncResourceSpecification(
607-
* new Resource("docs", "Documentation files", "text/markdown"),
616+
* Resource.builder()
617+
* .uri("docs")
618+
* .name("Documentation files")
619+
* .title("Documentation files")
620+
* .mimeType("text/markdown")
621+
* .description("Markdown documentation files")
622+
* .build(),
608623
* (exchange, request) -> {
609624
* String content = readFile(request.getPath());
610625
* return new ReadResourceResult(content);

mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
1515
import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion;
1616
import io.modelcontextprotocol.spec.McpSchema.ErrorCodes;
17-
import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse;
1817
import io.modelcontextprotocol.spec.McpSchema.PromptReference;
1918
import io.modelcontextprotocol.spec.McpSchema.ResourceReference;
2019
import io.modelcontextprotocol.spec.McpSchema.Tool;
@@ -277,19 +276,23 @@ public Mono<CallToolResult> apply(McpTransportContext transportContext, McpSchem
277276
// results that conform to this schema.
278277
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
279278
if (result.structuredContent() == null) {
280-
logger.warn(
281-
"Response missing structured content which is expected when calling tool with non-empty outputSchema");
282-
return new CallToolResult(
283-
"Response missing structured content which is expected when calling tool with non-empty outputSchema",
284-
true);
279+
String content = "Response missing structured content which is expected when calling tool with non-empty outputSchema";
280+
logger.warn(content);
281+
return CallToolResult.builder()
282+
.content(List.of(new McpSchema.TextContent(content)))
283+
.isError(true)
284+
.build();
285285
}
286286

287287
// Validate the result against the output schema
288288
var validation = this.jsonSchemaValidator.validate(outputSchema, result.structuredContent());
289289

290290
if (!validation.valid()) {
291291
logger.warn("Tool call result validation failed: {}", validation.errorMessage());
292-
return new CallToolResult(validation.errorMessage(), true);
292+
return CallToolResult.builder()
293+
.content(List.of(new McpSchema.TextContent(validation.errorMessage())))
294+
.isError(true)
295+
.build();
293296
}
294297

295298
if (Utils.isEmpty(result.content())) {

mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,7 @@ public CallToolResult(List<Content> content, Boolean isError, Map<String, Object
15621562
* content contains error information. If false or absent, indicates successful
15631563
* execution.
15641564
*/
1565+
@Deprecated
15651566
public CallToolResult(String content, Boolean isError) {
15661567
this(List.of(new TextContent(content)), isError, null);
15671568
}
@@ -1676,7 +1677,7 @@ public Builder meta(Map<String, Object> meta) {
16761677
* @return a new CallToolResult instance
16771678
*/
16781679
public CallToolResult build() {
1679-
return new CallToolResult(content, isError, (Object) structuredContent, meta);
1680+
return new CallToolResult(content, isError, structuredContent, meta);
16801681
}
16811682

16821683
}

0 commit comments

Comments
 (0)