feat(completion): implement completion API support (#141)

Add completion API support to the MCP protocol implementation:

- Add CompleteRequest and CompleteResult schema classes
- Implement completion capabilities in ServerCapabilities
- Add completion handlers in McpAsyncServer and McpServer
- Add completion client methods in McpAsyncClient and McpSyncClient
- Add CompletionRefKey and completion specifications in McpServerFeatures
- Add integration test for completion functionality
- Fix isPresent() check to use isEmpty() in WebMvcSseServerTransportProvider
- Replace McpServerFeatures.CompletionRefKey by McpSchemaCompleteReference

Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>

Signed-off-by: jitokim <pigberger70@gmail.com>
This commit is contained in:
jitokim 2025-04-11 13:36:37 +09:00 • committed by Christian Tzolov
commit 7853efefda
9 changed files with 340 additions and 33 deletions

View file

@ -10,6 +10,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -20,19 +21,12 @@ import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.server.TestUtil;
import io.modelcontextprotocol.server.McpSyncServerExchange;
import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;
import io.modelcontextprotocol.spec.McpSchema.InitializeResult;
import io.modelcontextprotocol.spec.McpSchema.ModelPreferences;
import io.modelcontextprotocol.spec.McpSchema.Role;
import io.modelcontextprotocol.spec.McpSchema.Root;
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
import io.modelcontextprotocol.spec.McpSchema.Tool;
import io.modelcontextprotocol.spec.McpSchema.*;
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities.CompletionCapabilities;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
@ -759,4 +753,53 @@ class WebFluxSseIntegrationTests {
mcpServer.close();
}
}
// ---------------------------------------
// Completion Tests
// ---------------------------------------
@ParameterizedTest(name = "{0} : Completion call")
@ValueSource(strings = { "httpclient", "webflux" })
void testCompletionShouldReturnExpectedSuggestions(String clientType) {
var clientBuilder = clientBuilders.get(clientType);
var expectedValues = List.of("python", "pytorch", "pyside");
var completionResponse = new McpSchema.CompleteResult(new CompleteResult.CompleteCompletion(expectedValues, 10, // total
true // hasMore
));
AtomicReference<CompleteRequest> samplingRequest = new AtomicReference<>();
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> completionHandler = (mcpSyncServerExchange,
request) -> {
samplingRequest.set(request);
return completionResponse;
};
var mcpServer = McpServer.sync(mcpServerTransportProvider)
.capabilities(ServerCapabilities.builder().completions(new CompletionCapabilities()).build())
.prompts(new McpServerFeatures.SyncPromptSpecification(
new Prompt("code_review", "this is code review prompt", List.of()),
(mcpSyncServerExchange, getPromptRequest) -> null))
.completions(new McpServerFeatures.SyncCompletionSpecification(
new McpSchema.PromptReference("ref/prompt", "code_review"), completionHandler))
.build();
try (var mcpClient = clientBuilder.build()) {
InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull();
CompleteRequest request = new CompleteRequest(new PromptReference("ref/prompt", "code_review"),
new CompleteRequest.CompleteArgument("language", "py"));
CompleteResult result = mcpClient.completeCompletion(request);
assertThat(result).isNotNull();
assertThat(samplingRequest.get().argument().name()).isEqualTo("language");
assertThat(samplingRequest.get().argument().value()).isEqualTo("py");
assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt");
}
mcpServer.close();
}
}

View file

@ -300,7 +300,7 @@ public class WebMvcSseServerTransportProvider implements McpServerTransportProvi
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).body("Server is shutting down");
}
if (!request.param("sessionId").isPresent()) {
if (request.param("sessionId").isEmpty()) {
return ServerResponse.badRequest().body(new McpError("Session ID missing in message endpoint"));
}

View file

@ -71,6 +71,7 @@ import reactor.core.publisher.Sinks;
*
* @author Dariusz Jędrzejczyk
* @author Christian Tzolov
* @author Jihoon Kim
* @see McpClient
* @see McpSchema
* @see McpClientSession
@ -816,4 +817,25 @@ public class McpAsyncClient {
this.protocolVersions = protocolVersions;
}
// --------------------------
// Completions
// --------------------------
private static final TypeReference<McpSchema.CompleteResult> COMPLETION_COMPLETE_RESULT_TYPE_REF = new TypeReference<>() {
};
/**
* Sends a completion/complete request to generate value suggestions based on a given
* reference and argument. This is typically used to provide auto-completion options
* for user input fields.
* @param completeRequest The request containing the prompt or resource reference and
* argument for which to generate completions.
* @return A Mono that completes with the result containing completion suggestions.
* @see McpSchema.CompleteRequest
* @see McpSchema.CompleteResult
*/
public Mono<McpSchema.CompleteResult> completeCompletion(McpSchema.CompleteRequest completeRequest) {
return this.withInitializationCheck("complete completions", initializedResult -> this.mcpSession
.sendRequest(McpSchema.METHOD_COMPLETION_COMPLETE, completeRequest, COMPLETION_COMPLETE_RESULT_TYPE_REF));
}
}

