5
5
package io .modelcontextprotocol .server ;
6
6
7
7
import java .time .Duration ;
8
+ import java .util .ArrayList ;
8
9
import java .util .HashMap ;
9
10
import java .util .List ;
10
11
import java .util .Map ;
22
23
import io .modelcontextprotocol .spec .McpSchema .CallToolResult ;
23
24
import io .modelcontextprotocol .spec .McpSchema .LoggingLevel ;
24
25
import io .modelcontextprotocol .spec .McpSchema .LoggingMessageNotification ;
26
+ import io .modelcontextprotocol .spec .McpSchema .ResourceTemplate ;
25
27
import io .modelcontextprotocol .spec .McpSchema .SetLevelRequest ;
26
28
import io .modelcontextprotocol .spec .McpSchema .Tool ;
27
29
import io .modelcontextprotocol .spec .McpServerSession ;
28
30
import io .modelcontextprotocol .spec .McpServerTransportProvider ;
31
+ import io .modelcontextprotocol .util .DeafaultMcpUriTemplateManagerFactory ;
32
+ import io .modelcontextprotocol .util .McpUriTemplateManagerFactory ;
29
33
import io .modelcontextprotocol .util .Utils ;
30
34
import org .slf4j .Logger ;
31
35
import org .slf4j .LoggerFactory ;
@@ -92,8 +96,10 @@ public class McpAsyncServer {
92
96
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
93
97
*/
94
98
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 );
97
103
}
98
104
99
105
/**
@@ -274,8 +280,11 @@ private static class AsyncServerImpl extends McpAsyncServer {
274
280
275
281
private List <String > protocolVersions = List .of (McpSchema .LATEST_PROTOCOL_VERSION );
276
282
283
+ private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory ();
284
+
277
285
AsyncServerImpl (McpServerTransportProvider mcpTransportProvider , ObjectMapper objectMapper ,
278
- Duration requestTimeout , McpServerFeatures .Async features ) {
286
+ Duration requestTimeout , McpServerFeatures .Async features ,
287
+ McpUriTemplateManagerFactory uriTemplateManagerFactory ) {
279
288
this .mcpTransportProvider = mcpTransportProvider ;
280
289
this .objectMapper = objectMapper ;
281
290
this .serverInfo = features .serverInfo ();
@@ -286,6 +295,7 @@ private static class AsyncServerImpl extends McpAsyncServer {
286
295
this .resourceTemplates .addAll (features .resourceTemplates ());
287
296
this .prompts .putAll (features .prompts ());
288
297
this .completions .putAll (features .completions ());
298
+ this .uriTemplateManagerFactory = uriTemplateManagerFactory ;
289
299
290
300
Map <String , McpServerSession .RequestHandler <?>> requestHandlers = new HashMap <>();
291
301
@@ -564,8 +574,26 @@ private McpServerSession.RequestHandler<McpSchema.ListResourcesResult> resources
564
574
565
575
private McpServerSession .RequestHandler <McpSchema .ListResourceTemplatesResult > resourceTemplateListRequestHandler () {
566
576
return (exchange , params ) -> Mono
567
- .just (new McpSchema .ListResourceTemplatesResult (this .resourceTemplates , null ));
577
+ .just (new McpSchema .ListResourceTemplatesResult (this .getResourceTemplates (), null ));
578
+
579
+ }
568
580
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 ;
569
597
}
570
598
571
599
private McpServerSession .RequestHandler <McpSchema .ReadResourceResult > resourcesReadRequestHandler () {
@@ -574,11 +602,16 @@ private McpServerSession.RequestHandler<McpSchema.ReadResourceResult> resourcesR
574
602
new TypeReference <McpSchema .ReadResourceRequest >() {
575
603
});
576
604
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 );
582
615
};
583
616
}
584
617
@@ -729,20 +762,38 @@ private McpServerSession.RequestHandler<McpSchema.CompleteResult> completionComp
729
762
730
763
String type = request .ref ().type ();
731
764
765
+ String argumentName = request .argument ().name ();
766
+
732
767
// check if the referenced resource exists
733
768
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 ) {
736
771
return Mono .error (new McpError ("Prompt not found: " + promptReference .name ()));
737
772
}
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
+ }
738
782
}
739
783
740
784
if (type .equals ("ref/resource" )
741
785
&& 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 ) {
744
789
return Mono .error (new McpError ("Resource not found: " + resourceReference .uri ()));
745
790
}
791
+ if (!uriTemplateManagerFactory .create (resourceSpec .resource ().uri ())
792
+ .getVariableNames ()
793
+ .contains (argumentName )) {
794
+ return Mono .error (new McpError ("Argument not found: " + argumentName ));
795
+ }
796
+
746
797
}
747
798
748
799
McpServerFeatures .AsyncCompletionSpecification specification = this .completions .get (request .ref ());
0 commit comments