Skip to content

Commit 8a2d86b

Browse files
refactor(McpToolUtils): Use builder pattern instead of deprecated constructors
- Update SyncToolSpecification creation to use builder pattern - Update AsyncToolSpecification creation to use builder pattern - Improve code readability and maintainability Signed-off-by: codeboyzhou <imzhouchen@gmail.com> Co-authored-by: Ilayaperumal Gopinathan <ilayaperumal.gopinathan@broadcom.com>
1 parent c796cbd commit 8a2d86b

File tree

2 files changed

+21
-12
lines changed

2 files changed

+21
-12
lines changed

mcp/common/src/main/java/org/springframework/ai/mcp/McpToolUtils.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import io.modelcontextprotocol.client.McpAsyncClient;
2929
import io.modelcontextprotocol.client.McpSyncClient;
3030
import io.modelcontextprotocol.server.McpServerFeatures;
31-
import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolSpecification;
3231
import io.modelcontextprotocol.server.McpStatelessServerFeatures;
3332
import io.modelcontextprotocol.server.McpSyncServerExchange;
3433
import io.modelcontextprotocol.spec.McpSchema;
@@ -222,8 +221,10 @@ public static McpStatelessServerFeatures.SyncToolSpecification toStatelessSyncTo
222221

223222
var sharedSpec = toSharedSyncToolSpecification(toolCallback, mimeType);
224223

225-
return new McpStatelessServerFeatures.SyncToolSpecification(sharedSpec.tool(),
226-
(exchange, request) -> sharedSpec.sharedHandler().apply(exchange, request));
224+
return McpStatelessServerFeatures.SyncToolSpecification.builder()
225+
.tool(sharedSpec.tool())
226+
.callHandler((exchange, request) -> sharedSpec.sharedHandler().apply(exchange, request))
227+
.build();
227228
}
228229

229230
private static SharedSyncToolSpecification toSharedSyncToolSpecification(ToolCallback toolCallback,
@@ -241,9 +242,9 @@ private static SharedSyncToolSpecification toSharedSyncToolSpecification(ToolCal
241242
String callResult = toolCallback.call(ModelOptionsUtils.toJsonString(request.arguments()),
242243
new ToolContext(Map.of(TOOL_CONTEXT_MCP_EXCHANGE_KEY, exchangeOrContext)));
243244
if (mimeType != null && mimeType.toString().startsWith("image")) {
244-
return new McpSchema.CallToolResult(List
245-
.of(new McpSchema.ImageContent(List.of(Role.ASSISTANT), null, callResult, mimeType.toString())),
246-
false);
245+
McpSchema.Annotations annotations = new McpSchema.Annotations(List.of(Role.ASSISTANT), null);
246+
return new McpSchema.CallToolResult(
247+
List.of(new McpSchema.ImageContent(annotations, callResult, mimeType.toString())), false);
247248
}
248249
return new McpSchema.CallToolResult(List.of(new McpSchema.TextContent(callResult)), false);
249250
}
@@ -353,10 +354,13 @@ public static McpServerFeatures.AsyncToolSpecification toAsyncToolSpecification(
353354

354355
McpServerFeatures.SyncToolSpecification syncToolSpecification = toSyncToolSpecification(toolCallback, mimeType);
355356

356-
return new AsyncToolSpecification(syncToolSpecification.tool(),
357-
(exchange, map) -> Mono
358-
.fromCallable(() -> syncToolSpecification.call().apply(new McpSyncServerExchange(exchange), map))
359-
.subscribeOn(Schedulers.boundedElastic()));
357+
return McpServerFeatures.AsyncToolSpecification.builder()
358+
.tool(syncToolSpecification.tool())
359+
.callHandler((exchange, request) -> Mono
360+
.fromCallable(
361+
() -> syncToolSpecification.callHandler().apply(new McpSyncServerExchange(exchange), request))
362+
.subscribeOn(Schedulers.boundedElastic()))
363+
.build();
360364
}
361365

362366
public static McpStatelessServerFeatures.AsyncToolSpecification toStatelessAsyncToolSpecification(

mcp/common/src/test/java/org/springframework/ai/mcp/ToolUtilsTests.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolSpecification;
2727
import io.modelcontextprotocol.server.McpServerFeatures.SyncToolSpecification;
2828
import io.modelcontextprotocol.server.McpSyncServerExchange;
29+
import io.modelcontextprotocol.spec.McpSchema;
2930
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
3031
import io.modelcontextprotocol.spec.McpSchema.Implementation;
3132
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
@@ -267,7 +268,9 @@ void toAsyncToolSpecificationShouldConvertSingleCallback() {
267268
assertThat(toolSpecification).isNotNull();
268269
assertThat(toolSpecification.tool().name()).isEqualTo("test");
269270

270-
StepVerifier.create(toolSpecification.call().apply(mock(McpAsyncServerExchange.class), Map.of()))
271+
StepVerifier
272+
.create(toolSpecification.callHandler()
273+
.apply(mock(McpAsyncServerExchange.class), mock(McpSchema.CallToolRequest.class)))
271274
.assertNext(result -> {
272275
TextContent content = (TextContent) result.content().get(0);
273276
assertThat(content.text()).isEqualTo("success");
@@ -283,7 +286,9 @@ void toAsyncToolSpecificationShouldHandleError() {
283286
AsyncToolSpecification toolSpecification = McpToolUtils.toAsyncToolSpecification(callback);
284287

285288
assertThat(toolSpecification).isNotNull();
286-
StepVerifier.create(toolSpecification.call().apply(mock(McpAsyncServerExchange.class), Map.of()))
289+
StepVerifier
290+
.create(toolSpecification.callHandler()
291+
.apply(mock(McpAsyncServerExchange.class), mock(McpSchema.CallToolRequest.class)))
287292
.assertNext(result -> {
288293
TextContent content = (TextContent) result.content().get(0);
289294
assertThat(content.text()).isEqualTo("error");

0 commit comments

Comments
 (0)