2
2
3
3
import com .fasterxml .jackson .databind .ObjectMapper ;
4
4
import com .github .codeboyzhou .mcp .declarative .annotation .*;
5
- import com .github .codeboyzhou .mcp .declarative .util .Annotations ;
5
+ import com .github .codeboyzhou .mcp .declarative .util .ReflectionHelper ;
6
6
import io .modelcontextprotocol .server .McpServer ;
7
7
import io .modelcontextprotocol .server .McpServerFeatures ;
8
8
import io .modelcontextprotocol .server .McpSyncServer ;
@@ -24,6 +24,8 @@ public class McpServers {
24
24
25
25
private static final Logger logger = LoggerFactory .getLogger (McpServers .class );
26
26
27
+ private static final McpServers INSTANCE = new McpServers ();
28
+
27
29
private static final McpSchema .ServerCapabilities DEFAULT_SERVER_CAPABILITIES = McpSchema .ServerCapabilities
28
30
.builder ()
29
31
.resources (true , true )
@@ -33,17 +35,29 @@ public class McpServers {
33
35
34
36
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
35
37
36
- private static final String OBJECT_TYPE_NAME = Object .class .getName ().toLowerCase ();
37
-
38
- private static final Reflections REFLECTIONS = new Reflections ();
38
+ private static final String OBJECT_TYPE_NAME = Object .class .getSimpleName ().toLowerCase ();
39
39
40
40
private static final String DEFAULT_MESSAGE_ENDPOINT = "/message" ;
41
41
42
42
private static final String DEFAULT_SSE_ENDPOINT = "/sse" ;
43
43
44
44
private static final int DEFAULT_HTTP_SERVER_PORT = 8080 ;
45
45
46
- public static void startSyncStdioServer (String name , String version ) {
46
+ private static Reflections reflections ;
47
+
48
+ public static McpServers run (Class <?> applicationMainClass , String [] args ) {
49
+ McpComponentScan scan = applicationMainClass .getAnnotation (McpComponentScan .class );
50
+ if (scan == null ) {
51
+ reflections = new Reflections (applicationMainClass .getPackageName ());
52
+ } else if (!scan .basePackage ().trim ().isBlank ()) {
53
+ reflections = new Reflections (scan .basePackage ());
54
+ } else if (scan .basePackageClass () != Object .class ) {
55
+ reflections = new Reflections (scan .basePackageClass ().getPackageName ());
56
+ }
57
+ return INSTANCE ;
58
+ }
59
+
60
+ public void startSyncStdioServer (String name , String version ) {
47
61
McpSyncServer server = McpServer .sync (new StdioServerTransportProvider ())
48
62
.capabilities (DEFAULT_SERVER_CAPABILITIES )
49
63
.serverInfo (name , version )
@@ -53,15 +67,15 @@ public static void startSyncStdioServer(String name, String version) {
53
67
registerTools (server );
54
68
}
55
69
56
- public static void startSyncSseServer (String name , String version ) {
70
+ public void startSyncSseServer (String name , String version ) {
57
71
startSyncSseServer (name , version , DEFAULT_MESSAGE_ENDPOINT , DEFAULT_SSE_ENDPOINT , DEFAULT_HTTP_SERVER_PORT );
58
72
}
59
73
60
- public static void startSyncSseServer (String name , String version , int port ) {
74
+ public void startSyncSseServer (String name , String version , int port ) {
61
75
startSyncSseServer (name , version , DEFAULT_MESSAGE_ENDPOINT , DEFAULT_SSE_ENDPOINT , port );
62
76
}
63
77
64
- public static void startSyncSseServer (String name , String version , String messageEndpoint , String sseEndpoint , int port ) {
78
+ public void startSyncSseServer (String name , String version , String messageEndpoint , String sseEndpoint , int port ) {
65
79
HttpServletSseServerTransportProvider transport = new HttpServletSseServerTransportProvider (
66
80
OBJECT_MAPPER , messageEndpoint , sseEndpoint
67
81
);
@@ -77,7 +91,7 @@ public static void startSyncSseServer(String name, String version, String messag
77
91
startHttpServer (server , transport , port );
78
92
}
79
93
80
- private static void startHttpServer (McpSyncServer server , HttpServletSseServerTransportProvider transport , int port ) {
94
+ private void startHttpServer (McpSyncServer server , HttpServletSseServerTransportProvider transport , int port ) {
81
95
ServletContextHandler servletContextHandler = new ServletContextHandler (ServletContextHandler .SESSIONS );
82
96
servletContextHandler .setContextPath ("/" );
83
97
@@ -109,25 +123,25 @@ private static void startHttpServer(McpSyncServer server, HttpServletSseServerTr
109
123
}
110
124
}
111
125
112
- private static void registerResources (McpSyncServer server ) {
113
- Set <Class <?>> resourceClasses = REFLECTIONS .getTypesAnnotatedWith (McpResources .class );
126
+ private void registerResources (McpSyncServer server ) {
127
+ Set <Class <?>> resourceClasses = reflections .getTypesAnnotatedWith (McpResources .class );
114
128
for (Class <?> resourceClass : resourceClasses ) {
115
- Set <Method > methods = Annotations .getMethodsAnnotatedWith (resourceClass , McpResource .class );
129
+ Set <Method > methods = ReflectionHelper .getMethodsAnnotatedWith (resourceClass , McpResource .class );
116
130
for (Method method : methods ) {
117
131
McpResource resourceMethod = method .getAnnotation (McpResource .class );
118
132
McpSchema .Resource resource = new McpSchema .Resource (
119
133
resourceMethod .uri (),
120
- resourceMethod .name (),
134
+ resourceMethod .name (). isBlank () ? method . getName () : resourceMethod . name () ,
121
135
resourceMethod .description (),
122
136
resourceMethod .mimeType (),
123
137
new McpSchema .Annotations (List .of (resourceMethod .roles ()), resourceMethod .priority ())
124
138
);
125
139
server .addResource (new McpServerFeatures .SyncResourceSpecification (resource , (exchange , request ) -> {
126
140
Object result ;
127
141
try {
128
- Object resourceObject = resourceClass . getDeclaredConstructor (). newInstance ( );
129
- result = method . invoke ( resourceObject );
130
- } catch ( Exception e ) {
142
+ result = ReflectionHelper . invokeMethod ( resourceClass , method );
143
+ } catch ( Throwable e ) {
144
+ logger . error ( "Error invoking resource method" , e );
131
145
result = e + ": " + e .getMessage ();
132
146
}
133
147
McpSchema .ResourceContents contents = new McpSchema .TextResourceContents (
@@ -139,21 +153,22 @@ private static void registerResources(McpSyncServer server) {
139
153
}
140
154
}
141
155
142
- private static void registerTools (McpSyncServer server ) {
143
- Set <Class <?>> toolClasses = REFLECTIONS .getTypesAnnotatedWith (McpTools .class );
156
+ private void registerTools (McpSyncServer server ) {
157
+ Set <Class <?>> toolClasses = reflections .getTypesAnnotatedWith (McpTools .class );
144
158
for (Class <?> toolClass : toolClasses ) {
145
- Set <Method > methods = Annotations .getMethodsAnnotatedWith (toolClass , McpTool .class );
159
+ Set <Method > methods = ReflectionHelper .getMethodsAnnotatedWith (toolClass , McpTool .class );
146
160
for (Method method : methods ) {
147
161
McpTool toolMethod = method .getAnnotation (McpTool .class );
148
162
McpSchema .JsonSchema paramSchema = createJsonSchema (method );
149
- McpSchema .Tool tool = new McpSchema .Tool (toolMethod .name (), toolMethod .description (), paramSchema );
163
+ final String toolName = toolMethod .name ().isBlank () ? method .getName () : toolMethod .name ();
164
+ McpSchema .Tool tool = new McpSchema .Tool (toolName , toolMethod .description (), paramSchema );
150
165
server .addTool (new McpServerFeatures .SyncToolSpecification (tool , (exchange , params ) -> {
151
166
Object result ;
152
167
boolean isError = false ;
153
168
try {
154
- Object toolObject = toolClass . getDeclaredConstructor (). newInstance ( );
155
- result = method . invoke ( toolObject , params . values ());
156
- } catch ( Exception e ) {
169
+ result = ReflectionHelper . invokeMethod ( toolClass , method , paramSchema , params );
170
+ } catch ( Throwable e ) {
171
+ logger . error ( "Error invoking tool method" , e );
157
172
result = e + ": " + e .getMessage ();
158
173
isError = true ;
159
174
}
@@ -164,15 +179,15 @@ private static void registerTools(McpSyncServer server) {
164
179
}
165
180
}
166
181
167
- private static McpSchema .JsonSchema createJsonSchema (Method method ) {
182
+ private McpSchema .JsonSchema createJsonSchema (Method method ) {
168
183
Map <String , Object > properties = new HashMap <>();
169
184
List <String > required = new ArrayList <>();
170
185
171
- Set <Parameter > parameters = Annotations .getParametersAnnotatedWith (method , McpToolParam .class );
186
+ Set <Parameter > parameters = ReflectionHelper .getParametersAnnotatedWith (method , McpToolParam .class );
172
187
for (Parameter parameter : parameters ) {
173
- final String parameterName = parameter .getName ();
174
- final String parameterType = parameter .getType ().getName ().toLowerCase ();
175
188
McpToolParam toolParam = parameter .getAnnotation (McpToolParam .class );
189
+ final String parameterName = toolParam .name ();
190
+ final String parameterType = parameter .getType ().getName ().toLowerCase ();
176
191
177
192
Map <String , String > parameterProperties = Map .of (
178
193
"type" , parameterType ,
0 commit comments