Skip to content

Commit 2994317

Browse files
committed
fix(#5): Tools calls are getting mixed up
1 parent e04a782 commit 2994317

File tree

7 files changed

+95
-40
lines changed

7 files changed

+95
-40
lines changed
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.github.codeboyzhou.mcp.declarative.server.component;
22

33
import io.modelcontextprotocol.server.McpSyncServerExchange;
4-
import java.util.function.BiFunction;
4+
import java.lang.reflect.Method;
55

6-
public interface McpServerComponentHandler<U, R> extends BiFunction<McpSyncServerExchange, U, R> {}
6+
public interface McpServerComponentHandler<U, R> {
7+
R invoke(Method method, String description, McpSyncServerExchange exchange, U request);
8+
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/component/McpServerPrompt.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,46 @@ public class McpServerPrompt
2828

2929
private final McpPromptParameterConverter converter;
3030

31-
private MethodMetadata methodCache;
32-
3331
private Object instance;
3432

35-
private String description;
36-
3733
public McpServerPrompt() {
3834
this.converter = injector.getInstance(McpPromptParameterConverter.class);
3935
}
4036

4137
@Override
4238
public McpServerFeatures.SyncPromptSpecification create(Method method) {
4339
// Use reflection cache for performance optimization
44-
methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
40+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
4541
instance = injector.getInstance(methodCache.getDeclaringClass());
4642

4743
McpPrompt promptMethod = methodCache.getMcpPromptAnnotation();
4844
final String name = Strings.defaultIfBlank(promptMethod.name(), methodCache.getMethodName());
4945
final String title = resolveComponentAttributeValue(promptMethod.title());
50-
description = resolveComponentAttributeValue(promptMethod.description());
46+
final String description = resolveComponentAttributeValue(promptMethod.description());
5147

52-
List<McpSchema.PromptArgument> promptArguments = createPromptArguments();
53-
McpSchema.Prompt prompt = new McpSchema.Prompt(name, title, description, promptArguments);
48+
List<McpSchema.PromptArgument> promptArgs = createPromptArguments(methodCache.getParameters());
49+
McpSchema.Prompt prompt = new McpSchema.Prompt(name, title, description, promptArgs);
5450

5551
log.debug(
5652
"Registering prompt: {} (Cached: {})",
5753
ObjectMappers.toJson(prompt),
5854
ReflectionCache.INSTANCE.isCached(method));
5955

60-
return new McpServerFeatures.SyncPromptSpecification(prompt, this);
56+
return new McpServerFeatures.SyncPromptSpecification(
57+
prompt, (exchange, request) -> invoke(method, description, exchange, request));
6158
}
6259

6360
@Override
64-
public McpSchema.GetPromptResult apply(McpSyncServerExchange ex, McpSchema.GetPromptRequest req) {
61+
public McpSchema.GetPromptResult invoke(
62+
Method method,
63+
String description,
64+
McpSyncServerExchange exchange,
65+
McpSchema.GetPromptRequest request) {
66+
6567
Object result;
68+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
6669
try {
67-
Map<String, Object> arguments = req.arguments();
70+
Map<String, Object> arguments = request.arguments();
6871
List<Object> convertedParams = converter.convertAllParameters(methodCache, arguments);
6972
// Use cached method for invocation
7073
result = methodCache.getMethod().invoke(instance, convertedParams.toArray());
@@ -77,8 +80,7 @@ public McpSchema.GetPromptResult apply(McpSyncServerExchange ex, McpSchema.GetPr
7780
return new McpSchema.GetPromptResult(description, List.of(message));
7881
}
7982

80-
private List<McpSchema.PromptArgument> createPromptArguments() {
81-
Parameter[] methodParams = methodCache.getParameters();
83+
private List<McpSchema.PromptArgument> createPromptArguments(Parameter[] methodParams) {
8284
List<McpSchema.PromptArgument> promptArguments = new ArrayList<>(methodParams.length);
8385

8486
for (Parameter param : methodParams) {

src/main/java/com/github/codeboyzhou/mcp/declarative/server/component/McpServerResource.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,14 @@ public class McpServerResource
2121

2222
private static final Logger log = LoggerFactory.getLogger(McpServerResource.class);
2323

24-
private MethodMetadata methodCache;
25-
2624
private Object instance;
2725

2826
private McpSchema.Resource resource;
2927

3028
@Override
3129
public McpServerFeatures.SyncResourceSpecification create(Method method) {
3230
// Use reflection cache for performance optimization
33-
methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
31+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
3432
instance = injector.getInstance(methodCache.getDeclaringClass());
3533

3634
McpResource res = methodCache.getMcpResourceAnnotation();
@@ -53,14 +51,19 @@ public McpServerFeatures.SyncResourceSpecification create(Method method) {
5351
ObjectMappers.toJson(resource),
5452
ReflectionCache.INSTANCE.isCached(method));
5553

56-
return new McpServerFeatures.SyncResourceSpecification(resource, this);
54+
return new McpServerFeatures.SyncResourceSpecification(
55+
resource, (exchange, request) -> invoke(method, description, exchange, request));
5756
}
5857

5958
@Override
60-
public McpSchema.ReadResourceResult apply(
61-
McpSyncServerExchange ex, McpSchema.ReadResourceRequest req) {
59+
public McpSchema.ReadResourceResult invoke(
60+
Method method,
61+
String description,
62+
McpSyncServerExchange exchange,
63+
McpSchema.ReadResourceRequest request) {
6264

6365
Object result;
66+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
6467
try {
6568
// Use cached method for invocation
6669
result = methodCache.getMethod().invoke(instance);

src/main/java/com/github/codeboyzhou/mcp/declarative/server/component/McpServerTool.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ public class McpServerTool
3636

3737
private final McpToolParameterConverter converter;
3838

39-
private MethodMetadata methodCache;
40-
4139
private Object instance;
4240

4341
public McpServerTool() {
@@ -47,15 +45,15 @@ public McpServerTool() {
4745
@Override
4846
public McpServerFeatures.SyncToolSpecification create(Method method) {
4947
// Use reflection cache for performance optimization
50-
methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
48+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
5149
instance = injector.getInstance(methodCache.getDeclaringClass());
5250

5351
McpTool toolMethod = methodCache.getMcpToolAnnotation();
5452
final String name = Strings.defaultIfBlank(toolMethod.name(), methodCache.getMethodName());
5553
final String title = resolveComponentAttributeValue(toolMethod.title());
5654
final String description = resolveComponentAttributeValue(toolMethod.description());
5755

58-
McpSchema.JsonSchema paramSchema = createJsonSchema();
56+
McpSchema.JsonSchema paramSchema = createJsonSchema(methodCache.getParameters());
5957
McpSchema.Tool tool =
6058
McpSchema.Tool.builder()
6159
.name(name)
@@ -69,16 +67,24 @@ public McpServerFeatures.SyncToolSpecification create(Method method) {
6967
ObjectMappers.toJson(tool),
7068
ReflectionCache.INSTANCE.isCached(method));
7169

72-
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(this).build();
70+
return McpServerFeatures.SyncToolSpecification.builder()
71+
.tool(tool)
72+
.callHandler((exchange, request) -> invoke(method, description, exchange, request))
73+
.build();
7374
}
7475

7576
@Override
76-
public McpSchema.CallToolResult apply(McpSyncServerExchange ex, McpSchema.CallToolRequest req) {
77+
public McpSchema.CallToolResult invoke(
78+
Method method,
79+
String description,
80+
McpSyncServerExchange exchange,
81+
McpSchema.CallToolRequest request) {
7782

7883
Object result;
7984
boolean isError = false;
85+
MethodMetadata methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
8086
try {
81-
Map<String, Object> arguments = req.arguments();
87+
Map<String, Object> arguments = request.arguments();
8288
List<Object> convertedParams = converter.convertAllParameters(methodCache, arguments);
8389
// Use cached method for invocation
8490
result = methodCache.getMethod().invoke(instance, convertedParams.toArray());
@@ -91,12 +97,11 @@ public McpSchema.CallToolResult apply(McpSyncServerExchange ex, McpSchema.CallTo
9197
return new McpSchema.CallToolResult(List.of(content), isError);
9298
}
9399

94-
private McpSchema.JsonSchema createJsonSchema() {
100+
private McpSchema.JsonSchema createJsonSchema(Parameter[] methodParams) {
95101
Map<String, Object> properties = new LinkedHashMap<>();
96102
Map<String, Object> definitions = new LinkedHashMap<>();
97103
List<String> required = new ArrayList<>();
98104

99-
Parameter[] methodParams = methodCache.getParameters();
100105
for (Parameter param : methodParams) {
101106
if (param.isAnnotationPresent(McpToolParam.class)) {
102107
McpToolParam toolParam = param.getAnnotation(McpToolParam.class);

src/test/java/com/github/codeboyzhou/mcp/declarative/McpServersTest.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ private void verifyResourcesRegistered(McpSyncClient client) {
182182

183183
private void verifyPromptsRegistered(McpSyncClient client) {
184184
List<McpSchema.Prompt> prompts = client.listPrompts().prompts();
185-
assertEquals(1, prompts.size());
185+
assertEquals(2, prompts.size());
186186

187187
McpSchema.Prompt prompt = prompts.get(0);
188188
assertEquals("prompt1_name", prompt.name());
@@ -205,17 +205,31 @@ private void verifyPromptsCalled(McpSyncClient client) {
205205
McpSchema.GetPromptRequest request1 = new McpSchema.GetPromptRequest(name1, args1);
206206
McpSchema.GetPromptResult result1 = client.getPrompt(request1);
207207
McpSchema.TextContent content = (McpSchema.TextContent) result1.messages().get(0).content();
208-
assertEquals(args1.get("param1") + args1.get("param2").toString(), content.text());
209208
assertEquals("prompt1_description", result1.description());
209+
assertEquals("prompt1 is called", content.text());
210+
211+
String name2 = "prompt2_name";
212+
Map<String, Object> args2 = Map.of("param1", "value1", "param2", "value2");
213+
McpSchema.GetPromptRequest request2 = new McpSchema.GetPromptRequest(name2, args2);
214+
McpSchema.GetPromptResult result2 = client.getPrompt(request2);
215+
McpSchema.TextContent content2 = (McpSchema.TextContent) result2.messages().get(0).content();
216+
assertEquals("prompt2_description", result2.description());
217+
assertEquals("prompt2 is called", content2.text());
210218
}
211219

212220
private void verifyToolsRegistered(McpSyncClient client) {
213221
List<McpSchema.Tool> tools = client.listTools().tools();
214-
assertEquals(1, tools.size());
215-
McpSchema.Tool tool = tools.get(0);
216-
assertEquals("tool1_name", tool.name());
217-
assertEquals("tool1_title", tool.title());
218-
assertEquals("tool1_description", tool.description());
222+
assertEquals(2, tools.size());
223+
224+
McpSchema.Tool tool1 = tools.get(0);
225+
assertEquals("tool1_name", tool1.name());
226+
assertEquals("tool1_title", tool1.title());
227+
assertEquals("tool1_description", tool1.description());
228+
229+
McpSchema.Tool tool2 = tools.get(1);
230+
assertEquals("tool2_name", tool2.name());
231+
assertEquals("tool2_title", tool2.title());
232+
assertEquals("tool2_description", tool2.description());
219233
}
220234

221235
private void verifyToolsCalled(McpSyncClient client) {
@@ -224,7 +238,15 @@ private void verifyToolsCalled(McpSyncClient client) {
224238
McpSchema.CallToolRequest request1 = new McpSchema.CallToolRequest(name1, args1);
225239
McpSchema.CallToolResult result1 = client.callTool(request1);
226240
McpSchema.TextContent content = (McpSchema.TextContent) result1.content().get(0);
227-
assertEquals(args1.get("param1") + args1.get("param2").toString(), content.text());
228241
assertFalse(result1.isError());
242+
assertEquals("tool1 is called", content.text());
243+
244+
String name2 = "tool2_name";
245+
Map<String, Object> args2 = Map.of("param1", "value1", "param2", "value2");
246+
McpSchema.CallToolRequest request2 = new McpSchema.CallToolRequest(name2, args2);
247+
McpSchema.CallToolResult result2 = client.callTool(request2);
248+
McpSchema.TextContent content2 = (McpSchema.TextContent) result2.content().get(0);
249+
assertFalse(result2.isError());
250+
assertEquals("tool2 is called", content2.text());
229251
}
230252
}

src/test/java/com/github/codeboyzhou/mcp/declarative/test/TestMcpPrompts.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ public String prompt1(
1717
String param2,
1818
String param3) {
1919
log.debug("prompt1 called with params: {}, {}, {}", param1, param2, param3);
20-
return param1 + param2;
20+
return "prompt1 is called";
21+
}
22+
23+
@McpPrompt(name = "prompt2_name", title = "prompt2_title", description = "prompt2_description")
24+
public String prompt2(
25+
@McpPromptParam(name = "param1", title = "param1_title", description = "param1_description")
26+
String param1,
27+
@McpPromptParam(name = "param2", title = "param2_title", description = "param2_description")
28+
String param2,
29+
String param3) {
30+
log.debug("prompt2 called with params: {}, {}, {}", param1, param2, param3);
31+
return "prompt2 is called";
2132
}
2233
}

src/test/java/com/github/codeboyzhou/mcp/declarative/test/TestMcpTools.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ public String tool1(
1616
String param2,
1717
String param3) {
1818
log.debug("tool1 called with params: {}, {}, {}", param1, param2, param3);
19-
return param1 + param2;
19+
return "tool1 is called";
20+
}
21+
22+
@McpTool(name = "tool2_name", title = "tool2_title", description = "tool2_description")
23+
public String tool2(
24+
@McpToolParam(name = "param1", description = "param1_description") String param1,
25+
@McpToolParam(name = "param2", description = "param2_description", required = true)
26+
String param2,
27+
String param3) {
28+
log.debug("tool2 called with params: {}, {}, {}", param1, param2, param3);
29+
return "tool2 is called";
2030
}
2131
}

0 commit comments

Comments
 (0)