Skip to content

Commit 60c12d7

Browse files
committed
feat(annotation): Introduce the annotations related to MCP prompt
1 parent 5c13299 commit 60c12d7

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.github.codeboyzhou.mcp.declarative.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.METHOD)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface McpPrompt {
11+
12+
String name() default "";
13+
14+
String description();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.github.codeboyzhou.mcp.declarative.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.PARAMETER)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface McpPromptParam {
11+
12+
String name();
13+
14+
String description();
15+
16+
boolean required() default false;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.github.codeboyzhou.mcp.declarative.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.TYPE)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface McpPrompts {
11+
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/McpServerComponentRegisters.java

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.codeboyzhou.mcp.declarative.server;
22

3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompts;
34
import com.github.codeboyzhou.mcp.declarative.annotation.McpResources;
45
import com.github.codeboyzhou.mcp.declarative.annotation.McpTools;
56
import io.modelcontextprotocol.server.McpSyncServer;
@@ -13,6 +14,9 @@ public static void registerAllTo(McpSyncServer server, Reflections reflections)
1314
Set<Class<?>> resourceClasses = reflections.getTypesAnnotatedWith(McpResources.class);
1415
new McpSyncServerResourceRegister(resourceClasses).registerTo(server);
1516

17+
Set<Class<?>> promptClasses = reflections.getTypesAnnotatedWith(McpPrompts.class);
18+
new McpSyncServerPromptRegister(promptClasses).registerTo(server);
19+
1620
Set<Class<?>> toolClasses = reflections.getTypesAnnotatedWith(McpTools.class);
1721
new McpSyncServerToolRegister(toolClasses).registerTo(server);
1822
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompt;
4+
import com.github.codeboyzhou.mcp.declarative.annotation.McpPromptParam;
5+
import com.github.codeboyzhou.mcp.declarative.util.ReflectionHelper;
6+
import io.modelcontextprotocol.server.McpServerFeatures;
7+
import io.modelcontextprotocol.server.McpSyncServer;
8+
import io.modelcontextprotocol.spec.McpSchema;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.lang.reflect.Method;
13+
import java.lang.reflect.Parameter;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
import java.util.Set;
17+
18+
public class McpSyncServerPromptRegister
19+
implements McpServerComponentRegister<McpSyncServer, McpServerFeatures.SyncPromptSpecification> {
20+
21+
private static final Logger logger = LoggerFactory.getLogger(McpSyncServerPromptRegister.class);
22+
23+
private final Set<Class<?>> promptClasses;
24+
25+
public McpSyncServerPromptRegister(Set<Class<?>> promptClasses) {
26+
this.promptClasses = promptClasses;
27+
}
28+
29+
@Override
30+
public void registerTo(McpSyncServer server) {
31+
for (Class<?> promptClass : promptClasses) {
32+
Set<Method> methods = ReflectionHelper.getMethodsAnnotatedWith(promptClass, McpPrompt.class);
33+
for (Method method : methods) {
34+
McpServerFeatures.SyncPromptSpecification prompt = createComponentFrom(promptClass, method);
35+
server.addPrompt(prompt);
36+
}
37+
}
38+
}
39+
40+
@Override
41+
public McpServerFeatures.SyncPromptSpecification createComponentFrom(Class<?> clazz, Method method) {
42+
McpPrompt promptMethod = method.getAnnotation(McpPrompt.class);
43+
final String name = promptMethod.name().isBlank() ? method.getName() : promptMethod.name();
44+
final String description = promptMethod.description();
45+
List<McpSchema.PromptArgument> promptArguments = createPromptArguments(method);
46+
McpSchema.Prompt prompt = new McpSchema.Prompt(name, description, promptArguments);
47+
return new McpServerFeatures.SyncPromptSpecification(prompt, (exchange, request) -> {
48+
Object result;
49+
try {
50+
result = ReflectionHelper.invokeMethod(clazz, method, request.arguments());
51+
} catch (Throwable e) {
52+
logger.error("Error invoking prompt method", e);
53+
result = e + ": " + e.getMessage();
54+
}
55+
McpSchema.Content content = new McpSchema.TextContent(result.toString());
56+
McpSchema.PromptMessage message = new McpSchema.PromptMessage(McpSchema.Role.USER, content);
57+
return new McpSchema.GetPromptResult(description, List.of(message));
58+
});
59+
}
60+
61+
private List<McpSchema.PromptArgument> createPromptArguments(Method method) {
62+
Set<Parameter> parameters = ReflectionHelper.getParametersAnnotatedWith(method, McpPromptParam.class);
63+
List<McpSchema.PromptArgument> promptArguments = new ArrayList<>(parameters.size());
64+
for (Parameter parameter : parameters) {
65+
McpPromptParam promptParam = parameter.getAnnotation(McpPromptParam.class);
66+
final String name = promptParam.name();
67+
final String description = promptParam.description();
68+
final boolean required = promptParam.required();
69+
McpSchema.PromptArgument promptArgument = new McpSchema.PromptArgument(name, description, required);
70+
promptArguments.add(promptArgument);
71+
}
72+
return promptArguments;
73+
}
74+
75+
}

src/main/java/com/github/codeboyzhou/mcp/declarative/util/ReflectionHelper.java

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public static Object invokeMethod(Class<?> clazz, Method method) throws Exceptio
2828
return method.invoke(object);
2929
}
3030

31+
public static Object invokeMethod(Class<?> clazz, Method method, Map<String, Object> parameters) throws Exception {
32+
Object object = clazz.getDeclaredConstructor().newInstance();
33+
return method.invoke(object, parameters.values().toArray());
34+
}
35+
3136
public static Object invokeMethod(Class<?> clazz, Method method, McpSchema.JsonSchema schema, Map<String, Object> parameters) throws Exception {
3237
Object object = clazz.getDeclaredConstructor().newInstance();
3338
Map<String, Object> typedParameters = asTypedParameters(schema, parameters);

0 commit comments

Comments
 (0)