feat: client-side application of elicitation schema defaults (SEP-1034) (#976)
Adds an opt-in McpClient builder option `applyElicitationDefaults(boolean)` that, when enabled, fills missing keys of an accepted ElicitResult.content with `default` values declared in the requestedSchema before returning the result to the server. Mirrors the TypeScript SDK's applyElicitationDefaults behavior, but exposed as a local client config rather than a wire capability. Co-authored-by: Sainath Reddy Bobbala <bsnr@amazon.com> Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
This commit is contained in:
parent
6b71136224
commit
accba74c8f
4 changed files with 587 additions and 18 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
* Copyright 2024-2026 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.client;
|
||||
|
|
@ -15,6 +15,9 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.modelcontextprotocol.client.LifecycleInitializer.Initialization;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
|
|
@ -30,16 +33,14 @@ import io.modelcontextprotocol.spec.McpSchema.ElicitRequest;
|
|||
import io.modelcontextprotocol.spec.McpSchema.ElicitResult;
|
||||
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
|
||||
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
|
||||
import io.modelcontextprotocol.util.ToolNameValidator;
|
||||
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
|
||||
import io.modelcontextprotocol.spec.McpSchema.LoggingLevel;
|
||||
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
|
||||
import io.modelcontextprotocol.spec.McpSchema.PaginatedRequest;
|
||||
import io.modelcontextprotocol.spec.McpSchema.Root;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import io.modelcontextprotocol.util.ToolNameValidator;
|
||||
import io.modelcontextprotocol.util.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
|
@ -171,6 +172,8 @@ public class McpAsyncClient {
|
|||
*/
|
||||
private final boolean enableCallToolSchemaCaching;
|
||||
|
||||
private final boolean applyElicitationDefaults;
|
||||
|
||||
/**
|
||||
* Create a new McpAsyncClient with the given transport and session request-response
|
||||
* timeout.
|
||||
|
|
@ -195,6 +198,7 @@ public class McpAsyncClient {
|
|||
this.jsonSchemaValidator = jsonSchemaValidator;
|
||||
this.toolsOutputSchemaCache = new ConcurrentHashMap<>();
|
||||
this.enableCallToolSchemaCaching = features.enableCallToolSchemaCaching();
|
||||
this.applyElicitationDefaults = features.applyElicitationDefaults();
|
||||
|
||||
// Request Handlers
|
||||
Map<String, RequestHandler<?>> requestHandlers = new HashMap<>();
|
||||
|
|
@ -561,10 +565,57 @@ public class McpAsyncClient {
|
|||
ElicitRequest request = transport.unmarshalFrom(params, new TypeRef<>() {
|
||||
});
|
||||
|
||||
return this.elicitationHandler.apply(request);
|
||||
return this.elicitationHandler.apply(request).map(result -> {
|
||||
if (this.applyElicitationDefaults && result.action() == ElicitResult.Action.ACCEPT
|
||||
&& result.content() != null) {
|
||||
Map<String, Object> merged = new HashMap<>(result.content());
|
||||
applyElicitationDefaults(request.requestedSchema(), merged);
|
||||
return new ElicitResult(result.action(), merged, result.meta());
|
||||
}
|
||||
return result;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies default values from the elicitation schema into a result-content map: for
|
||||
* each top-level property in {@code schema.properties} that declares a
|
||||
* {@code "default"}, the value is inserted into {@code content} when the key is
|
||||
* absent.
|
||||
* <p>
|
||||
* Only top-level properties are visited; nested objects and {@code anyOf}/
|
||||
* {@code oneOf} branches are not traversed. This is sufficient for SEP-1034's flat
|
||||
* elicitation primitive schemas (string, number, boolean, enum).
|
||||
* @param schema the {@code requestedSchema} from the {@link ElicitRequest}
|
||||
* @param content the mutable content map to update
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static void applyElicitationDefaults(Map<String, Object> schema, Map<String, Object> content) {
|
||||
if (schema == null || content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object propertiesObj = schema.get("properties");
|
||||
if (!(propertiesObj instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> properties = (Map<String, Object>) propertiesObj;
|
||||
for (Map.Entry<String, Object> entry : properties.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object propDef = entry.getValue();
|
||||
|
||||
if (!(propDef instanceof Map)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> propMap = (Map<String, Object>) propDef;
|
||||
if (!content.containsKey(key) && propMap.containsKey("default")) {
|
||||
content.put(key, propMap.get("default"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// Tools
|
||||
// --------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
* Copyright 2024-2026 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.client;
|
||||
|
|
@ -195,6 +195,8 @@ public interface McpClient {
|
|||
|
||||
private boolean enableCallToolSchemaCaching = false; // Default to false
|
||||
|
||||
private boolean applyElicitationDefaults = false; // Default to false
|
||||
|
||||
private SyncSpec(McpClientTransport transport) {
|
||||
Assert.notNull(transport, "Transport must not be null");
|
||||
this.transport = transport;
|
||||
|
|
@ -479,6 +481,19 @@ public interface McpClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables SDK-side merging of elicitation schema defaults into an accepted
|
||||
* {@link ElicitResult}'s {@code content} for fields the elicitation handler left
|
||||
* unset. This is a client-local behavior and is NOT serialized as part of the MCP
|
||||
* capability handshake.
|
||||
* @param applyElicitationDefaults true to enable, false to disable
|
||||
* @return This builder instance for method chaining
|
||||
*/
|
||||
public SyncSpec applyElicitationDefaults(boolean applyElicitationDefaults) {
|
||||
this.applyElicitationDefaults = applyElicitationDefaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link McpSyncClient} with the provided configurations or
|
||||
* sensible defaults.
|
||||
|
|
@ -488,7 +503,7 @@ public interface McpClient {
|
|||
McpClientFeatures.Sync syncFeatures = new McpClientFeatures.Sync(this.clientInfo, this.capabilities,
|
||||
this.roots, this.toolsChangeConsumers, this.resourcesChangeConsumers, this.resourcesUpdateConsumers,
|
||||
this.promptsChangeConsumers, this.loggingConsumers, this.progressConsumers, this.samplingHandler,
|
||||
this.elicitationHandler, this.enableCallToolSchemaCaching);
|
||||
this.elicitationHandler, this.enableCallToolSchemaCaching, this.applyElicitationDefaults);
|
||||
|
||||
McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures);
|
||||
|
||||
|
|
@ -549,6 +564,8 @@ public interface McpClient {
|
|||
|
||||
private boolean enableCallToolSchemaCaching = false; // Default to false
|
||||
|
||||
private boolean applyElicitationDefaults = false; // Default to false
|
||||
|
||||
private AsyncSpec(McpClientTransport transport) {
|
||||
Assert.notNull(transport, "Transport must not be null");
|
||||
this.transport = transport;
|
||||
|
|
@ -820,6 +837,19 @@ public interface McpClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables SDK-side merging of elicitation schema defaults into an accepted
|
||||
* {@link ElicitResult}'s {@code content} for fields the elicitation handler left
|
||||
* unset. This is a client-local behavior and is NOT serialized as part of the MCP
|
||||
* capability handshake.
|
||||
* @param applyElicitationDefaults true to enable, false to disable
|
||||
* @return This builder instance for method chaining
|
||||
*/
|
||||
public AsyncSpec applyElicitationDefaults(boolean applyElicitationDefaults) {
|
||||
this.applyElicitationDefaults = applyElicitationDefaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link McpAsyncClient} with the provided configurations
|
||||
* or sensible defaults.
|
||||
|
|
@ -833,7 +863,8 @@ public interface McpClient {
|
|||
new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots,
|
||||
this.toolsChangeConsumers, this.resourcesChangeConsumers, this.resourcesUpdateConsumers,
|
||||
this.promptsChangeConsumers, this.loggingConsumers, this.progressConsumers,
|
||||
this.samplingHandler, this.elicitationHandler, this.enableCallToolSchemaCaching));
|
||||
this.samplingHandler, this.elicitationHandler, this.enableCallToolSchemaCaching,
|
||||
this.applyElicitationDefaults));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
* Copyright 2024-2026 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.client;
|
||||
|
|
@ -63,6 +63,9 @@ class McpClientFeatures {
|
|||
* @param samplingHandler the sampling handler.
|
||||
* @param elicitationHandler the elicitation handler.
|
||||
* @param enableCallToolSchemaCaching whether to enable call tool schema caching.
|
||||
* @param applyElicitationDefaults whether the client should fill in missing fields of
|
||||
* an accepted {@code ElicitResult.content} with the {@code default} values declared
|
||||
* in the {@code requestedSchema}.
|
||||
*/
|
||||
record Async(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
|
||||
Map<String, McpSchema.Root> roots, List<Function<List<McpSchema.Tool>, Mono<Void>>> toolsChangeConsumers,
|
||||
|
|
@ -73,7 +76,7 @@ class McpClientFeatures {
|
|||
List<Function<McpSchema.ProgressNotification, Mono<Void>>> progressConsumers,
|
||||
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler,
|
||||
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler,
|
||||
boolean enableCallToolSchemaCaching) {
|
||||
boolean enableCallToolSchemaCaching, boolean applyElicitationDefaults) {
|
||||
|
||||
/**
|
||||
* Create an instance and validate the arguments.
|
||||
|
|
@ -87,6 +90,9 @@ class McpClientFeatures {
|
|||
* @param samplingHandler the sampling handler.
|
||||
* @param elicitationHandler the elicitation handler.
|
||||
* @param enableCallToolSchemaCaching whether to enable call tool schema caching.
|
||||
* @param applyElicitationDefaults whether the client should fill in missing
|
||||
* fields of an accepted {@code ElicitResult.content} with the {@code default}
|
||||
* values declared in the {@code requestedSchema}.
|
||||
*/
|
||||
public Async(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
|
||||
Map<String, McpSchema.Root> roots,
|
||||
|
|
@ -98,7 +104,7 @@ class McpClientFeatures {
|
|||
List<Function<McpSchema.ProgressNotification, Mono<Void>>> progressConsumers,
|
||||
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler,
|
||||
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler,
|
||||
boolean enableCallToolSchemaCaching) {
|
||||
boolean enableCallToolSchemaCaching, boolean applyElicitationDefaults) {
|
||||
|
||||
Assert.notNull(clientInfo, "Client info must not be null");
|
||||
this.clientInfo = clientInfo;
|
||||
|
|
@ -119,6 +125,7 @@ class McpClientFeatures {
|
|||
this.samplingHandler = samplingHandler;
|
||||
this.elicitationHandler = elicitationHandler;
|
||||
this.enableCallToolSchemaCaching = enableCallToolSchemaCaching;
|
||||
this.applyElicitationDefaults = applyElicitationDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -135,7 +142,7 @@ class McpClientFeatures {
|
|||
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler) {
|
||||
this(clientInfo, clientCapabilities, roots, toolsChangeConsumers, resourcesChangeConsumers,
|
||||
resourcesUpdateConsumers, promptsChangeConsumers, loggingConsumers, List.of(), samplingHandler,
|
||||
elicitationHandler, false);
|
||||
elicitationHandler, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -194,7 +201,7 @@ class McpClientFeatures {
|
|||
return new Async(syncSpec.clientInfo(), syncSpec.clientCapabilities(), syncSpec.roots(),
|
||||
toolsChangeConsumers, resourcesChangeConsumers, resourcesUpdateConsumers, promptsChangeConsumers,
|
||||
loggingConsumers, progressConsumers, samplingHandler, elicitationHandler,
|
||||
syncSpec.enableCallToolSchemaCaching);
|
||||
syncSpec.enableCallToolSchemaCaching, syncSpec.applyElicitationDefaults);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,6 +220,9 @@ class McpClientFeatures {
|
|||
* @param samplingHandler the sampling handler.
|
||||
* @param elicitationHandler the elicitation handler.
|
||||
* @param enableCallToolSchemaCaching whether to enable call tool schema caching.
|
||||
* @param applyElicitationDefaults whether the client should fill in missing fields of
|
||||
* an accepted {@code ElicitResult.content} with the {@code default} values declared
|
||||
* in the {@code requestedSchema}.
|
||||
*/
|
||||
public record Sync(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
|
||||
Map<String, McpSchema.Root> roots, List<Consumer<List<McpSchema.Tool>>> toolsChangeConsumers,
|
||||
|
|
@ -223,7 +233,7 @@ class McpClientFeatures {
|
|||
List<Consumer<McpSchema.ProgressNotification>> progressConsumers,
|
||||
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler,
|
||||
Function<McpSchema.ElicitRequest, McpSchema.ElicitResult> elicitationHandler,
|
||||
boolean enableCallToolSchemaCaching) {
|
||||
boolean enableCallToolSchemaCaching, boolean applyElicitationDefaults) {
|
||||
|
||||
/**
|
||||
* Create an instance and validate the arguments.
|
||||
|
|
@ -239,6 +249,9 @@ class McpClientFeatures {
|
|||
* @param samplingHandler the sampling handler.
|
||||
* @param elicitationHandler the elicitation handler.
|
||||
* @param enableCallToolSchemaCaching whether to enable call tool schema caching.
|
||||
* @param applyElicitationDefaults whether the client should fill in missing
|
||||
* fields of an accepted {@code ElicitResult.content} with the {@code default}
|
||||
* values declared in the {@code requestedSchema}.
|
||||
*/
|
||||
public Sync(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
|
||||
Map<String, McpSchema.Root> roots, List<Consumer<List<McpSchema.Tool>>> toolsChangeConsumers,
|
||||
|
|
@ -249,7 +262,7 @@ class McpClientFeatures {
|
|||
List<Consumer<McpSchema.ProgressNotification>> progressConsumers,
|
||||
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler,
|
||||
Function<McpSchema.ElicitRequest, McpSchema.ElicitResult> elicitationHandler,
|
||||
boolean enableCallToolSchemaCaching) {
|
||||
boolean enableCallToolSchemaCaching, boolean applyElicitationDefaults) {
|
||||
|
||||
Assert.notNull(clientInfo, "Client info must not be null");
|
||||
this.clientInfo = clientInfo;
|
||||
|
|
@ -270,6 +283,7 @@ class McpClientFeatures {
|
|||
this.samplingHandler = samplingHandler;
|
||||
this.elicitationHandler = elicitationHandler;
|
||||
this.enableCallToolSchemaCaching = enableCallToolSchemaCaching;
|
||||
this.applyElicitationDefaults = applyElicitationDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -285,7 +299,7 @@ class McpClientFeatures {
|
|||
Function<McpSchema.ElicitRequest, McpSchema.ElicitResult> elicitationHandler) {
|
||||
this(clientInfo, clientCapabilities, roots, toolsChangeConsumers, resourcesChangeConsumers,
|
||||
resourcesUpdateConsumers, promptsChangeConsumers, loggingConsumers, List.of(), samplingHandler,
|
||||
elicitationHandler, false);
|
||||
elicitationHandler, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2024-2026 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link McpAsyncClient#applyElicitationDefaults(Map, Map)}.
|
||||
*
|
||||
* Verifies that the client-side default application logic correctly fills in missing
|
||||
* fields from schema defaults, matching the behavior specified in SEP-1034.
|
||||
*/
|
||||
class McpAsyncClientElicitationDefaultsTests {
|
||||
|
||||
@Test
|
||||
void appliesStringDefault() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("name", Map.of("type", "string", "default", "Guest")));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("name", "Guest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesNumberDefault() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("age", Map.of("type", "integer", "default", 18)));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("age", 18);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesBooleanDefault() {
|
||||
Map<String, Object> schema = Map.of("properties",
|
||||
Map.of("subscribe", Map.of("type", "boolean", "default", true)));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("subscribe", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesEnumDefault() {
|
||||
Map<String, Object> schema = Map.of("properties",
|
||||
Map.of("color", Map.of("type", "string", "enum", List.of("red", "green"), "default", "green")));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("color", "green");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotOverrideExistingValues() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("name", Map.of("type", "string", "default", "Guest")));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
content.put("name", "Alice");
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("name", "Alice");
|
||||
}
|
||||
|
||||
@Test
|
||||
void skipsPropertiesWithoutDefault() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("email", Map.of("type", "string")));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).doesNotContainKey("email");
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesMultipleDefaults() {
|
||||
Map<String, Object> schema = Map.of("properties",
|
||||
Map.of("name", Map.of("type", "string", "default", "Guest"), "age",
|
||||
Map.of("type", "integer", "default", 18), "subscribe",
|
||||
Map.of("type", "boolean", "default", true), "color",
|
||||
Map.of("type", "string", "enum", List.of("red", "green"), "default", "green")));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("name", "Guest")
|
||||
.containsEntry("age", 18)
|
||||
.containsEntry("subscribe", true)
|
||||
.containsEntry("color", "green");
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesNullSchema() {
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(null, content);
|
||||
|
||||
assertThat(content).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesNullContent() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("name", Map.of("type", "string", "default", "Guest")));
|
||||
|
||||
// Should not throw
|
||||
McpAsyncClient.applyElicitationDefaults(schema, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesSchemaWithoutProperties() {
|
||||
Map<String, Object> schema = Map.of("type", "object");
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesDefaultsOnlyToMissingFields() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("name", Map.of("type", "string", "default", "Guest"),
|
||||
"age", Map.of("type", "integer", "default", 18)));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
content.put("name", "John");
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("name", "John").containsEntry("age", 18);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesFloatingPointDefault() {
|
||||
Map<String, Object> schema = Map.of("properties", Map.of("score", Map.of("type", "number", "default", 95.5)));
|
||||
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
McpAsyncClient.applyElicitationDefaults(schema, content);
|
||||
|
||||
assertThat(content).containsEntry("score", 95.5);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue