Skip to content

Commit 439c545

Browse files
committed
Fix stateless MCP tools calling
Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent ad93613 commit 439c545

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StatelessWebClientWebFluxServerIT.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.Map;
2626

2727
import org.junit.jupiter.api.Test;
28+
import org.springframework.ai.chat.model.ToolContext;
29+
import org.springframework.ai.mcp.McpToolUtils;
2830
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
2931
import org.springframework.ai.mcp.client.common.autoconfigure.McpToolCallbackAutoConfiguration;
3032
import org.springframework.ai.mcp.client.webflux.autoconfigure.StreamableHttpWebFluxTransportAutoConfiguration;
@@ -33,6 +35,7 @@
3335
import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties;
3436
import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStatelessAutoConfiguration;
3537
import org.springframework.ai.mcp.server.common.autoconfigure.StatelessToolCallbackConverterAutoConfiguration;
38+
import org.springframework.ai.tool.function.FunctionToolCallback;
3639
import org.springframework.beans.factory.ObjectProvider;
3740
import org.springframework.boot.autoconfigure.AutoConfigurations;
3841
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -123,7 +126,7 @@ void clientServerCapabilities() {
123126
// TOOLS / SAMPLING / ELICITATION
124127

125128
// tool list
126-
assertThat(mcpClient.listTools().tools()).hasSize(2);
129+
assertThat(mcpClient.listTools().tools()).hasSize(3);
127130
assertThat(mcpClient.listTools().tools())
128131
.contains(Tool.builder().name("tool1").description("tool1 description").inputSchema("""
129132
{
@@ -167,6 +170,18 @@ void clientServerCapabilities() {
167170
.isEqualTo(json("""
168171
{"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}"""));
169172

173+
// TOOL FROM MCP TOOL UTILS
174+
// Call the tool to ensure arguments are passed correctly
175+
CallToolResult toUpperCaseResponse = mcpClient
176+
.callTool(new McpSchema.CallToolRequest("toUpperCase", Map.of("input", "hello world")));
177+
assertThat(toUpperCaseResponse).isNotNull();
178+
assertThat(toUpperCaseResponse.isError()).isFalse();
179+
assertThat(toUpperCaseResponse.content()).hasSize(1)
180+
.first()
181+
.isInstanceOf(TextContent.class)
182+
.extracting("text")
183+
.isEqualTo("\"HELLO WORLD\"");
184+
170185
// PROMPT / COMPLETION
171186

172187
// list prompts
@@ -255,7 +270,20 @@ public List<McpStatelessServerFeatures.SyncToolSpecification> myTools() {
255270
})
256271
.build();
257272

258-
return List.of(tool1, tool2);
273+
// Tool 3
274+
275+
// Using a tool with McpToolUtils
276+
McpStatelessServerFeatures.SyncToolSpecification tool3 = McpToolUtils
277+
.toStatelessSyncToolSpecification(FunctionToolCallback
278+
.builder("toUpperCase", (ToUpperCaseRequest req, ToolContext context) -> req.input().toUpperCase())
279+
.description("Sets the input string to upper case")
280+
.inputType(ToUpperCaseRequest.class)
281+
.build(), null);
282+
283+
return List.of(tool1, tool2, tool3);
284+
}
285+
286+
record ToUpperCaseRequest(String input) {
259287
}
260288

261289
@Bean

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public static McpStatelessServerFeatures.SyncToolSpecification toStatelessSyncTo
201201

202202
return new McpStatelessServerFeatures.SyncToolSpecification(tool, (mcpTransportContext, request) -> {
203203
try {
204-
String callResult = toolCallback.call(ModelOptionsUtils.toJsonString(request),
204+
String callResult = toolCallback.call(ModelOptionsUtils.toJsonString(request.arguments()),
205205
new ToolContext(Map.of(TOOL_CONTEXT_MCP_EXCHANGE_KEY, mcpTransportContext)));
206206
if (mimeType != null && mimeType.toString().startsWith("image")) {
207207
return new McpSchema.CallToolResult(List

0 commit comments

Comments
 (0)