22
33import com .fasterxml .jackson .databind .ObjectMapper ;
44import com .github .codeboyzhou .mcp .declarative .annotation .*;
5- import com .github .codeboyzhou .mcp .declarative .util .Annotations ;
5+ import com .github .codeboyzhou .mcp .declarative .util .ReflectionHelper ;
66import io .modelcontextprotocol .server .McpServer ;
77import io .modelcontextprotocol .server .McpServerFeatures ;
88import io .modelcontextprotocol .server .McpSyncServer ;
@@ -24,6 +24,8 @@ public class McpServers {
2424
2525 private static final Logger logger = LoggerFactory .getLogger (McpServers .class );
2626
27+ private static final McpServers INSTANCE = new McpServers ();
28+
2729 private static final McpSchema .ServerCapabilities DEFAULT_SERVER_CAPABILITIES = McpSchema .ServerCapabilities
2830 .builder ()
2931 .resources (true , true )
@@ -33,17 +35,29 @@ public class McpServers {
3335
3436 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
3537
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 ();
3939
4040 private static final String DEFAULT_MESSAGE_ENDPOINT = "/message" ;
4141
4242 private static final String DEFAULT_SSE_ENDPOINT = "/sse" ;
4343
4444 private static final int DEFAULT_HTTP_SERVER_PORT = 8080 ;
4545
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 ) {
4761 McpSyncServer server = McpServer .sync (new StdioServerTransportProvider ())
4862 .capabilities (DEFAULT_SERVER_CAPABILITIES )
4963 .serverInfo (name , version )
@@ -53,15 +67,15 @@ public static void startSyncStdioServer(String name, String version) {
5367 registerTools (server );
5468 }
5569
56- public static void startSyncSseServer (String name , String version ) {
70+ public void startSyncSseServer (String name , String version ) {
5771 startSyncSseServer (name , version , DEFAULT_MESSAGE_ENDPOINT , DEFAULT_SSE_ENDPOINT , DEFAULT_HTTP_SERVER_PORT );
5872 }
5973
60- public static void startSyncSseServer (String name , String version , int port ) {
74+ public void startSyncSseServer (String name , String version , int port ) {
6175 startSyncSseServer (name , version , DEFAULT_MESSAGE_ENDPOINT , DEFAULT_SSE_ENDPOINT , port );
6276 }
6377
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 ) {
6579 HttpServletSseServerTransportProvider transport = new HttpServletSseServerTransportProvider (
6680 OBJECT_MAPPER , messageEndpoint , sseEndpoint
6781 );
@@ -77,7 +91,7 @@ public static void startSyncSseServer(String name, String version, String messag
7791 startHttpServer (server , transport , port );
7892 }
7993
80- private static void startHttpServer (McpSyncServer server , HttpServletSseServerTransportProvider transport , int port ) {
94+ private void startHttpServer (McpSyncServer server , HttpServletSseServerTransportProvider transport , int port ) {
8195 ServletContextHandler servletContextHandler = new ServletContextHandler (ServletContextHandler .SESSIONS );
8296 servletContextHandler .setContextPath ("/" );
8397
@@ -109,25 +123,25 @@ private static void startHttpServer(McpSyncServer server, HttpServletSseServerTr
109123 }
110124 }
111125
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 );
114128 for (Class <?> resourceClass : resourceClasses ) {
115- Set <Method > methods = Annotations .getMethodsAnnotatedWith (resourceClass , McpResource .class );
129+ Set <Method > methods = ReflectionHelper .getMethodsAnnotatedWith (resourceClass , McpResource .class );
116130 for (Method method : methods ) {
117131 McpResource resourceMethod = method .getAnnotation (McpResource .class );
118132 McpSchema .Resource resource = new McpSchema .Resource (
119133 resourceMethod .uri (),
120- resourceMethod .name (),
134+ resourceMethod .name (). isBlank () ? method . getName () : resourceMethod . name () ,
121135 resourceMethod .description (),
122136 resourceMethod .mimeType (),
123137 new McpSchema .Annotations (List .of (resourceMethod .roles ()), resourceMethod .priority ())
124138 );
125139 server .addResource (new McpServerFeatures .SyncResourceSpecification (resource , (exchange , request ) -> {
126140 Object result ;
127141 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 );
131145 result = e + ": " + e .getMessage ();
132146 }
133147 McpSchema .ResourceContents contents = new McpSchema .TextResourceContents (
@@ -139,21 +153,22 @@ private static void registerResources(McpSyncServer server) {
139153 }
140154 }
141155
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 );
144158 for (Class <?> toolClass : toolClasses ) {
145- Set <Method > methods = Annotations .getMethodsAnnotatedWith (toolClass , McpTool .class );
159+ Set <Method > methods = ReflectionHelper .getMethodsAnnotatedWith (toolClass , McpTool .class );
146160 for (Method method : methods ) {
147161 McpTool toolMethod = method .getAnnotation (McpTool .class );
148162 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 );
150165 server .addTool (new McpServerFeatures .SyncToolSpecification (tool , (exchange , params ) -> {
151166 Object result ;
152167 boolean isError = false ;
153168 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 );
157172 result = e + ": " + e .getMessage ();
158173 isError = true ;
159174 }
@@ -164,15 +179,15 @@ private static void registerTools(McpSyncServer server) {
164179 }
165180 }
166181
167- private static McpSchema .JsonSchema createJsonSchema (Method method ) {
182+ private McpSchema .JsonSchema createJsonSchema (Method method ) {
168183 Map <String , Object > properties = new HashMap <>();
169184 List <String > required = new ArrayList <>();
170185
171- Set <Parameter > parameters = Annotations .getParametersAnnotatedWith (method , McpToolParam .class );
186+ Set <Parameter > parameters = ReflectionHelper .getParametersAnnotatedWith (method , McpToolParam .class );
172187 for (Parameter parameter : parameters ) {
173- final String parameterName = parameter .getName ();
174- final String parameterType = parameter .getType ().getName ().toLowerCase ();
175188 McpToolParam toolParam = parameter .getAnnotation (McpToolParam .class );
189+ final String parameterName = toolParam .name ();
190+ final String parameterType = parameter .getType ().getName ().toLowerCase ();
176191
177192 Map <String , String > parameterProperties = Map .of (
178193 "type" , parameterType ,
0 commit comments