View file

@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory;
*
* @author Dariusz Jędrzejczyk
* @author Christian Tzolov
* @author Jihoon Kim
* @see McpClient
* @see McpAsyncClient
* @see McpSchema
@ -334,4 +335,14 @@ public class McpSyncClient implements AutoCloseable {
this.delegate.setLoggingLevel(loggingLevel).block();
}
/**
* Send a completion/complete request.
* @param completeRequest the completion request contains the prompt or resource
* reference and arguments for generating suggestions.
* @return the completion result containing suggested values.
*/
public McpSchema.CompleteResult completeCompletion(McpSchema.CompleteRequest completeRequest) {
return this.delegate.completeCompletion(completeRequest).block();
}
}

View file

@ -69,6 +69,7 @@ import reactor.core.publisher.Mono;
*
* @author Christian Tzolov
* @author Dariusz Jędrzejczyk
* @author Jihoon Kim
* @see McpServer
* @see McpSchema
* @see McpClientSession
@ -269,6 +270,8 @@ public class McpAsyncServer {
// broadcasting loggingNotification.
private LoggingLevel minLoggingLevel = LoggingLevel.DEBUG;
private final ConcurrentHashMap<McpSchema.CompleteReference, McpServerFeatures.AsyncCompletionSpecification> completions = new ConcurrentHashMap<>();
private List<String> protocolVersions = List.of(McpSchema.LATEST_PROTOCOL_VERSION);
AsyncServerImpl(McpServerTransportProvider mcpTransportProvider, ObjectMapper objectMapper,
@ -282,6 +285,7 @@ public class McpAsyncServer {
this.resources.putAll(features.resources());
this.resourceTemplates.addAll(features.resourceTemplates());
this.prompts.putAll(features.prompts());
this.completions.putAll(features.completions());
Map<String, McpServerSession.RequestHandler<?>> requestHandlers = new HashMap<>();
@ -314,6 +318,11 @@ public class McpAsyncServer {
requestHandlers.put(McpSchema.METHOD_LOGGING_SET_LEVEL, setLoggerRequestHandler());
}
// Add completion API handlers if the completion capability is enabled
if (this.serverCapabilities.completions() != null) {
requestHandlers.put(McpSchema.METHOD_COMPLETION_COMPLETE, completionCompleteRequestHandler());
}
Map<String, McpServerSession.NotificationHandler> notificationHandlers = new HashMap<>();
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_INITIALIZED, (exchange, params) -> Mono.empty());
@ -706,6 +715,81 @@ public class McpAsyncServer {
};
}
private McpServerSession.RequestHandler<McpSchema.CompleteResult> completionCompleteRequestHandler() {
return (exchange, params) -> {
McpSchema.CompleteRequest request = parseCompletionParams(params);
if (request.ref() == null) {
return Mono.error(new McpError("ref must not be null"));
}
if (request.ref().type() == null) {
return Mono.error(new McpError("type must not be null"));
}
String type = request.ref().type();
// check if the referenced resource exists
if (type.equals("ref/prompt") && request.ref() instanceof McpSchema.PromptReference promptReference) {
McpServerFeatures.AsyncPromptSpecification prompt = this.prompts.get(promptReference.name());
if (prompt == null) {
return Mono.error(new McpError("Prompt not found: " + promptReference.name()));
}
}
if (type.equals("ref/resource")
&& request.ref() instanceof McpSchema.ResourceReference resourceReference) {
McpServerFeatures.AsyncResourceSpecification resource = this.resources.get(resourceReference.uri());
if (resource == null) {
return Mono.error(new McpError("Resource not found: " + resourceReference.uri()));
}
}
McpServerFeatures.AsyncCompletionSpecification specification = this.completions.get(request.ref());
if (specification == null) {
return Mono.error(new McpError("AsyncCompletionSpecification not found: " + request.ref()));
}
return specification.completionHandler().apply(exchange, request);
};
}
/**
* Parses the raw JSON-RPC request parameters into a
* {@link McpSchema.CompleteRequest} object.
* <p>
* This method manually extracts the `ref` and `argument` fields from the input
* map, determines the correct reference type (either prompt or resource), and
* constructs a fully-typed {@code CompleteRequest} instance.
* @param object the raw request parameters, expected to be a Map containing "ref"
* and "argument" entries.
* @return a {@link McpSchema.CompleteRequest} representing the structured
* completion request.
* @throws IllegalArgumentException if the "ref" type is not recognized.
*/
@SuppressWarnings("unchecked")
private McpSchema.CompleteRequest parseCompletionParams(Object object) {
Map<String, Object> params = (Map<String, Object>) object;
Map<String, Object> refMap = (Map<String, Object>) params.get("ref");
Map<String, Object> argMap = (Map<String, Object>) params.get("argument");
String refType = (String) refMap.get("type");
McpSchema.CompleteReference ref = switch (refType) {
case "ref/prompt" -> new McpSchema.PromptReference(refType, (String) refMap.get("name"));
case "ref/resource" -> new McpSchema.ResourceReference(refType, (String) refMap.get("uri"));
default -> throw new IllegalArgumentException("Invalid ref type: " + refType);
};
String argName = (String) argMap.get("name");
String argValue = (String) argMap.get("value");
McpSchema.CompleteRequest.CompleteArgument argument = new McpSchema.CompleteRequest.CompleteArgument(
argName, argValue);
return new McpSchema.CompleteRequest(ref, argument);
}
// ---------------------------------------
// Sampling
// ---------------------------------------

View file

@ -115,6 +115,7 @@ import reactor.core.publisher.Mono;
*
* @author Christian Tzolov
* @author Dariusz Jędrzejczyk
* @author Jihoon Kim
* @see McpAsyncServer
* @see McpSyncServer
* @see McpServerTransportProvider
@ -192,6 +193,8 @@ public interface McpServer {
*/
private final Map<String, McpServerFeatures.AsyncPromptSpecification> prompts = new HashMap<>();
private final Map<McpSchema.CompleteReference, McpServerFeatures.AsyncCompletionSpecification> completions = new HashMap<>();
private final List<BiFunction<McpAsyncServerExchange, List<McpSchema.Root>, Mono<Void>>> rootsChangeHandlers = new ArrayList<>();
private Duration requestTimeout = Duration.ofSeconds(10); // Default timeout
@ -581,7 +584,8 @@ public interface McpServer {
*/
public McpAsyncServer build() {
var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools,
this.resources, this.resourceTemplates, this.prompts, this.rootsChangeHandlers, this.instructions);
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
this.instructions);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout);
}
@ -635,6 +639,8 @@ public interface McpServer {
*/
private final Map<String, McpServerFeatures.SyncPromptSpecification> prompts = new HashMap<>();
private final Map<McpSchema.CompleteReference, McpServerFeatures.SyncCompletionSpecification> completions = new HashMap<>();
private final List<BiConsumer<McpSyncServerExchange, List<McpSchema.Root>>> rootsChangeHandlers = new ArrayList<>();
private Duration requestTimeout = Duration.ofSeconds(10); // Default timeout
@ -957,6 +963,37 @@ public interface McpServer {
return this;
}
/**
* Registers multiple completions with their handlers using a List. This method is
* useful when completions need to be added in bulk from a collection.
* @param completions List of completion specifications. Must not be null.
* @return This builder instance for method chaining
* @throws IllegalArgumentException if completions is null
* @see #completions(McpServerFeatures.SyncCompletionSpecification...)
*/
public SyncSpecification completions(List<McpServerFeatures.SyncCompletionSpecification> completions) {
Assert.notNull(completions, "Completions list must not be null");
for (McpServerFeatures.SyncCompletionSpecification completion : completions) {
this.completions.put(completion.referenceKey(), completion);
}
return this;
}
/**
* Registers multiple completions with their handlers using varargs. This method
* is useful when completions are defined inline and added directly.
* @param completions Array of completion specifications. Must not be null.
* @return This builder instance for method chaining
* @throws IllegalArgumentException if completions is null
*/
public SyncSpecification completions(McpServerFeatures.SyncCompletionSpecification... completions) {
Assert.notNull(completions, "Completions list must not be null");
for (McpServerFeatures.SyncCompletionSpecification completion : completions) {
this.completions.put(completion.referenceKey(), completion);
}
return this;
}
/**
* Registers a consumer that will be notified when the list of roots changes. This
* is useful for updating resource availability dynamically, such as when new
@ -1023,8 +1060,8 @@ public interface McpServer {
*/
public McpSyncServer build() {
McpServerFeatures.Sync syncFeatures = new McpServerFeatures.Sync(this.serverInfo, this.serverCapabilities,
this.tools, this.resources, this.resourceTemplates, this.prompts, this.rootsChangeHandlers,
this.instructions);
this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions,
this.rootsChangeHandlers, this.instructions);
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout);

