diff --git a/MIGRATION-2.0.md b/MIGRATION-2.0.md index 273421189..261670768 100644 --- a/MIGRATION-2.0.md +++ b/MIGRATION-2.0.md @@ -77,6 +77,39 @@ The `Tool` record now models `inputSchema` (and `outputSchema`) as arbitrary JSO - Java code that used `Tool.inputSchema()` as a `JsonSchema` must switch to `Map` (or copy into your own schema wrapper). - `Tool.Builder.inputSchema(JsonSchema)` remains as a **deprecated** helper that maps the old record into a map; prefer `inputSchema(Map)` or `inputSchema(McpJsonMapper, String)`. +### Required MCP spec fields are enforced at construction time; builders require them upfront + +The following records assert that their required fields are non-null at construction time. Passing `null` throws `IllegalArgumentException` immediately, rather than producing a structurally invalid object that fails later during serialization or protocol handling. + +| Record | Required (non-null) fields | +|--------|---------------------------| +| `JSONRPCResponse.JSONRPCError` | `code`, `message` | +| `CallToolResult` | `content` | +| `SamplingMessage` | `role`, `content` | +| `CreateMessageRequest` | `messages`, `maxTokens` | +| `ElicitRequest` | `message`, `requestedSchema` | +| `ProgressNotification` | `progressToken`, `progress` | +| `LoggingMessageNotification` | `level`, `data` | + +**Action:** Audit any code that constructs these records with potentially-null values and provide valid, non-null arguments. + +#### Builder API changes + +The builder factory methods for several records now require the mandatory fields as arguments, making it impossible to obtain a builder that is already missing required state. The old no-arg `builder()` factory and the public no-arg `Builder()` constructor are deprecated and will be removed in a future release. + +| Type | Old (deprecated) | New | +|------|-----------------|-----| +| `CreateMessageRequest` | `CreateMessageRequest.builder().messages(m).maxTokens(n)` | `CreateMessageRequest.builder(m, n)` | +| `ElicitRequest` | `ElicitRequest.builder().message(m).requestedSchema(s)` | `ElicitRequest.builder(m, s)` | +| `LoggingMessageNotification` | `LoggingMessageNotification.builder().level(l).data(d)` | `LoggingMessageNotification.builder(l, d)` | + +Two records that previously had no builder now have one with the same required-first convention: + +- `ProgressNotification.builder(progressToken, progress)` — optional: `.total(Double)`, `.message(String)`, `.meta(Map)` +- `JSONRPCResponse.JSONRPCError.builder(code, message)` — optional: `.data(Object)` + +**Note:** `LoggingMessageNotification.level` must never be `null`. Because `LoggingLevel` deserialization is lenient (see the `LoggingLevel` section above), callers should ensure clients and servers send only recognized level strings. + ### Optional JSON Schema validation on `tools/call` (server) When a `JsonSchemaValidator` is available (including the default from `McpJsonDefaults.getSchemaValidator()` when you do not configure one explicitly) and `validateToolInputs` is left at its default of `true`, the server validates incoming tool arguments against `tool.inputSchema()` before invoking the tool. Failed validation produces a `CallToolResult` with `isError` set and a textual error in the content. diff --git a/conformance-tests/server-servlet/src/main/java/io/modelcontextprotocol/conformance/server/ConformanceServlet.java b/conformance-tests/server-servlet/src/main/java/io/modelcontextprotocol/conformance/server/ConformanceServlet.java index 25ec2c106..71704e2a7 100644 --- a/conformance-tests/server-servlet/src/main/java/io/modelcontextprotocol/conformance/server/ConformanceServlet.java +++ b/conformance-tests/server-servlet/src/main/java/io/modelcontextprotocol/conformance/server/ConformanceServlet.java @@ -237,18 +237,14 @@ private static List createToolSpecs() { .callHandler((exchange, request) -> { logger.info("Tool 'test_tool_with_logging' called"); // Send log notifications - exchange.loggingNotification(LoggingMessageNotification.builder() - .level(LoggingLevel.INFO) - .data("Tool execution started") - .build()); - exchange.loggingNotification(LoggingMessageNotification.builder() - .level(LoggingLevel.INFO) - .data("Tool processing data") - .build()); - exchange.loggingNotification(LoggingMessageNotification.builder() - .level(LoggingLevel.INFO) - .data("Tool execution completed") - .build()); + exchange.loggingNotification( + LoggingMessageNotification.builder(LoggingLevel.INFO, "Tool execution started") + .build()); + exchange.loggingNotification( + LoggingMessageNotification.builder(LoggingLevel.INFO, "Tool processing data").build()); + exchange.loggingNotification( + LoggingMessageNotification.builder(LoggingLevel.INFO, "Tool execution completed") + .build()); return CallToolResult.builder() .content(List.of(new TextContent("Tool execution completed with logging"))) .isError(false) @@ -335,9 +331,8 @@ private static List createToolSpecs() { String prompt = (String) request.arguments().get("prompt"); // Request sampling from client - CreateMessageRequest samplingRequest = CreateMessageRequest.builder() - .messages(List.of(new SamplingMessage(Role.USER, new TextContent(prompt)))) - .maxTokens(100) + CreateMessageRequest samplingRequest = CreateMessageRequest + .builder(List.of(new SamplingMessage(Role.USER, new TextContent(prompt))), 100) .build(); CreateMessageResult response = exchange.createMessage(samplingRequest); diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java index 72376929c..abd6e0ff9 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java @@ -296,6 +296,41 @@ public record JSONRPCError( // @formatter:off @JsonProperty("code") Integer code, @JsonProperty("message") String message, @JsonProperty("data") Object data) { // @formatter:on + + public JSONRPCError { + Assert.notNull(code, "code must not be null"); + Assert.notNull(message, "message must not be null"); + } + + public static Builder builder(int code, String message) { + return new Builder(code, message); + } + + public static class Builder { + + private final Integer code; + + private final String message; + + private Object data; + + private Builder(int code, String message) { + Assert.notNull(message, "message must not be null"); + this.code = code; + this.message = message; + } + + public Builder data(Object data) { + this.data = data; + return this; + } + + public JSONRPCError build() { + return new JSONRPCError(code, message, data); + } + + } + } } @@ -1573,6 +1608,10 @@ public record CallToolResult( // @formatter:off @JsonProperty("structuredContent") Object structuredContent, @JsonProperty("_meta") Map meta) implements Result { // @formatter:on + public CallToolResult { + Assert.notNull(content, "content must not be null"); + } + /** * Creates a builder for {@link CallToolResult}. * @return a new builder instance @@ -1590,6 +1629,14 @@ public static class Builder { private Boolean isError = false; + /** + * @deprecated Use {@link CallToolResult#builder()} factory method instead of + * instantiating the builder directly. + */ + @Deprecated + public Builder() { + } + private Object structuredContent; private Map meta; @@ -1683,6 +1730,7 @@ public Builder meta(Map meta) { * @return a new CallToolResult instance */ public CallToolResult build() { + Assert.notNull(content, "content must not be null"); return new CallToolResult(content, isError, structuredContent, meta); } @@ -1797,6 +1845,11 @@ public static ModelHint of(String name) { public record SamplingMessage( // @formatter:off @JsonProperty("role") Role role, @JsonProperty("content") Content content) { // @formatter:on + + public SamplingMessage { + Assert.notNull(role, "role must not be null"); + Assert.notNull(content, "content must not be null"); + } } /** @@ -1834,6 +1887,11 @@ public record CreateMessageRequest( // @formatter:off @JsonProperty("metadata") Map metadata, @JsonProperty("_meta") Map meta) implements Request { // @formatter:on + public CreateMessageRequest { + Assert.notNull(messages, "messages must not be null"); + Assert.notNull(maxTokens, "maxTokens must not be null"); + } + // backwards compatibility constructor public CreateMessageRequest(List messages, ModelPreferences modelPreferences, String systemPrompt, ContextInclusionStrategy includeContext, Double temperature, Integer maxTokens, @@ -1851,10 +1909,18 @@ public enum ContextInclusionStrategy { } + /** + * @deprecated Use {@link #builder(List, int)} instead. + */ + @Deprecated public static Builder builder() { return new Builder(); } + public static Builder builder(List messages, int maxTokens) { + return new Builder(messages, maxTokens); + } + public static class Builder { private List messages; @@ -1875,7 +1941,22 @@ public static class Builder { private Map meta; + /** + * @deprecated Use {@link CreateMessageRequest#builder(List, int)} factory + * method instead. + */ + @Deprecated + public Builder() { + } + + private Builder(List messages, int maxTokens) { + Assert.notNull(messages, "messages must not be null"); + this.messages = messages; + this.maxTokens = maxTokens; + } + public Builder messages(List messages) { + Assert.notNull(messages, "messages must not be null"); this.messages = messages; return this; } @@ -2063,15 +2144,28 @@ public record ElicitRequest( // @formatter:off @JsonProperty("requestedSchema") Map requestedSchema, @JsonProperty("_meta") Map meta) implements Request { // @formatter:on + public ElicitRequest { + Assert.notNull(message, "message must not be null"); + Assert.notNull(requestedSchema, "requestedSchema must not be null"); + } + // backwards compatibility constructor public ElicitRequest(String message, Map requestedSchema) { this(message, requestedSchema, null); } + /** + * @deprecated Use {@link #builder(String, Map)} instead. + */ + @Deprecated public static Builder builder() { return new Builder(); } + public static Builder builder(String message, Map requestedSchema) { + return new Builder(message, requestedSchema); + } + public static class Builder { private String message; @@ -2080,12 +2174,29 @@ public static class Builder { private Map meta; + /** + * @deprecated Use {@link ElicitRequest#builder(String, Map)} factory method + * instead. + */ + @Deprecated + public Builder() { + } + + private Builder(String message, Map requestedSchema) { + Assert.notNull(message, "message must not be null"); + Assert.notNull(requestedSchema, "requestedSchema must not be null"); + this.message = message; + this.requestedSchema = requestedSchema; + } + public Builder message(String message) { + Assert.notNull(message, "message must not be null"); this.message = message; return this; } public Builder requestedSchema(Map requestedSchema) { + Assert.notNull(requestedSchema, "requestedSchema must not be null"); this.requestedSchema = requestedSchema; return this; } @@ -2239,9 +2350,58 @@ public record ProgressNotification( // @formatter:off @JsonProperty("message") String message, @JsonProperty("_meta") Map meta) implements Notification { // @formatter:on + public ProgressNotification { + Assert.notNull(progressToken, "progressToken must not be null"); + Assert.notNull(progress, "progress must not be null"); + } + public ProgressNotification(Object progressToken, double progress, Double total, String message) { this(progressToken, progress, total, message, null); } + + public static Builder builder(Object progressToken, double progress) { + return new Builder(progressToken, progress); + } + + public static class Builder { + + private final Object progressToken; + + private final Double progress; + + private Double total; + + private String message; + + private Map meta; + + private Builder(Object progressToken, double progress) { + Assert.notNull(progressToken, "progressToken must not be null"); + this.progressToken = progressToken; + this.progress = progress; + } + + public Builder total(Double total) { + this.total = total; + return this; + } + + public Builder message(String message) { + this.message = message; + return this; + } + + public Builder meta(Map meta) { + this.meta = meta; + return this; + } + + public ProgressNotification build() { + return new ProgressNotification(progressToken, progress, total, message, meta); + } + + } + } /** @@ -2281,15 +2441,28 @@ public record LoggingMessageNotification( // @formatter:off @JsonProperty("data") String data, @JsonProperty("_meta") Map meta) implements Notification { // @formatter:on + public LoggingMessageNotification { + Assert.notNull(level, "level must not be null"); + Assert.notNull(data, "data must not be null"); + } + // backwards compatibility constructor public LoggingMessageNotification(LoggingLevel level, String logger, String data) { this(level, logger, data, null); } + /** + * @deprecated Use {@link #builder(LoggingLevel, String)} instead. + */ + @Deprecated public static Builder builder() { return new Builder(); } + public static Builder builder(LoggingLevel level, String data) { + return new Builder(level, data); + } + public static class Builder { private LoggingLevel level = LoggingLevel.INFO; @@ -2300,7 +2473,24 @@ public static class Builder { private Map meta; + /** + * @deprecated Use + * {@link LoggingMessageNotification#builder(LoggingLevel, String)} factory + * method instead. + */ + @Deprecated + public Builder() { + } + + private Builder(LoggingLevel level, String data) { + Assert.notNull(level, "level must not be null"); + Assert.notNull(data, "data must not be null"); + this.level = level; + this.data = data; + } + public Builder level(LoggingLevel level) { + Assert.notNull(level, "level must not be null"); this.level = level; return this; } @@ -2311,6 +2501,7 @@ public Builder logger(String logger) { } public Builder data(String data) { + Assert.notNull(data, "data must not be null"); this.data = data; return this; } diff --git a/mcp-core/src/test/java/io/modelcontextprotocol/server/McpAsyncServerExchangeTests.java b/mcp-core/src/test/java/io/modelcontextprotocol/server/McpAsyncServerExchangeTests.java index e6161a59f..5f07b318c 100644 --- a/mcp-core/src/test/java/io/modelcontextprotocol/server/McpAsyncServerExchangeTests.java +++ b/mcp-core/src/test/java/io/modelcontextprotocol/server/McpAsyncServerExchangeTests.java @@ -227,10 +227,9 @@ void testSetMinLoggingLevelWithNullValue() { @Test void testLoggingNotificationWithAllowedLevel() { - McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Test error message") .logger("test-logger") - .data("Test error message") .build(); when(mockSession.isNotificationForLevelAllowed(any())).thenReturn(Boolean.TRUE); @@ -248,10 +247,9 @@ void testLoggingNotificationWithFilteredLevel() { exchange.setMinLoggingLevel(McpSchema.LoggingLevel.DEBUG); verify(mockSession, times(1)).setMinLoggingLevel(eq(McpSchema.LoggingLevel.DEBUG)); - McpSchema.LoggingMessageNotification debugNotification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.DEBUG) + McpSchema.LoggingMessageNotification debugNotification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.DEBUG, "Debug message that should be filtered") .logger("test-logger") - .data("Debug message that should be filtered") .build(); when(mockSession.isNotificationForLevelAllowed(eq(McpSchema.LoggingLevel.DEBUG))).thenReturn(Boolean.TRUE); @@ -264,10 +262,9 @@ void testLoggingNotificationWithFilteredLevel() { verify(mockSession, times(1)).sendNotification(eq(McpSchema.METHOD_NOTIFICATION_MESSAGE), eq(debugNotification)); - McpSchema.LoggingMessageNotification warningNotification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.WARNING) + McpSchema.LoggingMessageNotification warningNotification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.WARNING, "Debug message that should be filtered") .logger("test-logger") - .data("Debug message that should be filtered") .build(); StepVerifier.create(exchange.loggingNotification(warningNotification)).verifyComplete(); @@ -279,10 +276,9 @@ void testLoggingNotificationWithFilteredLevel() { @Test void testLoggingNotificationWithSessionError() { - McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Test error message") .logger("test-logger") - .data("Test error message") .build(); when(mockSession.isNotificationForLevelAllowed(any())).thenReturn(Boolean.TRUE); @@ -304,8 +300,8 @@ void testCreateElicitationWithNullCapabilities() { McpAsyncServerExchange exchangeWithNullCapabilities = new McpAsyncServerExchange("testSessionId", mockSession, null, clientInfo, McpTransportContext.EMPTY); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); StepVerifier.create(exchangeWithNullCapabilities.createElicitation(elicitRequest)) @@ -328,8 +324,8 @@ void testCreateElicitationWithoutElicitationCapabilities() { McpAsyncServerExchange exchangeWithoutElicitation = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithoutElicitation, clientInfo, McpTransportContext.EMPTY); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); StepVerifier.create(exchangeWithoutElicitation.createElicitation(elicitRequest)).verifyErrorSatisfies(error -> { @@ -359,9 +355,8 @@ void testCreateElicitationWithComplexRequest() { java.util.Map.of("type", "number"))); requestedSchema.put("required", java.util.List.of("name")); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your personal information") - .requestedSchema(requestedSchema) + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your personal information", requestedSchema) .build(); java.util.Map responseContent = new java.util.HashMap<>(); @@ -395,8 +390,8 @@ void testCreateElicitationWithDeclineAction() { McpAsyncServerExchange exchangeWithElicitation = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide sensitive information") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide sensitive information", Map.of("type", "object")) .build(); McpSchema.ElicitResult expectedResult = McpSchema.ElicitResult.builder() @@ -422,8 +417,8 @@ void testCreateElicitationWithCancelAction() { McpAsyncServerExchange exchangeWithElicitation = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your information") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your information", Map.of("type", "object")) .build(); McpSchema.ElicitResult expectedResult = McpSchema.ElicitResult.builder() @@ -449,8 +444,8 @@ void testCreateElicitationWithSessionError() { McpAsyncServerExchange exchangeWithElicitation = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); when(mockSession.sendRequest(eq(McpSchema.METHOD_ELICITATION_CREATE), eq(elicitRequest), any(TypeRef.class))) @@ -471,9 +466,10 @@ void testCreateMessageWithNullCapabilities() { McpAsyncServerExchange exchangeWithNullCapabilities = new McpAsyncServerExchange("testSessionId", mockSession, null, clientInfo, McpTransportContext.EMPTY); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); StepVerifier.create(exchangeWithNullCapabilities.createMessage(createMessageRequest)) @@ -497,9 +493,10 @@ void testCreateMessageWithoutSamplingCapabilities() { McpAsyncServerExchange exchangeWithoutSampling = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithoutSampling, clientInfo, McpTransportContext.EMPTY); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); StepVerifier.create(exchangeWithoutSampling.createMessage(createMessageRequest)).verifyErrorSatisfies(error -> { @@ -522,9 +519,10 @@ void testCreateMessageWithBasicRequest() { McpAsyncServerExchange exchangeWithSampling = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); McpSchema.CreateMessageResult expectedResult = McpSchema.CreateMessageResult.builder() @@ -559,10 +557,13 @@ void testCreateMessageWithImageContent() { capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); // Create request with image content - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.ImageContent(null, "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...", - "image/jpeg")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder( + Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.ImageContent(null, + "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...", "image/jpeg"))), + 1000) .build(); McpSchema.CreateMessageResult expectedResult = McpSchema.CreateMessageResult.builder() @@ -593,9 +594,11 @@ void testCreateMessageWithSessionError() { McpAsyncServerExchange exchangeWithSampling = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder( + Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello"))), + 1000) .build(); when(mockSession.sendRequest(eq(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE), eq(createMessageRequest), @@ -617,9 +620,9 @@ void testCreateMessageWithIncludeContext() { McpAsyncServerExchange exchangeWithSampling = new McpAsyncServerExchange("testSessionId", mockSession, capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.TextContent("What files are available?")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("What files are available?"))), 1000) .includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.ALL_SERVERS) .build(); diff --git a/mcp-core/src/test/java/io/modelcontextprotocol/server/McpSyncServerExchangeTests.java b/mcp-core/src/test/java/io/modelcontextprotocol/server/McpSyncServerExchangeTests.java index fba733c9a..009a17955 100644 --- a/mcp-core/src/test/java/io/modelcontextprotocol/server/McpSyncServerExchangeTests.java +++ b/mcp-core/src/test/java/io/modelcontextprotocol/server/McpSyncServerExchangeTests.java @@ -221,10 +221,9 @@ void testLoggingNotificationWithNullMessage() { @Test void testLoggingNotificationWithAllowedLevel() { - McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Test error message") .logger("test-logger") - .data("Test error message") .build(); when(mockSession.isNotificationForLevelAllowed(any())).thenReturn(Boolean.TRUE); @@ -243,10 +242,9 @@ void testLoggingNotificationWithFilteredLevel() { asyncExchange.setMinLoggingLevel(McpSchema.LoggingLevel.DEBUG); verify(mockSession, times(1)).setMinLoggingLevel(McpSchema.LoggingLevel.DEBUG); - McpSchema.LoggingMessageNotification debugNotification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.DEBUG) + McpSchema.LoggingMessageNotification debugNotification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.DEBUG, "Debug message that should be filtered") .logger("test-logger") - .data("Debug message that should be filtered") .build(); when(mockSession.isNotificationForLevelAllowed(eq(McpSchema.LoggingLevel.DEBUG))).thenReturn(Boolean.TRUE); @@ -259,10 +257,9 @@ void testLoggingNotificationWithFilteredLevel() { verify(mockSession, times(1)).sendNotification(eq(McpSchema.METHOD_NOTIFICATION_MESSAGE), eq(debugNotification)); - McpSchema.LoggingMessageNotification warningNotification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.WARNING) + McpSchema.LoggingMessageNotification warningNotification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.WARNING, "Debug message that should be filtered") .logger("test-logger") - .data("Debug message that should be filtered") .build(); exchange.loggingNotification(warningNotification); @@ -275,10 +272,9 @@ void testLoggingNotificationWithFilteredLevel() { @Test void testLoggingNotificationWithSessionError() { - McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + McpSchema.LoggingMessageNotification notification = McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Test error message") .logger("test-logger") - .data("Test error message") .build(); when(mockSession.isNotificationForLevelAllowed(any())).thenReturn(Boolean.TRUE); @@ -301,8 +297,8 @@ void testCreateElicitationWithNullCapabilities() { McpSyncServerExchange exchangeWithNullCapabilities = new McpSyncServerExchange( asyncExchangeWithNullCapabilities); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); assertThatThrownBy(() -> exchangeWithNullCapabilities.createElicitation(elicitRequest)) @@ -324,8 +320,8 @@ void testCreateElicitationWithoutElicitationCapabilities() { mockSession, capabilitiesWithoutElicitation, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithoutElicitation = new McpSyncServerExchange(asyncExchangeWithoutElicitation); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); assertThatThrownBy(() -> exchangeWithoutElicitation.createElicitation(elicitRequest)) @@ -355,9 +351,8 @@ void testCreateElicitationWithComplexRequest() { java.util.Map.of("type", "number"))); requestedSchema.put("required", java.util.List.of("name")); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your personal information") - .requestedSchema(requestedSchema) + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your personal information", requestedSchema) .build(); java.util.Map responseContent = new java.util.HashMap<>(); @@ -392,8 +387,8 @@ void testCreateElicitationWithDeclineAction() { capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithElicitation = new McpSyncServerExchange(asyncExchangeWithElicitation); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide sensitive information") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide sensitive information", Map.of("type", "object")) .build(); McpSchema.ElicitResult expectedResult = McpSchema.ElicitResult.builder() @@ -420,8 +415,8 @@ void testCreateElicitationWithCancelAction() { capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithElicitation = new McpSyncServerExchange(asyncExchangeWithElicitation); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your information") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your information", Map.of("type", "object")) .build(); McpSchema.ElicitResult expectedResult = McpSchema.ElicitResult.builder() @@ -448,8 +443,8 @@ void testCreateElicitationWithSessionError() { capabilitiesWithElicitation, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithElicitation = new McpSyncServerExchange(asyncExchangeWithElicitation); - McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest.builder() - .message("Please provide your name") + McpSchema.ElicitRequest elicitRequest = McpSchema.ElicitRequest + .builder("Please provide your name", Map.of("type", "object")) .build(); when(mockSession.sendRequest(eq(McpSchema.METHOD_ELICITATION_CREATE), eq(elicitRequest), any(TypeRef.class))) @@ -472,9 +467,10 @@ void testCreateMessageWithNullCapabilities() { McpSyncServerExchange exchangeWithNullCapabilities = new McpSyncServerExchange( asyncExchangeWithNullCapabilities); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); assertThatThrownBy(() -> exchangeWithNullCapabilities.createMessage(createMessageRequest)) @@ -497,9 +493,10 @@ void testCreateMessageWithoutSamplingCapabilities() { capabilitiesWithoutSampling, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithoutSampling = new McpSyncServerExchange(asyncExchangeWithoutSampling); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); assertThatThrownBy(() -> exchangeWithoutSampling.createMessage(createMessageRequest)) @@ -522,9 +519,10 @@ void testCreateMessageWithBasicRequest() { capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithSampling = new McpSyncServerExchange(asyncExchangeWithSampling); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello, world!"))), + 1000) .build(); McpSchema.CreateMessageResult expectedResult = McpSchema.CreateMessageResult.builder() @@ -560,10 +558,13 @@ void testCreateMessageWithImageContent() { McpSyncServerExchange exchangeWithSampling = new McpSyncServerExchange(asyncExchangeWithSampling); // Create request with image content - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.ImageContent(null, "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...", - "image/jpeg")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder( + Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.ImageContent(null, + "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...", "image/jpeg"))), + 1000) .build(); McpSchema.CreateMessageResult expectedResult = McpSchema.CreateMessageResult.builder() @@ -595,9 +596,11 @@ void testCreateMessageWithSessionError() { capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithSampling = new McpSyncServerExchange(asyncExchangeWithSampling); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays - .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder( + Arrays + .asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Hello"))), + 1000) .build(); when(mockSession.sendRequest(eq(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE), eq(createMessageRequest), @@ -620,9 +623,9 @@ void testCreateMessageWithIncludeContext() { capabilitiesWithSampling, clientInfo, McpTransportContext.EMPTY); McpSyncServerExchange exchangeWithSampling = new McpSyncServerExchange(asyncExchangeWithSampling); - McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.TextContent("What files are available?")))) + McpSchema.CreateMessageRequest createMessageRequest = McpSchema.CreateMessageRequest + .builder(Arrays.asList(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("What files are available?"))), 1000) .includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.ALL_SERVERS) .build(); diff --git a/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java b/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java index beec006ba..7675f4e36 100644 --- a/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java +++ b/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java @@ -162,9 +162,9 @@ void testCreateMessageSuccess(String clientType) { .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.TextContent("Test message")))) + var createMessageRequest = McpSchema.CreateMessageRequest + .builder(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("Test message"))), 1000) .modelPreferences(ModelPreferences.builder() .hints(List.of()) .costPriority(1.0) @@ -241,9 +241,9 @@ void testCreateMessageWithRequestTimeoutSuccess(String clientType) throws Interr .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.TextContent("Test message")))) + var createMessageRequest = McpSchema.CreateMessageRequest + .builder(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("Test message"))), 1000) .modelPreferences(ModelPreferences.builder() .hints(List.of()) .costPriority(1.0) @@ -316,9 +316,9 @@ void testCreateMessageWithRequestTimeoutFail(String clientType) throws Interrupt .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var createMessageRequest = McpSchema.CreateMessageRequest.builder() - .messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, - new McpSchema.TextContent("Test message")))) + var createMessageRequest = McpSchema.CreateMessageRequest + .builder(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("Test message"))), 1000) .modelPreferences(ModelPreferences.builder() .hints(List.of()) .costPriority(1.0) @@ -412,9 +412,8 @@ void testCreateElicitationSuccess(String clientType) { .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var elicitationRequest = McpSchema.ElicitRequest.builder() - .message("Test message") - .requestedSchema( + var elicitationRequest = McpSchema.ElicitRequest + .builder("Test message", Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) .build(); @@ -471,9 +470,8 @@ void testCreateElicitationWithRequestTimeoutSuccess(String clientType) { .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var elicitationRequest = McpSchema.ElicitRequest.builder() - .message("Test message") - .requestedSchema( + var elicitationRequest = McpSchema.ElicitRequest + .builder("Test message", Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) .build(); @@ -542,9 +540,8 @@ void testCreateElicitationWithRequestTimeoutFail(String clientType) { .tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build()) .callHandler((exchange, request) -> { - var elicitationRequest = ElicitRequest.builder() - .message("Test message") - .requestedSchema( + var elicitationRequest = ElicitRequest + .builder("Test message", Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) .build(); @@ -1113,34 +1110,29 @@ void testLoggingNotification(String clientType) throws InterruptedException { //@formatter:off return exchange // This should be filtered out (DEBUG < NOTICE) - .loggingNotification(McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.DEBUG) + .loggingNotification(McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.DEBUG, "Debug message") .logger("test-logger") - .data("Debug message") .build()) .then(exchange // This should be sent (NOTICE >= NOTICE) - .loggingNotification(McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.NOTICE) + .loggingNotification(McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.NOTICE, "Notice message") .logger("test-logger") - .data("Notice message") .build())) .then(exchange // This should be sent (ERROR > NOTICE) - .loggingNotification(McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + .loggingNotification(McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Error message") .logger("test-logger") - .data("Error message") .build())) .then(exchange // This should be filtered out (INFO < NOTICE) - .loggingNotification(McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.INFO) + .loggingNotification(McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.INFO, "Another info message") .logger("test-logger") - .data("Another info message") .build())) .then(exchange // This should be sent (ERROR >= NOTICE) - .loggingNotification(McpSchema.LoggingMessageNotification.builder() - .level(McpSchema.LoggingLevel.ERROR) + .loggingNotification(McpSchema.LoggingMessageNotification + .builder(McpSchema.LoggingLevel.ERROR, "Another error message") .logger("test-logger") - .data("Another error message") .build())) .thenReturn(CallToolResult.builder() .content(List.of(new McpSchema.TextContent("Logging test completed"))) diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java index 47a229afd..3692c1c4e 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java @@ -417,9 +417,9 @@ void testElicitationCreateRequestHandling() { assertThat(asyncMcpClient.initialize().block()).isNotNull(); // Create a mock elicitation - var elicitRequest = McpSchema.ElicitRequest.builder() - .message("Test message") - .requestedSchema(Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) + var elicitRequest = McpSchema.ElicitRequest + .builder("Test message", + Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) .build(); // Simulate incoming request @@ -462,9 +462,9 @@ void testElicitationFailRequestHandling(McpSchema.ElicitResult.Action action) { assertThat(asyncMcpClient.initialize().block()).isNotNull(); // Create a mock elicitation - var elicitRequest = McpSchema.ElicitRequest.builder() - .message("Test message") - .requestedSchema(Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) + var elicitRequest = McpSchema.ElicitRequest + .builder("Test message", + Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string")))) .build(); // Simulate incoming request diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java index 09529f2e0..9cc9f1e11 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java @@ -133,13 +133,12 @@ void testCreateMessageRequestWithMeta() throws Exception { Map meta = new HashMap<>(); meta.put("progressToken", "create-message-token-456"); - McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder() - .messages(Collections.singletonList(message)) + McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest + .builder(Collections.singletonList(message), 1000) .modelPreferences(preferences) .systemPrompt("You are a helpful assistant") .includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.THIS_SERVER) .temperature(0.7) - .maxTokens(1000) .stopSequences(Arrays.asList("STOP", "END")) .metadata(metadata) .meta(meta) @@ -1363,13 +1362,12 @@ void testCreateMessageRequest() throws Exception { Map metadata = new HashMap<>(); metadata.put("session", "test-session"); - McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder() - .messages(Collections.singletonList(message)) + McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest + .builder(Collections.singletonList(message), 1000) .modelPreferences(preferences) .systemPrompt("You are a helpful assistant") .includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.THIS_SERVER) .temperature(0.7) - .maxTokens(1000) .stopSequences(Arrays.asList("STOP", "END")) .metadata(metadata) .build(); @@ -1426,9 +1424,9 @@ void testCreateMessageResultUnknownStopReason() throws Exception { @Test void testCreateElicitationRequest() throws Exception { - McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder() - .requestedSchema(Map.of("type", "object", "required", List.of("a"), "properties", - Map.of("foo", Map.of("type", "string")))) + McpSchema.ElicitRequest request = McpSchema.ElicitRequest + .builder("Please provide additional information", Map.of("type", "object", "required", List.of("a"), + "properties", Map.of("foo", Map.of("type", "string")))) .build(); String value = JSON_MAPPER.writeValueAsString(request); @@ -1436,8 +1434,9 @@ void testCreateElicitationRequest() throws Exception { assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) .when(Option.IGNORING_EXTRA_ARRAY_ITEMS) .isObject() - .isEqualTo(json(""" - {"requestedSchema":{"properties":{"foo":{"type":"string"}},"required":["a"],"type":"object"}}""")); + .isEqualTo( + json(""" + {"message":"Please provide additional information","requestedSchema":{"properties":{"foo":{"type":"string"}},"required":["a"],"type":"object"}}""")); } @Test @@ -1464,9 +1463,7 @@ void testElicitRequestWithMeta() throws Exception { Map meta = new HashMap<>(); meta.put("progressToken", "elicit-token-789"); - McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder() - .message("Please provide your name") - .requestedSchema(requestedSchema) + McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder("Please provide your name", requestedSchema) .meta(meta) .build();