Skip to content

Commit f939dd1

Browse files
committed
feat: implement Elicitation support for MCP 2025-06-18
Add complete Elicitation functionality enabling interactive user input workflows: - Add ElicitationAction enum (Accept/Reject/Cancel) - Add CreateElicitationRequestParam and CreateElicitationResult structs - Integrate elicitation into JSON-RPC pipeline and union types - Add elicitation capability to ServerCapabilities with builder support - Implement client handler create_elicitation method - Add server peer create_elicitation request method - Add comprehensive tests covering spec compliance and serialization This implementation provides 100% compliance with MCP 2025-06-18 Elicitation specification, enabling servers to request structured user input during tool execution workflows.
1 parent b9d7d61 commit f939dd1

File tree

6 files changed

+381
-4
lines changed

6 files changed

+381
-4
lines changed

crates/rmcp/src/handler/client.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ impl<H: ClientHandler> Service<RoleClient> for H {
2121
.list_roots(context)
2222
.await
2323
.map(ClientResult::ListRootsResult),
24+
ServerRequest::CreateElicitationRequest(request) => self
25+
.create_elicitation(request.params, context)
26+
.await
27+
.map(ClientResult::CreateElicitationResult),
2428
}
2529
}
2630

@@ -86,6 +90,16 @@ pub trait ClientHandler: Sized + Send + Sync + 'static {
8690
std::future::ready(Ok(ListRootsResult::default()))
8791
}
8892

93+
fn create_elicitation(
94+
&self,
95+
params: CreateElicitationRequestParam,
96+
context: RequestContext<RoleClient>,
97+
) -> impl Future<Output = Result<CreateElicitationResult, McpError>> + Send + '_ {
98+
std::future::ready(Err(
99+
McpError::method_not_found::<CreateElicitationRequestMethod>(),
100+
))
101+
}
102+
89103
fn on_cancelled(
90104
&self,
91105
params: CancelledNotificationParam,

crates/rmcp/src/model.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,51 @@ pub struct ListRootsResult {
11761176
const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
11771177
pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
11781178

1179+
// =============================================================================
1180+
// ELICITATION (MCP 2025-06-18)
1181+
// =============================================================================
1182+
1183+
/// Elicitation action types representing user responses
1184+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1185+
#[serde(rename_all = "lowercase")]
1186+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1187+
pub enum ElicitationAction {
1188+
/// User clicked "Submit", "OK", "Confirm", etc.
1189+
Accept,
1190+
/// User explicitly rejected the request - clicked "Reject", "Decline", "No", etc.
1191+
Reject,
1192+
/// User dismissed without making an explicit choice - closed dialog, clicked outside, pressed Escape, etc.
1193+
Cancel,
1194+
}
1195+
1196+
const_string!(CreateElicitationRequestMethod = "elicitation/create");
1197+
1198+
/// Parameters for creating an elicitation request
1199+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1200+
#[serde(rename_all = "camelCase")]
1201+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1202+
pub struct CreateElicitationRequestParam {
1203+
/// User-facing description of what information is being requested
1204+
pub message: String,
1205+
/// JSON Schema defining the structure and constraints for the requested data
1206+
pub requested_schema: serde_json::Value,
1207+
}
1208+
1209+
/// Request to create an elicitation (server to client)
1210+
pub type CreateElicitationRequest = Request<CreateElicitationRequestMethod, CreateElicitationRequestParam>;
1211+
1212+
/// Result of an elicitation request
1213+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1214+
#[serde(rename_all = "camelCase")]
1215+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1216+
pub struct CreateElicitationResult {
1217+
/// The action taken by the user
1218+
pub action: ElicitationAction,
1219+
/// Optional data provided by user (only present when action is Accept)
1220+
#[serde(skip_serializing_if = "Option::is_none")]
1221+
pub content: Option<serde_json::Value>,
1222+
}
1223+
11791224
// =============================================================================
11801225
// TOOL EXECUTION RESULTS
11811226
// =============================================================================
@@ -1318,7 +1363,7 @@ ts_union!(
13181363
);
13191364

13201365
ts_union!(
1321-
export type ClientResult = CreateMessageResult | ListRootsResult | EmptyResult;
1366+
export type ClientResult = CreateMessageResult | ListRootsResult | CreateElicitationResult | EmptyResult;
13221367
);
13231368

13241369
impl ClientResult {
@@ -1333,7 +1378,8 @@ ts_union!(
13331378
export type ServerRequest =
13341379
| PingRequest
13351380
| CreateMessageRequest
1336-
| ListRootsRequest;
1381+
| ListRootsRequest
1382+
| CreateElicitationRequest;
13371383
);
13381384

13391385
ts_union!(

crates/rmcp/src/model/capabilities.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ pub struct RootsCapabilities {
3939
pub list_changed: Option<bool>,
4040
}
4141

42+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
43+
#[serde(rename_all = "camelCase")]
44+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
45+
pub struct ElicitationCapability {}
46+
4247
///
4348
/// # Builder
4449
/// ```rust
@@ -89,6 +94,8 @@ pub struct ServerCapabilities {
8994
pub resources: Option<ResourcesCapability>,
9095
#[serde(skip_serializing_if = "Option::is_none")]
9196
pub tools: Option<ToolsCapability>,
97+
#[serde(skip_serializing_if = "Option::is_none")]
98+
pub elicitation: Option<ElicitationCapability>,
9299
}
93100

94101
macro_rules! builder {
@@ -203,7 +210,8 @@ builder! {
203210
completions: JsonObject,
204211
prompts: PromptsCapability,
205212
resources: ResourcesCapability,
206-
tools: ToolsCapability
213+
tools: ToolsCapability,
214+
elicitation: ElicitationCapability
207215
}
208216
}
209217

crates/rmcp/src/model/meta.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ variant_extension! {
7474
PingRequest
7575
CreateMessageRequest
7676
ListRootsRequest
77+
CreateElicitationRequest
7778
}
7879
}
7980

crates/rmcp/src/service/server.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use thiserror::Error;
55
use super::*;
66
use crate::model::{
77
CancelledNotification, CancelledNotificationParam, ClientInfo, ClientJsonRpcMessage,
8-
ClientNotification, ClientRequest, ClientResult, CreateMessageRequest,
8+
ClientNotification, ClientRequest, ClientResult, CreateElicitationRequest,
9+
CreateElicitationRequestParam, CreateElicitationResult, CreateMessageRequest,
910
CreateMessageRequestParam, CreateMessageResult, ErrorData, ListRootsRequest, ListRootsResult,
1011
LoggingMessageNotification, LoggingMessageNotificationParam, ProgressNotification,
1112
ProgressNotificationParam, PromptListChangedNotification, ProtocolVersion,
@@ -317,6 +318,7 @@ macro_rules! method {
317318
impl Peer<RoleServer> {
318319
method!(peer_req create_message CreateMessageRequest(CreateMessageRequestParam) => CreateMessageResult);
319320
method!(peer_req list_roots ListRootsRequest() => ListRootsResult);
321+
method!(peer_req create_elicitation CreateElicitationRequest(CreateElicitationRequestParam) => CreateElicitationResult);
320322

321323
method!(peer_not notify_cancelled CancelledNotification(CancelledNotificationParam));
322324
method!(peer_not notify_progress ProgressNotification(ProgressNotificationParam));

0 commit comments

Comments
 (0)