21
21
* MCP server features specification that a particular server can choose to support.
22
22
*
23
23
* @author Dariusz Jędrzejczyk
24
+ * @author Jihoon Kim
24
25
*/
25
26
public class McpServerFeatures {
26
27
@@ -41,6 +42,7 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s
41
42
List <McpServerFeatures .AsyncToolSpecification > tools , Map <String , AsyncResourceSpecification > resources ,
42
43
List <McpSchema .ResourceTemplate > resourceTemplates ,
43
44
Map <String , McpServerFeatures .AsyncPromptSpecification > prompts ,
45
+ Map <CompletionRefKey , McpServerFeatures .AsyncCompletionSpecification > completions ,
44
46
List <BiFunction <McpAsyncServerExchange , List <McpSchema .Root >, Mono <Void >>> rootsChangeConsumers ,
45
47
String instructions ) {
46
48
@@ -60,14 +62,16 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s
60
62
List <McpServerFeatures .AsyncToolSpecification > tools , Map <String , AsyncResourceSpecification > resources ,
61
63
List <McpSchema .ResourceTemplate > resourceTemplates ,
62
64
Map <String , McpServerFeatures .AsyncPromptSpecification > prompts ,
65
+ Map <CompletionRefKey , McpServerFeatures .AsyncCompletionSpecification > completions ,
63
66
List <BiFunction <McpAsyncServerExchange , List <McpSchema .Root >, Mono <Void >>> rootsChangeConsumers ,
64
67
String instructions ) {
65
68
66
69
Assert .notNull (serverInfo , "Server info must not be null" );
67
70
68
71
this .serverInfo = serverInfo ;
69
72
this .serverCapabilities = (serverCapabilities != null ) ? serverCapabilities
70
- : new McpSchema .ServerCapabilities (null , // experimental
73
+ : new McpSchema .ServerCapabilities (null , // completions
74
+ null , // experimental
71
75
new McpSchema .ServerCapabilities .LoggingCapabilities (), // Enable
72
76
// logging
73
77
// by
@@ -81,6 +85,7 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s
81
85
this .resources = (resources != null ) ? resources : Map .of ();
82
86
this .resourceTemplates = (resourceTemplates != null ) ? resourceTemplates : List .of ();
83
87
this .prompts = (prompts != null ) ? prompts : Map .of ();
88
+ this .completions = (completions != null ) ? completions : Map .of ();
84
89
this .rootsChangeConsumers = (rootsChangeConsumers != null ) ? rootsChangeConsumers : List .of ();
85
90
this .instructions = instructions ;
86
91
}
@@ -109,6 +114,11 @@ static Async fromSync(Sync syncSpec) {
109
114
prompts .put (key , AsyncPromptSpecification .fromSync (prompt ));
110
115
});
111
116
117
+ Map <CompletionRefKey , McpServerFeatures .AsyncCompletionSpecification > completions = new HashMap <>();
118
+ syncSpec .completions ().forEach ((key , completion ) -> {
119
+ completions .put (key , AsyncCompletionSpecification .fromSync (completion ));
120
+ });
121
+
112
122
List <BiFunction <McpAsyncServerExchange , List <McpSchema .Root >, Mono <Void >>> rootChangeConsumers = new ArrayList <>();
113
123
114
124
for (var rootChangeConsumer : syncSpec .rootsChangeConsumers ()) {
@@ -118,7 +128,7 @@ static Async fromSync(Sync syncSpec) {
118
128
}
119
129
120
130
return new Async (syncSpec .serverInfo (), syncSpec .serverCapabilities (), tools , resources ,
121
- syncSpec .resourceTemplates (), prompts , rootChangeConsumers , syncSpec .instructions ());
131
+ syncSpec .resourceTemplates (), prompts , completions , rootChangeConsumers , syncSpec .instructions ());
122
132
}
123
133
}
124
134
@@ -140,6 +150,7 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se
140
150
Map <String , McpServerFeatures .SyncResourceSpecification > resources ,
141
151
List <McpSchema .ResourceTemplate > resourceTemplates ,
142
152
Map <String , McpServerFeatures .SyncPromptSpecification > prompts ,
153
+ Map <CompletionRefKey , McpServerFeatures .SyncCompletionSpecification > completions ,
143
154
List <BiConsumer <McpSyncServerExchange , List <McpSchema .Root >>> rootsChangeConsumers , String instructions ) {
144
155
145
156
/**
@@ -159,14 +170,16 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se
159
170
Map <String , McpServerFeatures .SyncResourceSpecification > resources ,
160
171
List <McpSchema .ResourceTemplate > resourceTemplates ,
161
172
Map <String , McpServerFeatures .SyncPromptSpecification > prompts ,
173
+ Map <CompletionRefKey , McpServerFeatures .SyncCompletionSpecification > completions ,
162
174
List <BiConsumer <McpSyncServerExchange , List <McpSchema .Root >>> rootsChangeConsumers ,
163
175
String instructions ) {
164
176
165
177
Assert .notNull (serverInfo , "Server info must not be null" );
166
178
167
179
this .serverInfo = serverInfo ;
168
180
this .serverCapabilities = (serverCapabilities != null ) ? serverCapabilities
169
- : new McpSchema .ServerCapabilities (null , // experimental
181
+ : new McpSchema .ServerCapabilities (null , // completions
182
+ null , // experimental
170
183
new McpSchema .ServerCapabilities .LoggingCapabilities (), // Enable
171
184
// logging
172
185
// by
@@ -180,6 +193,7 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se
180
193
this .resources = (resources != null ) ? resources : new HashMap <>();
181
194
this .resourceTemplates = (resourceTemplates != null ) ? resourceTemplates : new ArrayList <>();
182
195
this .prompts = (prompts != null ) ? prompts : new HashMap <>();
196
+ this .completions = (completions != null ) ? completions : new HashMap <>();
183
197
this .rootsChangeConsumers = (rootsChangeConsumers != null ) ? rootsChangeConsumers : new ArrayList <>();
184
198
this .instructions = instructions ;
185
199
}
@@ -325,6 +339,19 @@ static AsyncPromptSpecification fromSync(SyncPromptSpecification prompt) {
325
339
}
326
340
}
327
341
342
+ public record AsyncCompletionSpecification (
343
+ BiFunction <McpAsyncServerExchange , McpSchema .CompleteRequest , Mono <McpSchema .CompleteResult >> completionHandler ) {
344
+
345
+ static AsyncCompletionSpecification fromSync (SyncCompletionSpecification completion ) {
346
+ if (completion == null ) {
347
+ return null ;
348
+ }
349
+ return new AsyncCompletionSpecification ((exchange , request ) -> Mono
350
+ .fromCallable (() -> completion .completionHandler ().apply (new McpSyncServerExchange (exchange ), request ))
351
+ .subscribeOn (Schedulers .boundedElastic ()));
352
+ }
353
+ }
354
+
328
355
/**
329
356
* Specification of a tool with its synchronous handler function. Tools are the
330
357
* primary way for MCP servers to expose functionality to AI models. Each tool
@@ -431,4 +458,23 @@ public record SyncPromptSpecification(McpSchema.Prompt prompt,
431
458
BiFunction <McpSyncServerExchange , McpSchema .GetPromptRequest , McpSchema .GetPromptResult > promptHandler ) {
432
459
}
433
460
461
+ public record SyncCompletionSpecification (CompletionRefKey referenceKey ,
462
+ BiFunction <McpSyncServerExchange , McpSchema .CompleteRequest , McpSchema .CompleteResult > completionHandler ) {
463
+ }
464
+
465
+ public record CompletionRefKey (String type , String identifier ) {
466
+ public static CompletionRefKey from (McpSchema .CompleteRequest request ) {
467
+ var ref = request .ref ();
468
+ if (ref instanceof McpSchema .CompleteRequest .PromptReference pr ) {
469
+ return new CompletionRefKey (ref .type (), pr .name ());
470
+ }
471
+ else if (ref instanceof McpSchema .CompleteRequest .ResourceReference rr ) {
472
+ return new CompletionRefKey (ref .type (), rr .uri ());
473
+ }
474
+ else {
475
+ throw new IllegalArgumentException ("Unsupported reference type: " + ref );
476
+ }
477
+ }
478
+ }
479
+
434
480
}
0 commit comments