Elicitation
Elicitation is a mechanism that allows a server to request additional information from the user during the execution of a tool, resource, or prompt. While traditional MCP interactions are client-initiated, elicitation enables a “reverse RPC” pattern where the server pauses execution to ask for missing data, confirmation, or credentials.
Key features include:
Server-Initiated: The server triggers the request via the
Contextobject.Asynchronous: Execution pauses until the user responds or the request times out.
Structured: Supports both form-based input (with JSON Schema validation) and URL-based redirects.
Server-side Elicitation
A server-side handler can initiate elicitation using the Server Context object’s elicit() method. This method is available in any async handler that accepts a Context&.
"request_user_info", "A tool that elicits user information via form-based elicitation",
tool_schema, [](Context& ctx, const nlohmann::json& args) -> Task<nlohmann::json> {
std::string task = args.at("task").get<std::string>();
std::cout << "Tool: Starting request_user_info for task: " << task << "\n";
ElicitRequestFormParams form_params;
form_params.mode = "form";
form_params.message = "Please provide your contact information";
form_params.requestedSchema = nlohmann::json{
{"type", "object"},
{"properties",
nlohmann::json{
{"name", nlohmann::json{{"type", "string"}, {"title", "Full Name"}}},
{"email", nlohmann::json{{"type", "string"}, {"title", "Email Address"}}},
{"priority",
nlohmann::json{{"type", "string"},
{"title", "Priority Level"},
{"enum", nlohmann::json::array({"low", "medium", "high"})}}}}},
{"required", nlohmann::json::array({"name", "email"})}};
std::cout << "Tool: Sending elicitation request\n";
ElicitRequestParams params = form_params;
auto result = co_await ctx.elicit(params);
std::cout << "Tool: Received elicitation result\n";
auto make_result = [](const std::string& text) {
return nlohmann::json{
{"content",
nlohmann::json::array(
{nlohmann::json{{"type", "text"}, {"text", text}}})}};
};
if (result.action == ElicitAction::eAccept) {
std::cout << "Tool: User accepted the form\n";
if (result.content) {
std::cout << "Tool: Form data: " << result.content->dump() << "\n";
co_return make_result("Accepted: task=" + task +
" info=" + result.content->dump());
}
co_return make_result("Accepted: task=" + task + " (no form data)");
} else if (result.action == ElicitAction::eDecline) {
std::cout << "Tool: User declined the form\n";
co_return make_result("Declined: task=" + task);
} else {
std::cout << "Tool: User cancelled the form\n";
co_return make_result("Cancelled: task=" + task);
}
});
The elicit() method takes an ElicitRequestParams object and returns a Task<ElicitResult>.
Form-based Elicitation
Form-based elicitation (ElicitRequestFormParams) allows the server to request specific data fields defined by a JSON Schema. The client is responsible for rendering an appropriate UI (e.g., a dialog with input fields) and validating the user’s input against the schema.
ElicitRequestFormParams form_params;
form_params.mode = "form";
form_params.message = "Please provide your contact information";
form_params.requestedSchema = nlohmann::json{
{"type", "object"},
{"properties", {
{"name", {{"type", "string"}, {"title", "Full Name"}}},
{"email", {{"type", "string"}, {"title", "Email Address"}}}
}},
{"required", nlohmann::json::array({"name", "email"})}
};
auto result = co_await ctx.elicit(form_params);
URL-based Elicitation
URL-based elicitation (ElicitRequestURLParams) is used when the user needs to perform an action on an external website, such as completing an OAuth flow or verifying their identity.
ElicitRequestURLParams url_params;
url_params.mode = "url";
url_params.message = "Please sign in to continue";
url_params.url = "https://auth.example.com/login?id=123";
url_params.elicitationId = "login-flow-456";
auto result = co_await ctx.elicit(url_params);
Client-side Handling
Clients must register a handler to respond to elicitation requests. The mcp::Client class provides a convenience method on_elicitation() for this purpose.
Implementation client_info;
client_info.name = "elicitation-client";
client_info.version = "1.0.0";
std::cout << "Client: Connecting to server\n";
auto init_result = co_await client.connect(client_info, ClientCapabilities{});
std::cout << "Client: Connected to " << init_result.serverInfo.name << "\n";
bool elicitation_received = false;
client.on_elicitation([&](const ElicitRequestParams& params) -> Task<ElicitResult> {
std::cout << "Client: Received elicitation request\n";
elicitation_received = true;
if (std::holds_alternative<ElicitRequestFormParams>(params)) {
auto form_params = std::get<ElicitRequestFormParams>(params);
std::cout << "Client: Form message: " << form_params.message << "\n";
std::cout << "Client: Form schema: " << form_params.requestedSchema.dump()
<< "\n";
nlohmann::json form_data = {{"name", "Alice Johnson"},
{"email", "alice@example.com"},
{"priority", "high"}};
std::cout << "Client: Submitting form with data: " << form_data.dump()
<< "\n";
ElicitResult result;
result.action = ElicitAction::eAccept;
result.content = form_data;
co_return result;
}
ElicitResult result;
result.action = ElicitAction::eDecline;
co_return result;
});
ElicitResult Actions
The ElicitResult returned by the client contains an action field of type ElicitAction:
ElicitAction::eAccept: The user provided the requested information or confirmed the action. For form-based elicitation, thecontentfield will contain the submitted data.ElicitAction::eDecline: The user explicitly refused to provide the information.ElicitAction::eCancel: The user dismissed the request without making a choice (e.g., closed a dialog).
The server should handle each of these cases to ensure a graceful user experience.
if (result.action == ElicitAction::eAccept) {
// Process result.content
} else if (result.action == ElicitAction::eDecline) {
// Handle refusal
} else if (result.action == ElicitAction::eCancel) {
// Handle cancellation
}
Example Walkthrough
The complete elicitation flow involves:
Server calls
ctx.elicit()within a tool handler.SDK sends an
elicitation/createrequest to the client.Client receives the request via its
on_elicitation()handler.Client presents a UI to the user and awaits their response.
Client returns an
ElicitResultto the server.Server resumes execution with the provided data or handles the refusal.
For a full working example, see examples/features/elicitation.cpp.
See Also
Server Context for more on reverse RPC capabilities.
Tools for tool registration and handlers.