@@ -453,6 +453,7 @@ impl ErrorCode {
453453 pub const INVALID_PARAMS : Self = Self ( -32602 ) ;
454454 pub const INTERNAL_ERROR : Self = Self ( -32603 ) ;
455455 pub const PARSE_ERROR : Self = Self ( -32700 ) ;
456+ pub const URL_ELICITATION_REQUIRED : Self = Self ( -32042 ) ;
456457}
457458
458459/// Error information for JSON-RPC error responses.
@@ -504,6 +505,12 @@ impl ErrorData {
504505 pub fn internal_error ( message : impl Into < Cow < ' static , str > > , data : Option < Value > ) -> Self {
505506 Self :: new ( ErrorCode :: INTERNAL_ERROR , message, data)
506507 }
508+ pub fn url_elicitation_required (
509+ message : impl Into < Cow < ' static , str > > ,
510+ data : Option < Value > ,
511+ ) -> Self {
512+ Self :: new ( ErrorCode :: URL_ELICITATION_REQUIRED , message, data)
513+ }
507514}
508515
509516/// Represents any JSON-RPC message that can be sent or received.
@@ -1447,6 +1454,7 @@ pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNoti
14471454// Elicitation allows servers to request interactive input from users during tool execution.
14481455const_string ! ( ElicitationCreateRequestMethod = "elicitation/create" ) ;
14491456const_string ! ( ElicitationResponseNotificationMethod = "notifications/elicitation/response" ) ;
1457+ const_string ! ( ElicitationCompletionNotificationMethod = "notifications/elicitation/complete" ) ;
14501458
14511459/// Represents the possible actions a user can take in response to an elicitation request.
14521460///
@@ -1466,38 +1474,121 @@ pub enum ElicitationAction {
14661474 Cancel ,
14671475}
14681476
1477+ /// Helper enum for deserializing CreateElicitationRequestParam with backward compatibility.
1478+ /// When mode is missing, it defaults to FormElicitationParam.
1479+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq ) ]
1480+ #[ serde( tag = "mode" ) ]
1481+ #[ cfg_attr( feature = "schemars" , derive( schemars:: JsonSchema ) ) ]
1482+ enum CreateElicitationRequestParamDeserializeHelper {
1483+ #[ serde( rename = "form" , rename_all = "camelCase" ) ]
1484+ FormElicitationParam {
1485+ message : String ,
1486+ requested_schema : ElicitationSchema ,
1487+ } ,
1488+ #[ serde( rename = "url" , rename_all = "camelCase" ) ]
1489+ UrlElicitationParam {
1490+ message : String ,
1491+ url : String ,
1492+ elicitation_id : String ,
1493+ } ,
1494+ #[ serde( untagged, rename_all = "camelCase" ) ]
1495+ FormElicitationParamBackwardsCompat {
1496+ message : String ,
1497+ requested_schema : ElicitationSchema ,
1498+ } ,
1499+ }
1500+
1501+ impl TryFrom < CreateElicitationRequestParamDeserializeHelper > for CreateElicitationRequestParam {
1502+ type Error = serde_json:: Error ;
1503+
1504+ fn try_from (
1505+ value : CreateElicitationRequestParamDeserializeHelper ,
1506+ ) -> Result < Self , Self :: Error > {
1507+ match value {
1508+ CreateElicitationRequestParamDeserializeHelper :: FormElicitationParam {
1509+ message,
1510+ requested_schema,
1511+ }
1512+ | CreateElicitationRequestParamDeserializeHelper :: FormElicitationParamBackwardsCompat {
1513+ message,
1514+ requested_schema,
1515+ } => Ok ( CreateElicitationRequestParam :: FormElicitationParam {
1516+ message,
1517+ requested_schema,
1518+ } ) ,
1519+ CreateElicitationRequestParamDeserializeHelper :: UrlElicitationParam {
1520+ message,
1521+ url,
1522+ elicitation_id,
1523+ } => Ok ( CreateElicitationRequestParam :: UrlElicitationParam {
1524+ message,
1525+ url,
1526+ elicitation_id,
1527+ } ) ,
1528+ }
1529+ }
1530+ }
1531+
14691532/// Parameters for creating an elicitation request to gather user input.
14701533///
14711534/// This structure contains everything needed to request interactive input from a user:
14721535/// - A human-readable message explaining what information is needed
14731536/// - A type-safe schema defining the expected structure of the response
14741537///
14751538/// # Example
1476- ///
1539+ /// 1. Form-based elicitation request
14771540/// ```rust
14781541/// use rmcp::model::*;
14791542///
1480- /// let params = CreateElicitationRequestParam {
1543+ /// let params = CreateElicitationRequestParam::FormElicitationParam {
14811544/// message: "Please provide your email".to_string(),
14821545/// requested_schema: ElicitationSchema::builder()
14831546/// .required_email("email")
14841547/// .build()
14851548/// .unwrap(),
14861549/// };
14871550/// ```
1551+ /// 2. URL-based elicitation request
1552+ /// ```rust
1553+ /// use rmcp::model::*;
1554+ /// let params = CreateElicitationRequestParam::UrlElicitationParam {
1555+ /// message: "Please provide your feedback at the following URL".to_string(),
1556+ /// url: "https://example.com/feedback".to_string(),
1557+ /// elicitation_id: "unique-id-123".to_string(),
1558+ /// };
1559+ /// ```
14881560#[ derive( Debug , Serialize , Deserialize , Clone , PartialEq ) ]
1489- #[ serde( rename_all = "camelCase" ) ]
1561+ #[ serde(
1562+ tag = "mode" ,
1563+ try_from = "CreateElicitationRequestParamDeserializeHelper"
1564+ ) ]
14901565#[ cfg_attr( feature = "schemars" , derive( schemars:: JsonSchema ) ) ]
1491- pub struct CreateElicitationRequestParam {
1492- /// Human-readable message explaining what input is needed from the user.
1493- /// This should be clear and provide sufficient context for the user to understand
1494- /// what information they need to provide.
1495- pub message : String ,
1496-
1497- /// Type-safe schema defining the expected structure and validation rules for the user's response.
1498- /// This enforces the MCP 2025-06-18 specification that elicitation schemas must be objects
1499- /// with primitive-typed properties.
1500- pub requested_schema : ElicitationSchema ,
1566+ pub enum CreateElicitationRequestParam {
1567+ #[ serde( rename = "form" , rename_all = "camelCase" ) ]
1568+ FormElicitationParam {
1569+ /// Human-readable message explaining what input is needed from the user.
1570+ /// This should be clear and provide sufficient context for the user to understand
1571+ /// what information they need to provide.
1572+ message : String ,
1573+
1574+ /// Type-safe schema defining the expected structure and validation rules for the user's response.
1575+ /// This enforces the MCP 2025-06-18 specification that elicitation schemas must be objects
1576+ /// with primitive-typed properties.
1577+ requested_schema : ElicitationSchema ,
1578+ } ,
1579+ #[ serde( rename = "url" , rename_all = "camelCase" ) ]
1580+ UrlElicitationParam {
1581+ /// Human-readable message explaining what input is needed from the user.
1582+ /// This should be clear and provide sufficient context for the user to understand
1583+ /// what information they need to provide.
1584+ message : String ,
1585+
1586+ /// The URL where the user can provide the requested information.
1587+ /// The client should direct the user to this URL to complete the elicitation.
1588+ url : String ,
1589+ /// The unique identifier for this elicitation request.
1590+ elicitation_id : String ,
1591+ } ,
15011592}
15021593
15031594/// The result returned by a client in response to an elicitation request.
@@ -1522,6 +1613,18 @@ pub struct CreateElicitationResult {
15221613pub type CreateElicitationRequest =
15231614 Request < ElicitationCreateRequestMethod , CreateElicitationRequestParam > ;
15241615
1616+ /// Notification parameters for an url elicitation completion notification.
1617+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq ) ]
1618+ #[ serde( rename_all = "camelCase" ) ]
1619+ #[ cfg_attr( feature = "schemars" , derive( schemars:: JsonSchema ) ) ]
1620+ pub struct ElicitationResponseNotificationParam {
1621+ pub elicitation_id : String ,
1622+ }
1623+
1624+ /// Notification sent when an url elicitation process is completed.
1625+ pub type ElicitationCompletionNotification =
1626+ Notification < ElicitationCompletionNotificationMethod , ElicitationResponseNotificationParam > ;
1627+
15251628// =============================================================================
15261629// TOOL EXECUTION RESULTS
15271630// =============================================================================
@@ -1945,6 +2048,7 @@ ts_union!(
19452048 | ResourceListChangedNotification
19462049 | ToolListChangedNotification
19472050 | PromptListChangedNotification
2051+ | ElicitationCompletionNotification
19482052 | CustomNotification ;
19492053) ;
19502054
@@ -2446,4 +2550,124 @@ mod tests {
24462550 assert_eq ! ( json[ "serverInfo" ] [ "icons" ] [ 0 ] [ "sizes" ] [ 0 ] , "48x48" ) ;
24472551 assert_eq ! ( json[ "serverInfo" ] [ "websiteUrl" ] , "https://docs.example.com" ) ;
24482552 }
2553+
2554+ #[ test]
2555+ fn test_elicitation_deserialization_untagged ( ) {
2556+ // Test deserialization without the "type" field (should default to FormElicitationParam)
2557+ let json_data_without_tag = json ! ( {
2558+ "message" : "Please provide more details." ,
2559+ "requestedSchema" : {
2560+ "title" : "User Details" ,
2561+ "type" : "object" ,
2562+ "properties" : {
2563+ "name" : { "type" : "string" } ,
2564+ "age" : { "type" : "integer" }
2565+ } ,
2566+ "required" : [ "name" , "age" ]
2567+ }
2568+ } ) ;
2569+ let elicitation: CreateElicitationRequestParam =
2570+ serde_json:: from_value ( json_data_without_tag) . expect ( "Deserialization failed" ) ;
2571+ if let CreateElicitationRequestParam :: FormElicitationParam {
2572+ message,
2573+ requested_schema,
2574+ } = elicitation
2575+ {
2576+ assert_eq ! ( message, "Please provide more details." ) ;
2577+ assert_eq ! ( requested_schema. title, Some ( Cow :: from( "User Details" ) ) ) ;
2578+ assert_eq ! ( requested_schema. type_, ObjectTypeConst ) ;
2579+ } else {
2580+ panic ! ( "Expected FormElicitationParam" ) ;
2581+ }
2582+ }
2583+
2584+ #[ test]
2585+ fn test_elicitation_deserialization ( ) {
2586+ let json_data_form = json ! ( {
2587+ "mode" : "form" ,
2588+ "message" : "Please provide more details." ,
2589+ "requestedSchema" : {
2590+ "title" : "User Details" ,
2591+ "type" : "object" ,
2592+ "properties" : {
2593+ "name" : { "type" : "string" } ,
2594+ "age" : { "type" : "integer" }
2595+ } ,
2596+ "required" : [ "name" , "age" ]
2597+ }
2598+ } ) ;
2599+ let elicitation_form: CreateElicitationRequestParam =
2600+ serde_json:: from_value ( json_data_form) . expect ( "Deserialization failed" ) ;
2601+ if let CreateElicitationRequestParam :: FormElicitationParam {
2602+ message,
2603+ requested_schema,
2604+ } = elicitation_form
2605+ {
2606+ assert_eq ! ( message, "Please provide more details." ) ;
2607+ assert_eq ! ( requested_schema. title, Some ( Cow :: from( "User Details" ) ) ) ;
2608+ assert_eq ! ( requested_schema. type_, ObjectTypeConst ) ;
2609+ } else {
2610+ panic ! ( "Expected FormElicitationParam" ) ;
2611+ }
2612+
2613+ let json_data_url = json ! ( {
2614+ "mode" : "url" ,
2615+ "message" : "Please fill out the form at the following URL." ,
2616+ "url" : "https://example.com/form" ,
2617+ "elicitationId" : "elicitation-123"
2618+ } ) ;
2619+ let elicitation_url: CreateElicitationRequestParam =
2620+ serde_json:: from_value ( json_data_url) . expect ( "Deserialization failed" ) ;
2621+ if let CreateElicitationRequestParam :: UrlElicitationParam {
2622+ message,
2623+ url,
2624+ elicitation_id,
2625+ } = elicitation_url
2626+ {
2627+ assert_eq ! ( message, "Please fill out the form at the following URL." ) ;
2628+ assert_eq ! ( url, "https://example.com/form" ) ;
2629+ assert_eq ! ( elicitation_id, "elicitation-123" ) ;
2630+ } else {
2631+ panic ! ( "Expected UrlElicitationParam" ) ;
2632+ }
2633+ }
2634+
2635+ #[ test]
2636+ fn test_elicitation_serialization ( ) {
2637+ let form_elicitation = CreateElicitationRequestParam :: FormElicitationParam {
2638+ message : "Please provide more details." . to_string ( ) ,
2639+ requested_schema : ElicitationSchema :: builder ( )
2640+ . title ( "User Details" )
2641+ . string_property ( "name" , |s| s)
2642+ . build ( )
2643+ . expect ( "Valid schema" ) ,
2644+ } ;
2645+ let json_form = serde_json:: to_value ( & form_elicitation) . expect ( "Serialization failed" ) ;
2646+ let expected_form_json = json ! ( {
2647+ "mode" : "form" ,
2648+ "message" : "Please provide more details." ,
2649+ "requestedSchema" : {
2650+ "title" : "User Details" ,
2651+ "type" : "object" ,
2652+ "properties" : {
2653+ "name" : { "type" : "string" } ,
2654+ } ,
2655+ }
2656+ } ) ;
2657+ assert_eq ! ( json_form, expected_form_json) ;
2658+
2659+ let url_elicitation = CreateElicitationRequestParam :: UrlElicitationParam {
2660+ message : "Please fill out the form at the following URL." . to_string ( ) ,
2661+ url : "https://example.com/form" . to_string ( ) ,
2662+ elicitation_id : "elicitation-123" . to_string ( ) ,
2663+ } ;
2664+ let json_url = serde_json:: to_value ( & url_elicitation) . expect ( "Serialization failed" ) ;
2665+ let expected_url_json = json ! ( {
2666+ "mode" : "url" ,
2667+ "message" : "Please fill out the form at the following URL." ,
2668+ "url" : "https://example.com/form" ,
2669+ "elicitationId" : "elicitation-123"
2670+ } ) ;
2671+ assert_eq ! ( json_url, expected_url_json) ;
2672+ }
24492673}
0 commit comments