feat: Add elicitation support to MCP protocol

Implement elicitation capabilities allowing servers to request additional information
from users through clients during interactions. This feature provides a standardized
way for servers to gather necessary information dynamically while clients maintain
control over user interactions and data sharing.

- Add ElicitRequest and ElicitResult classes to McpSchema
- Implement elicitation handlers in client classes
- Add elicitation capabilities to server exchange classes
- Add tests for elicitation functionality with various scenarios
This commit is contained in:
Luca Chang 2025-05-27 15:26:44 -07:00 • committed by Christian Tzolov
commit 8a5a591d39
6 changed files with 1106 additions and 28 deletions

View file

@ -23,6 +23,8 @@ import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;
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.spec.McpSchema.ListPromptsResult;
@ -141,6 +143,15 @@ public class McpAsyncClient {
*/
private Function<CreateMessageRequest, Mono<CreateMessageResult>> samplingHandler;
/**
* MCP provides a standardized way for servers to request additional information from
* users through the client during interactions. This flow allows clients to maintain
* control over user interactions and data sharing while enabling servers to gather
* necessary information dynamically. Servers can request structured data from users
* with optional JSON schemas to validate responses.
*/
private Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler;
/**
* Client transport implementation.
*/
@ -189,6 +200,15 @@ public class McpAsyncClient {
requestHandlers.put(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE, samplingCreateMessageHandler());
}
// Elicitation Handler
if (this.clientCapabilities.elicitation() != null) {
if (features.elicitationHandler() == null) {
throw new McpError("Elicitation handler must not be null when client capabilities include elicitation");
}
this.elicitationHandler = features.elicitationHandler();
requestHandlers.put(McpSchema.METHOD_ELICITATION_CREATE, elicitationCreateHandler());
}
// Notification Handlers
Map<String, NotificationHandler> notificationHandlers = new HashMap<>();
@ -500,6 +520,18 @@ public class McpAsyncClient {
};
}
// --------------------------
// Elicitation
// --------------------------
private RequestHandler<ElicitResult> elicitationCreateHandler() {
return params -> {
ElicitRequest request = transport.unmarshalFrom(params, new TypeReference<>() {
});
return this.elicitationHandler.apply(request);
};
}
// --------------------------
// Tools
// --------------------------

View file

@ -18,6 +18,8 @@ import io.modelcontextprotocol.spec.McpTransport;
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;
import io.modelcontextprotocol.spec.McpSchema.ElicitRequest;
import io.modelcontextprotocol.spec.McpSchema.ElicitResult;
import io.modelcontextprotocol.spec.McpSchema.Implementation;
import io.modelcontextprotocol.spec.McpSchema.Root;
import io.modelcontextprotocol.util.Assert;
@ -175,6 +177,8 @@ public interface McpClient {
private Function<CreateMessageRequest, CreateMessageResult> samplingHandler;
private Function<ElicitRequest, ElicitResult> elicitationHandler;
private SyncSpec(McpClientTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
@ -283,6 +287,21 @@ public interface McpClient {
return this;
}
/**
* Sets a custom elicitation handler for processing elicitation message requests.
* The elicitation handler can modify or validate messages before they are sent to
* the server, enabling custom processing logic.
* @param elicitationHandler A function that processes elicitation requests and
* returns results. Must not be null.
* @return This builder instance for method chaining
* @throws IllegalArgumentException if elicitationHandler is null
*/
public SyncSpec elicitation(Function<ElicitRequest, ElicitResult> elicitationHandler) {
Assert.notNull(elicitationHandler, "Elicitation handler must not be null");
this.elicitationHandler = elicitationHandler;
return this;
}
/**
* Adds a consumer to be notified when the available tools change. This allows the
* client to react to changes in the server's tool capabilities, such as tools
@ -364,7 +383,7 @@ public interface McpClient {
public McpSyncClient build() {
McpClientFeatures.Sync syncFeatures = new McpClientFeatures.Sync(this.clientInfo, this.capabilities,
this.roots, this.toolsChangeConsumers, this.resourcesChangeConsumers, this.promptsChangeConsumers,
this.loggingConsumers, this.samplingHandler);
this.loggingConsumers, this.samplingHandler, this.elicitationHandler);
McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures);
@ -414,6 +433,8 @@ public interface McpClient {
private Function<CreateMessageRequest, Mono<CreateMessageResult>> samplingHandler;
private Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler;
private AsyncSpec(McpClientTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
@ -522,6 +543,21 @@ public interface McpClient {
return this;
}
/**
* Sets a custom elicitation handler for processing elicitation message requests.
* The elicitation handler can modify or validate messages before they are sent to
* the server, enabling custom processing logic.
* @param elicitationHandler A function that processes elicitation requests and
* returns results. Must not be null.
* @return This builder instance for method chaining
* @throws IllegalArgumentException if elicitationHandler is null
*/
public AsyncSpec elicitation(Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler) {
Assert.notNull(elicitationHandler, "Elicitation handler must not be null");
this.elicitationHandler = elicitationHandler;
return this;
}
/**
* Adds a consumer to be notified when the available tools change. This allows the
* client to react to changes in the server's tool capabilities, such as tools
@ -606,7 +642,7 @@ public interface McpClient {
return new McpAsyncClient(this.transport, this.requestTimeout, this.initializationTimeout,
new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots,
this.toolsChangeConsumers, this.resourcesChangeConsumers, this.promptsChangeConsumers,
this.loggingConsumers, this.samplingHandler));
this.loggingConsumers, this.samplingHandler, this.elicitationHandler));
}
}

View file

@ -60,13 +60,15 @@ class McpClientFeatures {
* @param promptsChangeConsumers the prompts change consumers.
* @param loggingConsumers the logging consumers.
* @param samplingHandler the sampling handler.
* @param elicitationHandler the elicitation handler.
*/
record Async(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
Map<String, McpSchema.Root> roots, List<Function<List<McpSchema.Tool>, Mono<Void>>> toolsChangeConsumers,
List<Function<List<McpSchema.Resource>, Mono<Void>>> resourcesChangeConsumers,
List<Function<List<McpSchema.Prompt>, Mono<Void>>> promptsChangeConsumers,
List<Function<McpSchema.LoggingMessageNotification, Mono<Void>>> loggingConsumers,
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler) {
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler,
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler) {
/**
* Create an instance and validate the arguments.
@ -77,6 +79,7 @@ class McpClientFeatures {
* @param promptsChangeConsumers the prompts change consumers.
* @param loggingConsumers the logging consumers.
* @param samplingHandler the sampling handler.
* @param elicitationHandler the elicitation handler.
*/
public Async(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
Map<String, McpSchema.Root> roots,
@ -84,14 +87,16 @@ class McpClientFeatures {
List<Function<List<McpSchema.Resource>, Mono<Void>>> resourcesChangeConsumers,
List<Function<List<McpSchema.Prompt>, Mono<Void>>> promptsChangeConsumers,
List<Function<McpSchema.LoggingMessageNotification, Mono<Void>>> loggingConsumers,
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler) {
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler,
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler) {
Assert.notNull(clientInfo, "Client info must not be null");
this.clientInfo = clientInfo;
this.clientCapabilities = (clientCapabilities != null) ? clientCapabilities
: new McpSchema.ClientCapabilities(null,
!Utils.isEmpty(roots) ? new McpSchema.ClientCapabilities.RootCapabilities(false) : null,
samplingHandler != null ? new McpSchema.ClientCapabilities.Sampling() : null);
samplingHandler != null ? new McpSchema.ClientCapabilities.Sampling() : null,
elicitationHandler != null ? new McpSchema.ClientCapabilities.Elicitation() : null);
this.roots = roots != null ? new ConcurrentHashMap<>(roots) : new ConcurrentHashMap<>();
this.toolsChangeConsumers = toolsChangeConsumers != null ? toolsChangeConsumers : List.of();
@ -99,6 +104,7 @@ class McpClientFeatures {
this.promptsChangeConsumers = promptsChangeConsumers != null ? promptsChangeConsumers : List.of();
this.loggingConsumers = loggingConsumers != null ? loggingConsumers : List.of();
this.samplingHandler = samplingHandler;
this.elicitationHandler = elicitationHandler;
}
/**
@ -138,9 +144,14 @@ class McpClientFeatures {
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler = r -> Mono
.fromCallable(() -> syncSpec.samplingHandler().apply(r))
.subscribeOn(Schedulers.boundedElastic());
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler = r -> Mono
.fromCallable(() -> syncSpec.elicitationHandler().apply(r))
.subscribeOn(Schedulers.boundedElastic());
return new Async(syncSpec.clientInfo(), syncSpec.clientCapabilities(), syncSpec.roots(),
toolsChangeConsumers, resourcesChangeConsumers, promptsChangeConsumers, loggingConsumers,
samplingHandler);
samplingHandler, elicitationHandler);
}
}
@ -156,13 +167,15 @@ class McpClientFeatures {
* @param promptsChangeConsumers the prompts change consumers.
* @param loggingConsumers the logging consumers.
* @param samplingHandler the sampling handler.
* @param elicitationHandler the elicitation handler.
*/
public record Sync(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
Map<String, McpSchema.Root> roots, List<Consumer<List<McpSchema.Tool>>> toolsChangeConsumers,
List<Consumer<List<McpSchema.Resource>>> resourcesChangeConsumers,
List<Consumer<List<McpSchema.Prompt>>> promptsChangeConsumers,
List<Consumer<McpSchema.LoggingMessageNotification>> loggingConsumers,
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler) {
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler,
Function<McpSchema.ElicitRequest, McpSchema.ElicitResult> elicitationHandler) {
/**
* Create an instance and validate the arguments.
@ -174,20 +187,23 @@ class McpClientFeatures {
* @param promptsChangeConsumers the prompts change consumers.
* @param loggingConsumers the logging consumers.
* @param samplingHandler the sampling handler.
* @param elicitationHandler the elicitation handler.
*/
public Sync(McpSchema.Implementation clientInfo, McpSchema.ClientCapabilities clientCapabilities,
Map<String, McpSchema.Root> roots, List<Consumer<List<McpSchema.Tool>>> toolsChangeConsumers,
List<Consumer<List<McpSchema.Resource>>> resourcesChangeConsumers,
List<Consumer<List<McpSchema.Prompt>>> promptsChangeConsumers,
List<Consumer<McpSchema.LoggingMessageNotification>> loggingConsumers,
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler) {
Function<McpSchema.CreateMessageRequest, McpSchema.CreateMessageResult> samplingHandler,
Function<McpSchema.ElicitRequest, McpSchema.ElicitResult> elicitationHandler) {
Assert.notNull(clientInfo, "Client info must not be null");
this.clientInfo = clientInfo;
this.clientCapabilities = (clientCapabilities != null) ? clientCapabilities
: new McpSchema.ClientCapabilities(null,
!Utils.isEmpty(roots) ? new McpSchema.ClientCapabilities.RootCapabilities(false) : null,
samplingHandler != null ? new McpSchema.ClientCapabilities.Sampling() : null);
samplingHandler != null ? new McpSchema.ClientCapabilities.Sampling() : null,
elicitationHandler != null ? new McpSchema.ClientCapabilities.Elicitation() : null);
this.roots = roots != null ? new HashMap<>(roots) : new HashMap<>();
this.toolsChangeConsumers = toolsChangeConsumers != null ? toolsChangeConsumers : List.of();
@ -195,6 +211,7 @@ class McpClientFeatures {
this.promptsChangeConsumers = promptsChangeConsumers != null ? promptsChangeConsumers : List.of();
this.loggingConsumers = loggingConsumers != null ? loggingConsumers : List.of();
this.samplingHandler = samplingHandler;
this.elicitationHandler = elicitationHandler;
}
}

View file

@ -36,6 +36,9 @@ public class McpAsyncServerExchange {
private static final TypeReference<McpSchema.ListRootsResult> LIST_ROOTS_RESULT_TYPE_REF = new TypeReference<>() {
};
private static final TypeReference<McpSchema.ElicitResult> ELICITATION_RESULT_TYPE_REF = new TypeReference<>() {
};
/**
* Create a new asynchronous exchange with the client.
* @param session The server session representing a 1-1 interaction.
@ -93,6 +96,31 @@ public class McpAsyncServerExchange {
CREATE_MESSAGE_RESULT_TYPE_REF);
}
/**
* Creates a new elicitation. MCP provides a standardized way for servers to request
* additional information from users through the client during interactions. This flow
* allows clients to maintain control over user interactions and data sharing while
* enabling servers to gather necessary information dynamically. Servers can request
* structured data from users with optional JSON schemas to validate responses.
* @param elicitRequest The request to create a new elicitation
* @return A Mono that completes when the elicitation has been resolved.
* @see McpSchema.ElicitRequest
* @see McpSchema.ElicitResult
* @see <a href=
* "https://spec.modelcontextprotocol.io/specification/client/elicitation/">Elicitation
* Specification</a>
*/
public Mono<McpSchema.ElicitResult> createElicitation(McpSchema.ElicitRequest elicitRequest) {
if (this.clientCapabilities == null) {
return Mono.error(new McpError("Client must be initialized. Call the initialize method first!"));
}
if (this.clientCapabilities.elicitation() == null) {
return Mono.error(new McpError("Client must be configured with elicitation capabilities"));
}
return this.session.sendRequest(McpSchema.METHOD_ELICITATION_CREATE, elicitRequest,
ELICITATION_RESULT_TYPE_REF);
}
/**
* Retrieves the list of all roots provided by the client.
* @return A Mono that emits the list of roots result.

View file

@ -64,6 +64,24 @@ public class McpSyncServerExchange {
return this.exchange.createMessage(createMessageRequest).block();
}
/**
* Creates a new elicitation. MCP provides a standardized way for servers to request
* additional information from users through the client during interactions. This flow
* allows clients to maintain control over user interactions and data sharing while
* enabling servers to gather necessary information dynamically. Servers can request
* structured data from users with optional JSON schemas to validate responses.
* @param elicitRequest The request to create a new elicitation
* @return A result containing the elicitation response.
* @see McpSchema.ElicitRequest
* @see McpSchema.ElicitResult
* @see <a href=
* "https://spec.modelcontextprotocol.io/specification/client/elicitation/">Elicitation
* Specification</a>
*/
public McpSchema.ElicitResult createElicitation(McpSchema.ElicitRequest elicitRequest) {
return this.exchange.createElicitation(elicitRequest).block();
}
/**
* Retrieves the list of all roots provided by the client.
* @return The list of roots result.

View file

@ -94,6 +94,9 @@ public final class McpSchema {
// Sampling Methods
public static final String METHOD_SAMPLING_CREATE_MESSAGE = "sampling/createMessage";
// Elicitation Methods
public static final String METHOD_ELICITATION_CREATE = "elicitation/create";
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
// ---------------------------
@ -131,8 +134,8 @@ public final class McpSchema {
}
public sealed interface Request
permits InitializeRequest, CallToolRequest, CreateMessageRequest, CompleteRequest, GetPromptRequest {
public sealed interface Request permits InitializeRequest, CallToolRequest, CreateMessageRequest, ElicitRequest,
CompleteRequest, GetPromptRequest {
}
@ -221,7 +224,7 @@ public final class McpSchema {
public record InitializeRequest( // @formatter:off
@JsonProperty("protocolVersion") String protocolVersion,
@JsonProperty("capabilities") ClientCapabilities capabilities,
@JsonProperty("clientInfo") Implementation clientInfo) implements Request {
@JsonProperty("clientInfo") Implementation clientInfo) implements Request {
} // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@ -245,6 +248,8 @@ public final class McpSchema {
* access to.
* @param sampling Provides a standardized way for servers to request LLM sampling
* (“completions” or “generations”) from language models via clients.
* @param elicitation Provides a standardized way for servers to request additional
* information from users through the client during interactions.
*
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@ -252,7 +257,8 @@ public final class McpSchema {
public record ClientCapabilities( // @formatter:off
@JsonProperty("experimental") Map<String, Object> experimental,
@JsonProperty("roots") RootCapabilities roots,
@JsonProperty("sampling") Sampling sampling) {
@JsonProperty("sampling") Sampling sampling,
@JsonProperty("elicitation") Elicitation elicitation) {
/**
* Roots define the boundaries of where servers can operate within the filesystem,
@ -264,7 +270,7 @@ public final class McpSchema {
* has changed since the last time the server checked.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public record RootCapabilities(
@JsonProperty("listChanged") Boolean listChanged) {
}
@ -279,10 +285,22 @@ public final class McpSchema {
* image-based interactions and optionally include context
* from MCP servers in their prompts.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record Sampling() {
}
/**
* Provides a standardized way for servers to request additional
* information from users through the client during interactions.
* This flow allows clients to maintain control over user
* interactions and data sharing while enabling servers to gather
* necessary information dynamically. Servers can request structured
* data from users with optional JSON schemas to validate responses.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record Elicitation() {
}
public static Builder builder() {
return new Builder();
}
@ -291,6 +309,7 @@ public final class McpSchema {
private Map<String, Object> experimental;
private RootCapabilities roots;
private Sampling sampling;
private Elicitation elicitation;
public Builder experimental(Map<String, Object> experimental) {
this.experimental = experimental;
@ -307,8 +326,13 @@ public final class McpSchema {
return this;
}
public Builder elicitation() {
this.elicitation = new Elicitation();
return this;
}
public ClientCapabilities build() {
return new ClientCapabilities(experimental, roots, sampling);
return new ClientCapabilities(experimental, roots, sampling, elicitation);
}
}
}// @formatter:on
@ -326,11 +350,11 @@ public final class McpSchema {
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record CompletionCapabilities() {
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record LoggingCapabilities() {
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record PromptCapabilities(
@JsonProperty("listChanged") Boolean listChanged) {
@ -727,11 +751,11 @@ public final class McpSchema {
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("inputSchema") JsonSchema inputSchema) {
public Tool(String name, String description, String schema) {
this(name, description, parseSchema(schema));
}
} // @formatter:on
private static JsonSchema parseSchema(String schema) {
@ -758,7 +782,7 @@ public final class McpSchema {
@JsonProperty("arguments") Map<String, Object> arguments) implements Request {
public CallToolRequest(String name, String jsonArguments) {
this(name, parseJsonArguments(jsonArguments));
this(name, parseJsonArguments(jsonArguments));
}
private static Map<String, Object> parseJsonArguments(String jsonArguments) {
@ -893,7 +917,7 @@ public final class McpSchema {
@JsonProperty("costPriority") Double costPriority,
@JsonProperty("speedPriority") Double speedPriority,
@JsonProperty("intelligencePriority") Double intelligencePriority) {
public static Builder builder() {
return new Builder();
}
@ -963,7 +987,7 @@ public final class McpSchema {
@JsonProperty("includeContext") ContextInclusionStrategy includeContext,
@JsonProperty("temperature") Double temperature,
@JsonProperty("maxTokens") int maxTokens,
@JsonProperty("stopSequences") List<String> stopSequences,
@JsonProperty("stopSequences") List<String> stopSequences,
@JsonProperty("metadata") Map<String, Object> metadata) implements Request {
public enum ContextInclusionStrategy {
@ -971,7 +995,7 @@ public final class McpSchema {
@JsonProperty("thisServer") THIS_SERVER,
@JsonProperty("allServers") ALL_SERVERS
}
public static Builder builder() {
return new Builder();
}
@ -1040,7 +1064,7 @@ public final class McpSchema {
@JsonProperty("content") Content content,
@JsonProperty("model") String model,
@JsonProperty("stopReason") StopReason stopReason) {
public enum StopReason {
@JsonProperty("endTurn") END_TURN,
@JsonProperty("stopSequence") STOP_SEQUENCE,
@ -1088,6 +1112,79 @@ public final class McpSchema {
}
}// @formatter:on
// Elicitation
/**
* Used by the server to send an elicitation to the client.
*
* @param message The body of the elicitation message.
* @param requestedSchema The elicitation response schema that must be satisfied.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ElicitRequest(// @formatter:off
@JsonProperty("message") String message,
@JsonProperty("requestedSchema") Map<String, Object> requestedSchema) implements Request {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String message;
private Map<String, Object> requestedSchema;
public Builder message(String message) {
this.message = message;
return this;
}
public Builder requestedSchema(Map<String, Object> requestedSchema) {
this.requestedSchema = requestedSchema;
return this;
}
public ElicitRequest build() {
return new ElicitRequest(message, requestedSchema);
}
}
}// @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ElicitResult(// @formatter:off
@JsonProperty("action") Action action,
@JsonProperty("content") Map<String, Object> content) {
public enum Action {
@JsonProperty("accept") ACCEPT,
@JsonProperty("decline") DECLINE,
@JsonProperty("cancel") CANCEL
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Action action;
private Map<String, Object> content;
public Builder message(Action action) {
this.action = action;
return this;
}
public Builder content(Map<String, Object> content) {
this.content = content;
return this;
}
public ElicitResult build() {
return new ElicitResult(action, content);
}
}
}// @formatter:on
// ---------------------------
// Pagination Interfaces
// ---------------------------