View file

@ -21,6 +21,7 @@ import reactor.core.scheduler.Schedulers;
* MCP server features specification that a particular server can choose to support.
*
* @author Dariusz Jędrzejczyk
* @author Jihoon Kim
*/
public class McpServerFeatures {
@ -41,6 +42,7 @@ public class McpServerFeatures {
List<McpServerFeatures.AsyncToolSpecification> tools, Map<String, AsyncResourceSpecification> resources,
List<McpSchema.ResourceTemplate> resourceTemplates,
Map<String, McpServerFeatures.AsyncPromptSpecification> prompts,
Map<McpSchema.CompleteReference, McpServerFeatures.AsyncCompletionSpecification> completions,
List<BiFunction<McpAsyncServerExchange, List<McpSchema.Root>, Mono<Void>>> rootsChangeConsumers,
String instructions) {
@ -60,6 +62,7 @@ public class McpServerFeatures {
List<McpServerFeatures.AsyncToolSpecification> tools, Map<String, AsyncResourceSpecification> resources,
List<McpSchema.ResourceTemplate> resourceTemplates,
Map<String, McpServerFeatures.AsyncPromptSpecification> prompts,
Map<McpSchema.CompleteReference, McpServerFeatures.AsyncCompletionSpecification> completions,
List<BiFunction<McpAsyncServerExchange, List<McpSchema.Root>, Mono<Void>>> rootsChangeConsumers,
String instructions) {
@ -67,7 +70,8 @@ public class McpServerFeatures {
this.serverInfo = serverInfo;
this.serverCapabilities = (serverCapabilities != null) ? serverCapabilities
: new McpSchema.ServerCapabilities(null, // experimental
: new McpSchema.ServerCapabilities(null, // completions
null, // experimental
new McpSchema.ServerCapabilities.LoggingCapabilities(), // Enable
// logging
// by
@ -81,6 +85,7 @@ public class McpServerFeatures {
this.resources = (resources != null) ? resources : Map.of();
this.resourceTemplates = (resourceTemplates != null) ? resourceTemplates : List.of();
this.prompts = (prompts != null) ? prompts : Map.of();
this.completions = (completions != null) ? completions : Map.of();
this.rootsChangeConsumers = (rootsChangeConsumers != null) ? rootsChangeConsumers : List.of();
this.instructions = instructions;
}
@ -109,6 +114,11 @@ public class McpServerFeatures {
prompts.put(key, AsyncPromptSpecification.fromSync(prompt));
});
Map<McpSchema.CompleteReference, McpServerFeatures.AsyncCompletionSpecification> completions = new HashMap<>();
syncSpec.completions().forEach((key, completion) -> {
completions.put(key, AsyncCompletionSpecification.fromSync(completion));
});
List<BiFunction<McpAsyncServerExchange, List<McpSchema.Root>, Mono<Void>>> rootChangeConsumers = new ArrayList<>();
for (var rootChangeConsumer : syncSpec.rootsChangeConsumers()) {
@ -118,7 +128,7 @@ public class McpServerFeatures {
}
return new Async(syncSpec.serverInfo(), syncSpec.serverCapabilities(), tools, resources,
syncSpec.resourceTemplates(), prompts, rootChangeConsumers, syncSpec.instructions());
syncSpec.resourceTemplates(), prompts, completions, rootChangeConsumers, syncSpec.instructions());
}
}
@ -140,6 +150,7 @@ public class McpServerFeatures {
Map<String, McpServerFeatures.SyncResourceSpecification> resources,
List<McpSchema.ResourceTemplate> resourceTemplates,
Map<String, McpServerFeatures.SyncPromptSpecification> prompts,
Map<McpSchema.CompleteReference, McpServerFeatures.SyncCompletionSpecification> completions,
List<BiConsumer<McpSyncServerExchange, List<McpSchema.Root>>> rootsChangeConsumers, String instructions) {
/**
@ -159,6 +170,7 @@ public class McpServerFeatures {
Map<String, McpServerFeatures.SyncResourceSpecification> resources,
List<McpSchema.ResourceTemplate> resourceTemplates,
Map<String, McpServerFeatures.SyncPromptSpecification> prompts,
Map<McpSchema.CompleteReference, McpServerFeatures.SyncCompletionSpecification> completions,
List<BiConsumer<McpSyncServerExchange, List<McpSchema.Root>>> rootsChangeConsumers,
String instructions) {
@ -166,7 +178,8 @@ public class McpServerFeatures {
this.serverInfo = serverInfo;
this.serverCapabilities = (serverCapabilities != null) ? serverCapabilities
: new McpSchema.ServerCapabilities(null, // experimental
: new McpSchema.ServerCapabilities(null, // completions
null, // experimental
new McpSchema.ServerCapabilities.LoggingCapabilities(), // Enable
// logging
// by
@ -180,6 +193,7 @@ public class McpServerFeatures {
this.resources = (resources != null) ? resources : new HashMap<>();
this.resourceTemplates = (resourceTemplates != null) ? resourceTemplates : new ArrayList<>();
this.prompts = (prompts != null) ? prompts : new HashMap<>();
this.completions = (completions != null) ? completions : new HashMap<>();
this.rootsChangeConsumers = (rootsChangeConsumers != null) ? rootsChangeConsumers : new ArrayList<>();
this.instructions = instructions;
}
@ -325,6 +339,44 @@ public class McpServerFeatures {
}
}
/**
* Specification of a completion handler function with asynchronous execution support.
* Completions generate AI model outputs based on prompt or resource references and
* user-provided arguments. This abstraction enables:
* <ul>
* <li>Customizable response generation logic
* <li>Parameter-driven template expansion
* <li>Dynamic interaction with connected clients
* </ul>
*
* @param referenceKey The unique key representing the completion reference.
* @param completionHandler The asynchronous function that processes completion
* requests and returns results. The first argument is an
* {@link McpAsyncServerExchange} used to interact with the client. The second
* argument is a {@link io.modelcontextprotocol.spec.McpSchema.CompleteRequest}.
*/
public record AsyncCompletionSpecification(McpSchema.CompleteReference referenceKey,
BiFunction<McpAsyncServerExchange, McpSchema.CompleteRequest, Mono<McpSchema.CompleteResult>> completionHandler) {
/**
* Converts a synchronous {@link SyncCompletionSpecification} into an
* {@link AsyncCompletionSpecification} by wrapping the handler in a bounded
* elastic scheduler for safe non-blocking execution.
* @param completion the synchronous completion specification
* @return an asynchronous wrapper of the provided sync specification, or
* {@code null} if input is null
*/
static AsyncCompletionSpecification fromSync(SyncCompletionSpecification completion) {
if (completion == null) {
return null;
}
return new AsyncCompletionSpecification(completion.referenceKey(),
(exchange, request) -> Mono.fromCallable(
() -> completion.completionHandler().apply(new McpSyncServerExchange(exchange), request))
.subscribeOn(Schedulers.boundedElastic()));
}
}
/**
* Specification of a tool with its synchronous handler function. Tools are the
* primary way for MCP servers to expose functionality to AI models. Each tool
@ -431,4 +483,17 @@ public class McpServerFeatures {
BiFunction<McpSyncServerExchange, McpSchema.GetPromptRequest, McpSchema.GetPromptResult> promptHandler) {
}
/**
* Specification of a completion handler function with synchronous execution support.
*
* @param referenceKey The unique key representing the completion reference.
* @param completionHandler The synchronous function that processes completion
* requests and returns results. The first argument is an
* {@link McpSyncServerExchange} used to interact with the client. The second argument
* is a {@link io.modelcontextprotocol.spec.McpSchema.CompleteRequest}.
*/
public record SyncCompletionSpecification(McpSchema.CompleteReference referenceKey,
BiFunction<McpSyncServerExchange, McpSchema.CompleteRequest, McpSchema.CompleteResult> completionHandler) {
}
}

View file

@ -238,6 +238,7 @@ public class McpClientSession implements McpSession {
});
}).timeout(this.requestTimeout).handle((jsonRpcResponse, sink) -> {
if (jsonRpcResponse.error() != null) {
logger.error("Error handling request: {}", jsonRpcResponse.error());
sink.error(new McpError(jsonRpcResponse.error()));
}
else {

View file

@ -79,6 +79,8 @@ public final class McpSchema {
public static final String METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED = "notifications/prompts/list_changed";
public static final String METHOD_COMPLETION_COMPLETE = "completion/complete";
// Logging Methods
public static final String METHOD_LOGGING_SET_LEVEL = "logging/setLevel";
@ -314,12 +316,16 @@ public final class McpSchema {
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ServerCapabilities( // @formatter:off
@JsonProperty("completions") CompletionCapabilities completions,
@JsonProperty("experimental") Map<String, Object> experimental,
@JsonProperty("logging") LoggingCapabilities logging,
@JsonProperty("prompts") PromptCapabilities prompts,
@JsonProperty("resources") ResourceCapabilities resources,
@JsonProperty("tools") ToolCapabilities tools) {
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record CompletionCapabilities() {
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record LoggingCapabilities() {
@ -347,12 +353,18 @@ public final class McpSchema {
public static class Builder {
private CompletionCapabilities completions;
private Map<String, Object> experimental;
private LoggingCapabilities logging = new LoggingCapabilities();
private PromptCapabilities prompts;
private ResourceCapabilities resources;
private ToolCapabilities tools;
public Builder completions(CompletionCapabilities completions) {
this.completions = completions;
return this;
}
public Builder experimental(Map<String, Object> experimental) {
this.experimental = experimental;
return this;
@ -379,7 +391,7 @@ public final class McpSchema {
}
public ServerCapabilities build() {
return new ServerCapabilities(experimental, logging, prompts, resources, tools);
return new ServerCapabilities(completions, experimental, logging, prompts, resources, tools);
}
}
} // @formatter:on
@ -1173,31 +1185,63 @@ public final class McpSchema {
// ---------------------------
// Autocomplete
// ---------------------------
public record CompleteRequest(PromptOrResourceReference ref, CompleteArgument argument) implements Request {
public sealed interface PromptOrResourceReference permits PromptReference, ResourceReference {
public sealed interface CompleteReference permits PromptReference, ResourceReference {
String type();
String type();
String identifier();
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record PromptReference(// @formatter:off
@JsonProperty("type") String type,
@JsonProperty("name") String name) implements McpSchema.CompleteReference {
public PromptReference(String name) {
this("ref/prompt", name);
}
public record PromptReference(// @formatter:off
@JsonProperty("type") String type,
@JsonProperty("name") String name) implements PromptOrResourceReference {
}// @formatter:on
@Override
public String identifier() {
return name();
}
}// @formatter:on
public record ResourceReference(// @formatter:off
@JsonProperty("type") String type,
@JsonProperty("uri") String uri) implements PromptOrResourceReference {
}// @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ResourceReference(// @formatter:off
@JsonProperty("type") String type,
@JsonProperty("uri") String uri) implements McpSchema.CompleteReference {
public record CompleteArgument(// @formatter:off
public ResourceReference(String uri) {
this("ref/resource", uri);
}
@Override
public String identifier() {
return uri();
}
}// @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record CompleteRequest(// @formatter:off
@JsonProperty("ref") McpSchema.CompleteReference ref,
@JsonProperty("argument") CompleteArgument argument) implements Request {
public record CompleteArgument(
@JsonProperty("name") String name,
@JsonProperty("value") String value) {
}// @formatter:on
}
public record CompleteResult(CompleteCompletion completion) {
public record CompleteCompletion(// @formatter:off
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record CompleteResult(@JsonProperty("values") CompleteCompletion completion) { // @formatter:off
public record CompleteCompletion(
@JsonProperty("values") List<String> values,
@JsonProperty("total") Integer total,
@JsonProperty("hasMore") Boolean hasMore) {