55package io .modelcontextprotocol .server ;
66
77import java .time .Duration ;
8+ import java .util .ArrayList ;
89import java .util .HashMap ;
910import java .util .List ;
1011import java .util .Map ;
2223import io .modelcontextprotocol .spec .McpSchema .CallToolResult ;
2324import io .modelcontextprotocol .spec .McpSchema .LoggingLevel ;
2425import io .modelcontextprotocol .spec .McpSchema .LoggingMessageNotification ;
26+ import io .modelcontextprotocol .spec .McpSchema .ResourceTemplate ;
2527import io .modelcontextprotocol .spec .McpSchema .SetLevelRequest ;
2628import io .modelcontextprotocol .spec .McpSchema .Tool ;
2729import io .modelcontextprotocol .spec .McpServerSession ;
2830import io .modelcontextprotocol .spec .McpServerTransportProvider ;
31+ import io .modelcontextprotocol .util .DeafaultMcpUriTemplateManagerFactory ;
32+ import io .modelcontextprotocol .util .McpUriTemplateManagerFactory ;
2933import io .modelcontextprotocol .util .Utils ;
3034import org .slf4j .Logger ;
3135import org .slf4j .LoggerFactory ;
@@ -92,8 +96,10 @@ public class McpAsyncServer {
9296 * @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
9397 */
9498 McpAsyncServer (McpServerTransportProvider mcpTransportProvider , ObjectMapper objectMapper ,
95- McpServerFeatures .Async features , Duration requestTimeout ) {
96- this .delegate = new AsyncServerImpl (mcpTransportProvider , objectMapper , requestTimeout , features );
99+ McpServerFeatures .Async features , Duration requestTimeout ,
100+ McpUriTemplateManagerFactory uriTemplateManagerFactory ) {
101+ this .delegate = new AsyncServerImpl (mcpTransportProvider , objectMapper , requestTimeout , features ,
102+ uriTemplateManagerFactory );
97103 }
98104
99105 /**
@@ -274,8 +280,11 @@ private static class AsyncServerImpl extends McpAsyncServer {
274280
275281 private List <String > protocolVersions = List .of (McpSchema .LATEST_PROTOCOL_VERSION );
276282
283+ private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory ();
284+
277285 AsyncServerImpl (McpServerTransportProvider mcpTransportProvider , ObjectMapper objectMapper ,
278- Duration requestTimeout , McpServerFeatures .Async features ) {
286+ Duration requestTimeout , McpServerFeatures .Async features ,
287+ McpUriTemplateManagerFactory uriTemplateManagerFactory ) {
279288 this .mcpTransportProvider = mcpTransportProvider ;
280289 this .objectMapper = objectMapper ;
281290 this .serverInfo = features .serverInfo ();
@@ -286,6 +295,7 @@ private static class AsyncServerImpl extends McpAsyncServer {
286295 this .resourceTemplates .addAll (features .resourceTemplates ());
287296 this .prompts .putAll (features .prompts ());
288297 this .completions .putAll (features .completions ());
298+ this .uriTemplateManagerFactory = uriTemplateManagerFactory ;
289299
290300 Map <String , McpServerSession .RequestHandler <?>> requestHandlers = new HashMap <>();
291301
@@ -564,8 +574,26 @@ private McpServerSession.RequestHandler<McpSchema.ListResourcesResult> resources
564574
565575 private McpServerSession .RequestHandler <McpSchema .ListResourceTemplatesResult > resourceTemplateListRequestHandler () {
566576 return (exchange , params ) -> Mono
567- .just (new McpSchema .ListResourceTemplatesResult (this .resourceTemplates , null ));
577+ .just (new McpSchema .ListResourceTemplatesResult (this .getResourceTemplates (), null ));
578+
579+ }
568580
581+ private List <McpSchema .ResourceTemplate > getResourceTemplates () {
582+ var list = new ArrayList <>(this .resourceTemplates );
583+ List <ResourceTemplate > resourceTemplates = this .resources .keySet ()
584+ .stream ()
585+ .filter (uri -> uri .contains ("{" ))
586+ .map (uri -> {
587+ var resource = this .resources .get (uri ).resource ();
588+ var template = new McpSchema .ResourceTemplate (resource .uri (), resource .name (),
589+ resource .description (), resource .mimeType (), resource .annotations ());
590+ return template ;
591+ })
592+ .toList ();
593+
594+ list .addAll (resourceTemplates );
595+
596+ return list ;
569597 }
570598
571599 private McpServerSession .RequestHandler <McpSchema .ReadResourceResult > resourcesReadRequestHandler () {
@@ -574,11 +602,16 @@ private McpServerSession.RequestHandler<McpSchema.ReadResourceResult> resourcesR
574602 new TypeReference <McpSchema .ReadResourceRequest >() {
575603 });
576604 var resourceUri = resourceRequest .uri ();
577- McpServerFeatures .AsyncResourceSpecification specification = this .resources .get (resourceUri );
578- if (specification != null ) {
579- return specification .readHandler ().apply (exchange , resourceRequest );
580- }
581- return Mono .error (new McpError ("Resource not found: " + resourceUri ));
605+
606+ McpServerFeatures .AsyncResourceSpecification specification = this .resources .values ()
607+ .stream ()
608+ .filter (resourceSpecification -> this .uriTemplateManagerFactory
609+ .create (resourceSpecification .resource ().uri ())
610+ .matches (resourceUri ))
611+ .findFirst ()
612+ .orElseThrow (() -> new McpError ("Resource not found: " + resourceUri ));
613+
614+ return specification .readHandler ().apply (exchange , resourceRequest );
582615 };
583616 }
584617
@@ -729,20 +762,38 @@ private McpServerSession.RequestHandler<McpSchema.CompleteResult> completionComp
729762
730763 String type = request .ref ().type ();
731764
765+ String argumentName = request .argument ().name ();
766+
732767 // check if the referenced resource exists
733768 if (type .equals ("ref/prompt" ) && request .ref () instanceof McpSchema .PromptReference promptReference ) {
734- McpServerFeatures .AsyncPromptSpecification prompt = this .prompts .get (promptReference .name ());
735- if (prompt == null ) {
769+ McpServerFeatures .AsyncPromptSpecification promptSpec = this .prompts .get (promptReference .name ());
770+ if (promptSpec == null ) {
736771 return Mono .error (new McpError ("Prompt not found: " + promptReference .name ()));
737772 }
773+ if (!promptSpec .prompt ()
774+ .arguments ()
775+ .stream ()
776+ .filter (arg -> arg .name ().equals (argumentName ))
777+ .findFirst ()
778+ .isPresent ()) {
779+
780+ return Mono .error (new McpError ("Argument not found: " + argumentName ));
781+ }
738782 }
739783
740784 if (type .equals ("ref/resource" )
741785 && request .ref () instanceof McpSchema .ResourceReference resourceReference ) {
742- McpServerFeatures .AsyncResourceSpecification resource = this .resources .get (resourceReference .uri ());
743- if (resource == null ) {
786+ McpServerFeatures .AsyncResourceSpecification resourceSpec = this .resources
787+ .get (resourceReference .uri ());
788+ if (resourceSpec == null ) {
744789 return Mono .error (new McpError ("Resource not found: " + resourceReference .uri ()));
745790 }
791+ if (!uriTemplateManagerFactory .create (resourceSpec .resource ().uri ())
792+ .getVariableNames ()
793+ .contains (argumentName )) {
794+ return Mono .error (new McpError ("Argument not found: " + argumentName ));
795+ }
796+
746797 }
747798
748799 McpServerFeatures .AsyncCompletionSpecification specification = this .completions .get (request .ref ());
0 commit comments