Implement SEP-1319: Decouple Request Payload from RPC Methods (#617)

* feat: implement SEP-1319 Decouple Request Payload from RPC Methods

* test: update tests

* fix: update handler trait methods to use new types

* fix: update examples

* fix: correct deprecation version

* fix: update wrapper macros to use new *Params type names
This commit is contained in:
Dale Seo 2026-01-16 12:16:52 -05:00 • committed by GitHub
commit 9e881a645b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 913 additions and 278 deletions

View file

@ -49,7 +49,7 @@ impl TestClientHandler {
impl ClientHandler for TestClientHandler {
async fn create_message(
&self,
params: CreateMessageRequestParam,
params: CreateMessageRequestParams,
_context: RequestContext<RoleClient>,
) -> Result<CreateMessageResult, McpError> {
// First validate that there's at least one User message
@ -117,7 +117,7 @@ impl ServerHandler for TestServer {
fn set_level(
&self,
request: SetLevelRequestParam,
request: SetLevelRequestParams,
context: RequestContext<RoleServer>,
) -> impl Future<Output = Result<(), McpError>> + Send + '_ {
let peer = context.peer;

View file

@ -52,7 +52,8 @@ fn test_complete_request_param_serialization() {
let mut args = HashMap::new();
args.insert("previous_input".to_string(), "test".to_string());
let request = CompleteRequestParam {
let request = CompleteRequestParams {
meta: None,
r#ref: Reference::for_prompt("weather_prompt"),
argument: ArgumentInfo {
name: "location".to_string(),
@ -195,7 +196,8 @@ fn test_completion_context_empty() {
#[test]
fn test_mcp_schema_compliance() {
// Test that our types serialize correctly according to MCP specification
let request = CompleteRequestParam {
let request = CompleteRequestParams {
meta: None,
r#ref: Reference::for_resource("file://{path}"),
argument: ArgumentInfo {
name: "path".to_string(),

View file

@ -36,7 +36,7 @@ async fn test_elicitation_serialization() {
);
}
/// Test CreateElicitationRequestParam structure serialization/deserialization
/// Test CreateElicitationRequestParams structure serialization/deserialization
#[tokio::test]
async fn test_elicitation_request_param_serialization() {
let schema = ElicitationSchema::builder()
@ -44,7 +44,8 @@ async fn test_elicitation_request_param_serialization() {
.build()
.unwrap();
let request_param = CreateElicitationRequestParam {
let request_param = CreateElicitationRequestParams {
meta: None,
message: "Please provide your email address".to_string(),
requested_schema: schema,
};
@ -68,7 +69,7 @@ async fn test_elicitation_request_param_serialization() {
assert_eq!(json, expected);
// Test deserialization
let deserialized: CreateElicitationRequestParam = serde_json::from_value(expected).unwrap();
let deserialized: CreateElicitationRequestParams = serde_json::from_value(expected).unwrap();
assert_eq!(deserialized.message, request_param.message);
assert_eq!(
deserialized.requested_schema,
@ -128,7 +129,8 @@ async fn test_elicitation_json_rpc_protocol() {
id: RequestId::Number(1),
request: CreateElicitationRequest {
method: ElicitationCreateRequestMethod,
params: CreateElicitationRequestParam {
params: CreateElicitationRequestParams {
meta: None,
message: "Do you want to continue?".to_string(),
requested_schema: schema,
},
@ -212,7 +214,8 @@ async fn test_elicitation_spec_compliance() {
#[tokio::test]
async fn test_elicitation_error_handling() {
// Test minimal schema handling (empty properties is technically valid)
let minimal_schema_request = CreateElicitationRequestParam {
let minimal_schema_request = CreateElicitationRequestParams {
meta: None,
message: "Test message".to_string(),
requested_schema: ElicitationSchema::builder().build().unwrap(),
};
@ -221,7 +224,8 @@ async fn test_elicitation_error_handling() {
let _json = serde_json::to_value(&minimal_schema_request).unwrap();
// Test empty message
let empty_message_request = CreateElicitationRequestParam {
let empty_message_request = CreateElicitationRequestParams {
meta: None,
message: "".to_string(),
requested_schema: ElicitationSchema::builder()
.property("value", PrimitiveSchema::String(StringSchema::new()))
@ -246,7 +250,8 @@ async fn test_elicitation_performance() {
.build()
.unwrap();
let request = CreateElicitationRequestParam {
let request = CreateElicitationRequestParams {
meta: None,
message: "Performance test message".to_string(),
requested_schema: schema,
};
@ -256,7 +261,7 @@ async fn test_elicitation_performance() {
// Serialize/deserialize 1000 times
for _ in 0..1000 {
let json = serde_json::to_value(&request).unwrap();
let _deserialized: CreateElicitationRequestParam = serde_json::from_value(json).unwrap();
let _deserialized: CreateElicitationRequestParams = serde_json::from_value(json).unwrap();
}
let duration = start.elapsed();
@ -369,8 +374,9 @@ async fn test_elicitation_convenience_methods() {
.contains("Option A")
);
// Test that CreateElicitationRequestParam can be created with type-safe schemas
let confirmation_request = CreateElicitationRequestParam {
// Test that CreateElicitationRequestParams can be created with type-safe schemas
let confirmation_request = CreateElicitationRequestParams {
meta: None,
message: "Test confirmation".to_string(),
requested_schema: ElicitationSchema::builder()
.property(
@ -412,14 +418,15 @@ async fn test_elicitation_structured_schemas() {
.build()
.unwrap();
let request = CreateElicitationRequestParam {
let request = CreateElicitationRequestParams {
meta: None,
message: "Please provide your user information".to_string(),
requested_schema: schema,
};
// Test that complex schemas serialize/deserialize correctly
let json = serde_json::to_value(&request).unwrap();
let deserialized: CreateElicitationRequestParam = serde_json::from_value(json).unwrap();
let deserialized: CreateElicitationRequestParams = serde_json::from_value(json).unwrap();
assert_eq!(deserialized.message, "Please provide your user information");
assert_eq!(deserialized.requested_schema.properties.len(), 5);
@ -654,14 +661,15 @@ async fn test_elicitation_multi_select_enum() {
.build()
.unwrap();
let request = CreateElicitationRequestParam {
let request = CreateElicitationRequestParams {
meta: None,
message: "Please provide your user information".to_string(),
requested_schema: schema,
};
// Test that complex schemas serialize/deserialize correctly
let json = serde_json::to_value(&request).unwrap();
let deserialized: CreateElicitationRequestParam = serde_json::from_value(json).unwrap();
let deserialized: CreateElicitationRequestParams = serde_json::from_value(json).unwrap();
assert_eq!(deserialized.message, "Please provide your user information");
assert_eq!(deserialized.requested_schema.properties.len(), 1);
@ -735,14 +743,15 @@ async fn test_elicitation_single_select_enum() {
.build()
.unwrap();
let request = CreateElicitationRequestParam {
let request = CreateElicitationRequestParams {
meta: None,
message: "Please provide your user information".to_string(),
requested_schema: schema,
};
// Test that complex schemas serialize/deserialize correctly
let json = serde_json::to_value(&request).unwrap();
let deserialized: CreateElicitationRequestParam = serde_json::from_value(json).unwrap();
let deserialized: CreateElicitationRequestParams = serde_json::from_value(json).unwrap();
assert_eq!(deserialized.message, "Please provide your user information");
assert_eq!(deserialized.requested_schema.properties.len(), 1);
assert!(
@ -816,7 +825,8 @@ async fn test_elicitation_direction_server_to_client() {
.build()
.unwrap();
let elicitation_request = CreateElicitationRequestParam {
let elicitation_request = CreateElicitationRequestParams {
meta: None,
message: "Please enter your name".to_string(),
requested_schema: schema,
};
@ -868,7 +878,8 @@ async fn test_elicitation_json_rpc_direction() {
let server_request = ServerJsonRpcMessage::request(
ServerRequest::CreateElicitationRequest(CreateElicitationRequest {
method: ElicitationCreateRequestMethod,
params: CreateElicitationRequestParam {
params: CreateElicitationRequestParams {
meta: None,
message: "Do you want to continue?".to_string(),
requested_schema: schema,
},
@ -1039,8 +1050,9 @@ async fn test_client_capabilities_with_elicitation() {
/// Test InitializeRequestParam with elicitation capability
#[tokio::test]
async fn test_initialize_request_with_elicitation() {
// Test InitializeRequestParam with elicitation capability
let init_param = InitializeRequestParam {
// Test InitializeRequestParams with elicitation capability
let init_param = InitializeRequestParams {
meta: None,
protocol_version: ProtocolVersion::LATEST,
capabilities: ClientCapabilities {
elicitation: Some(ElicitationCapability {
@ -1084,7 +1096,8 @@ async fn test_capability_checking_logic() {
// Simulate the logic that would be used in supports_elicitation()
// Case 1: Client with elicitation capability
let client_with_capability = InitializeRequestParam {
let client_with_capability = InitializeRequestParams {
meta: None,
protocol_version: ProtocolVersion::LATEST,
capabilities: ClientCapabilities {
elicitation: Some(ElicitationCapability {
@ -1106,7 +1119,8 @@ async fn test_capability_checking_logic() {
assert!(supports_elicitation);
// Case 2: Client without elicitation capability
let client_without_capability = InitializeRequestParam {
let client_without_capability = InitializeRequestParams {
meta: None,
protocol_version: ProtocolVersion::LATEST,
capabilities: ClientCapabilities {
elicitation: None,
@ -1308,7 +1322,8 @@ async fn test_create_elicitation_with_timeout_basic() {
.build()
.unwrap();
let _params = CreateElicitationRequestParam {
let _params = CreateElicitationRequestParams {
meta: None,
message: "Enter your details".to_string(),
requested_schema: schema,
};

View file

@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex};
use common::handlers::{TestClientHandler, TestServer};
use rmcp::{
ServiceExt,
model::{LoggingLevel, LoggingMessageNotificationParam, SetLevelRequestParam},
model::{LoggingLevel, LoggingMessageNotificationParam, SetLevelRequestParams},
};
use serde_json::json;
use tokio::sync::Notify;
@ -63,7 +63,7 @@ async fn test_logging_spec_compliance() -> anyhow::Result<()> {
] {
client
.peer()
.set_level(SetLevelRequestParam { level })
.set_level(SetLevelRequestParams { meta: None, level })
.await?;
// Wait for each message response
@ -121,7 +121,8 @@ async fn test_logging_user_scenarios() -> anyhow::Result<()> {
// Test 1: Error reporting scenario
client
.peer()
.set_level(SetLevelRequestParam {
.set_level(SetLevelRequestParams {
meta: None,
level: LoggingLevel::Error,
})
.await?;
@ -147,7 +148,8 @@ async fn test_logging_user_scenarios() -> anyhow::Result<()> {
// Test 2: Debug scenario
client
.peer()
.set_level(SetLevelRequestParam {
.set_level(SetLevelRequestParams {
meta: None,
level: LoggingLevel::Debug,
})
.await?;
@ -170,7 +172,8 @@ async fn test_logging_user_scenarios() -> anyhow::Result<()> {
// Test 3: Production monitoring scenario
client
.peer()
.set_level(SetLevelRequestParam {
.set_level(SetLevelRequestParams {
meta: None,
level: LoggingLevel::Info,
})
.await?;
@ -256,7 +259,7 @@ async fn test_logging_edge_cases() -> anyhow::Result<()> {
] {
client
.peer()
.set_level(SetLevelRequestParam { level })
.set_level(SetLevelRequestParams { meta: None, level })
.await?;
receive_signal.notified().await;
@ -316,7 +319,7 @@ async fn test_logging_optional_fields() -> anyhow::Result<()> {
for level in [LoggingLevel::Info, LoggingLevel::Debug] {
client
.peer()
.set_level(SetLevelRequestParam { level })
.set_level(SetLevelRequestParams { meta: None, level })
.await?;
// Wait for each message response

View file

@ -47,7 +47,9 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
// Test ThisServer context inclusion
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -89,7 +91,9 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
// Test AllServers context inclusion
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -131,7 +135,9 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
// Test No context inclusion
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -193,7 +199,9 @@ async fn test_context_inclusion_ignored_integration() -> anyhow::Result<()> {
// Test that context requests are ignored
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -254,7 +262,9 @@ async fn test_message_sequence_integration() -> anyhow::Result<()> {
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![
SamplingMessage {
role: Role::User,
@ -325,7 +335,9 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
// Test valid sequence: User -> Assistant -> User
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![
SamplingMessage {
role: Role::User,
@ -369,7 +381,9 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
// Test invalid: No user message
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::Assistant,
content: Content::text("assistant message"),
@ -422,7 +436,9 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
// Test ThisServer is honored
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -462,7 +478,9 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
// Test AllServers is ignored
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test message"),
@ -519,7 +537,9 @@ async fn test_context_inclusion() -> anyhow::Result<()> {
// Test context handling
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("test"),

View file

@ -187,10 +187,18 @@
"format": "const",
"const": "tools/call"
},
"CallToolRequestParam": {
"description": "Parameters for calling a tool provided by an MCP server.\n\nContains the tool name and optional arguments needed to execute\nthe tool operation.",
"CallToolRequestParams": {
"description": "Parameters for calling a tool provided by an MCP server.\n\nContains the tool name and optional arguments needed to execute\nthe tool operation.\n\nThis implements `TaskAugmentedRequestParamsMeta` as tool calls can be\nlong-running and may benefit from task-based execution.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"arguments": {
"description": "Arguments to pass to the tool (must match the tool's input schema)",
"type": [
@ -204,6 +212,7 @@
"type": "string"
},
"task": {
"description": "Task metadata for async task management (SEP-1319)",
"type": [
"object",
"null"
@ -220,9 +229,17 @@
"format": "const",
"const": "tasks/cancel"
},
"CancelTaskParam": {
"CancelTaskParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -332,9 +349,17 @@
"format": "const",
"const": "completion/complete"
},
"CompleteRequestParam": {
"CompleteRequestParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"argument": {
"$ref": "#/definitions/ArgumentInfo"
},
@ -534,10 +559,18 @@
"format": "const",
"const": "prompts/get"
},
"GetPromptRequestParam": {
"GetPromptRequestParams": {
"description": "Parameters for retrieving a specific prompt",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"arguments": {
"type": [
"object",
@ -558,9 +591,17 @@
"format": "const",
"const": "tasks/get"
},
"GetTaskInfoParam": {
"GetTaskInfoParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -574,9 +615,17 @@
"format": "const",
"const": "tasks/result"
},
"GetTaskResultParam": {
"GetTaskResultParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -651,10 +700,18 @@
"version"
]
},
"InitializeRequestParam": {
"InitializeRequestParams": {
"description": "Parameters sent by a client when initializing a connection to an MCP server.\n\nThis contains the client's protocol version, capabilities, and implementation\ninformation, allowing the server to understand what the client supports.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"capabilities": {
"description": "The capabilities this client supports (sampling, roots, etc.)",
"allOf": [
@ -953,9 +1010,17 @@
}
]
},
"PaginatedRequestParam": {
"PaginatedRequestParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"cursor": {
"type": [
"string",
@ -1183,10 +1248,18 @@
"format": "const",
"const": "resources/read"
},
"ReadResourceRequestParam": {
"ReadResourceRequestParams": {
"description": "Parameters for reading a specific resource",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to read",
"type": "string"
@ -1242,7 +1315,7 @@
"$ref": "#/definitions/InitializeResultMethod"
},
"params": {
"$ref": "#/definitions/InitializeRequestParam"
"$ref": "#/definitions/InitializeRequestParams"
}
},
"required": [
@ -1258,7 +1331,7 @@
"$ref": "#/definitions/GetTaskResultMethod"
},
"params": {
"$ref": "#/definitions/GetTaskResultParam"
"$ref": "#/definitions/GetTaskResultParams"
}
},
"required": [
@ -1274,7 +1347,7 @@
"$ref": "#/definitions/CancelTaskMethod"
},
"params": {
"$ref": "#/definitions/CancelTaskParam"
"$ref": "#/definitions/CancelTaskParams"
}
},
"required": [
@ -1290,7 +1363,7 @@
"$ref": "#/definitions/CompleteRequestMethod"
},
"params": {
"$ref": "#/definitions/CompleteRequestParam"
"$ref": "#/definitions/CompleteRequestParams"
}
},
"required": [
@ -1306,7 +1379,7 @@
"$ref": "#/definitions/SetLevelRequestMethod"
},
"params": {
"$ref": "#/definitions/SetLevelRequestParam"
"$ref": "#/definitions/SetLevelRequestParams"
}
},
"required": [
@ -1322,7 +1395,7 @@
"$ref": "#/definitions/GetPromptRequestMethod"
},
"params": {
"$ref": "#/definitions/GetPromptRequestParam"
"$ref": "#/definitions/GetPromptRequestParams"
}
},
"required": [
@ -1338,7 +1411,7 @@
"$ref": "#/definitions/ReadResourceRequestMethod"
},
"params": {
"$ref": "#/definitions/ReadResourceRequestParam"
"$ref": "#/definitions/ReadResourceRequestParams"
}
},
"required": [
@ -1354,7 +1427,7 @@
"$ref": "#/definitions/SubscribeRequestMethod"
},
"params": {
"$ref": "#/definitions/SubscribeRequestParam"
"$ref": "#/definitions/SubscribeRequestParams"
}
},
"required": [
@ -1370,7 +1443,7 @@
"$ref": "#/definitions/UnsubscribeRequestMethod"
},
"params": {
"$ref": "#/definitions/UnsubscribeRequestParam"
"$ref": "#/definitions/UnsubscribeRequestParams"
}
},
"required": [
@ -1386,7 +1459,7 @@
"$ref": "#/definitions/CallToolRequestMethod"
},
"params": {
"$ref": "#/definitions/CallToolRequestParam"
"$ref": "#/definitions/CallToolRequestParams"
}
},
"required": [
@ -1402,7 +1475,7 @@
"$ref": "#/definitions/GetTaskInfoMethod"
},
"params": {
"$ref": "#/definitions/GetTaskInfoParam"
"$ref": "#/definitions/GetTaskInfoParams"
}
},
"required": [
@ -1430,7 +1503,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1451,7 +1524,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1472,7 +1545,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1493,7 +1566,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1514,7 +1587,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1650,10 +1723,18 @@
"format": "const",
"const": "logging/setLevel"
},
"SetLevelRequestParam": {
"SetLevelRequestParams": {
"description": "Parameters for setting the logging level",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"level": {
"description": "The desired logging level",
"allOf": [
@ -1672,10 +1753,18 @@
"format": "const",
"const": "resources/subscribe"
},
"SubscribeRequestParam": {
"SubscribeRequestParams": {
"description": "Parameters for subscribing to resource updates",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to subscribe to",
"type": "string"
@ -1720,10 +1809,18 @@
"format": "const",
"const": "resources/unsubscribe"
},
"UnsubscribeRequestParam": {
"UnsubscribeRequestParams": {
"description": "Parameters for unsubscribing from resource updates",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to unsubscribe from",
"type": "string"

View file

@ -187,10 +187,18 @@
"format": "const",
"const": "tools/call"
},
"CallToolRequestParam": {
"description": "Parameters for calling a tool provided by an MCP server.\n\nContains the tool name and optional arguments needed to execute\nthe tool operation.",
"CallToolRequestParams": {
"description": "Parameters for calling a tool provided by an MCP server.\n\nContains the tool name and optional arguments needed to execute\nthe tool operation.\n\nThis implements `TaskAugmentedRequestParamsMeta` as tool calls can be\nlong-running and may benefit from task-based execution.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"arguments": {
"description": "Arguments to pass to the tool (must match the tool's input schema)",
"type": [
@ -204,6 +212,7 @@
"type": "string"
},
"task": {
"description": "Task metadata for async task management (SEP-1319)",
"type": [
"object",
"null"
@ -220,9 +229,17 @@
"format": "const",
"const": "tasks/cancel"
},
"CancelTaskParam": {
"CancelTaskParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -332,9 +349,17 @@
"format": "const",
"const": "completion/complete"
},
"CompleteRequestParam": {
"CompleteRequestParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"argument": {
"$ref": "#/definitions/ArgumentInfo"
},
@ -534,10 +559,18 @@
"format": "const",
"const": "prompts/get"
},
"GetPromptRequestParam": {
"GetPromptRequestParams": {
"description": "Parameters for retrieving a specific prompt",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"arguments": {
"type": [
"object",
@ -558,9 +591,17 @@
"format": "const",
"const": "tasks/get"
},
"GetTaskInfoParam": {
"GetTaskInfoParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -574,9 +615,17 @@
"format": "const",
"const": "tasks/result"
},
"GetTaskResultParam": {
"GetTaskResultParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"taskId": {
"type": "string"
}
@ -651,10 +700,18 @@
"version"
]
},
"InitializeRequestParam": {
"InitializeRequestParams": {
"description": "Parameters sent by a client when initializing a connection to an MCP server.\n\nThis contains the client's protocol version, capabilities, and implementation\ninformation, allowing the server to understand what the client supports.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"capabilities": {
"description": "The capabilities this client supports (sampling, roots, etc.)",
"allOf": [
@ -953,9 +1010,17 @@
}
]
},
"PaginatedRequestParam": {
"PaginatedRequestParams": {
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"cursor": {
"type": [
"string",
@ -1183,10 +1248,18 @@
"format": "const",
"const": "resources/read"
},
"ReadResourceRequestParam": {
"ReadResourceRequestParams": {
"description": "Parameters for reading a specific resource",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to read",
"type": "string"
@ -1242,7 +1315,7 @@
"$ref": "#/definitions/InitializeResultMethod"
},
"params": {
"$ref": "#/definitions/InitializeRequestParam"
"$ref": "#/definitions/InitializeRequestParams"
}
},
"required": [
@ -1258,7 +1331,7 @@
"$ref": "#/definitions/GetTaskResultMethod"
},
"params": {
"$ref": "#/definitions/GetTaskResultParam"
"$ref": "#/definitions/GetTaskResultParams"
}
},
"required": [
@ -1274,7 +1347,7 @@
"$ref": "#/definitions/CancelTaskMethod"
},
"params": {
"$ref": "#/definitions/CancelTaskParam"
"$ref": "#/definitions/CancelTaskParams"
}
},
"required": [
@ -1290,7 +1363,7 @@
"$ref": "#/definitions/CompleteRequestMethod"
},
"params": {
"$ref": "#/definitions/CompleteRequestParam"
"$ref": "#/definitions/CompleteRequestParams"
}
},
"required": [
@ -1306,7 +1379,7 @@
"$ref": "#/definitions/SetLevelRequestMethod"
},
"params": {
"$ref": "#/definitions/SetLevelRequestParam"
"$ref": "#/definitions/SetLevelRequestParams"
}
},
"required": [
@ -1322,7 +1395,7 @@
"$ref": "#/definitions/GetPromptRequestMethod"
},
"params": {
"$ref": "#/definitions/GetPromptRequestParam"
"$ref": "#/definitions/GetPromptRequestParams"
}
},
"required": [
@ -1338,7 +1411,7 @@
"$ref": "#/definitions/ReadResourceRequestMethod"
},
"params": {
"$ref": "#/definitions/ReadResourceRequestParam"
"$ref": "#/definitions/ReadResourceRequestParams"
}
},
"required": [
@ -1354,7 +1427,7 @@
"$ref": "#/definitions/SubscribeRequestMethod"
},
"params": {
"$ref": "#/definitions/SubscribeRequestParam"
"$ref": "#/definitions/SubscribeRequestParams"
}
},
"required": [
@ -1370,7 +1443,7 @@
"$ref": "#/definitions/UnsubscribeRequestMethod"
},
"params": {
"$ref": "#/definitions/UnsubscribeRequestParam"
"$ref": "#/definitions/UnsubscribeRequestParams"
}
},
"required": [
@ -1386,7 +1459,7 @@
"$ref": "#/definitions/CallToolRequestMethod"
},
"params": {
"$ref": "#/definitions/CallToolRequestParam"
"$ref": "#/definitions/CallToolRequestParams"
}
},
"required": [
@ -1402,7 +1475,7 @@
"$ref": "#/definitions/GetTaskInfoMethod"
},
"params": {
"$ref": "#/definitions/GetTaskInfoParam"
"$ref": "#/definitions/GetTaskInfoParams"
}
},
"required": [
@ -1430,7 +1503,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1451,7 +1524,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1472,7 +1545,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1493,7 +1566,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1514,7 +1587,7 @@
"params": {
"anyOf": [
{
"$ref": "#/definitions/PaginatedRequestParam"
"$ref": "#/definitions/PaginatedRequestParams"
},
{
"type": "null"
@ -1650,10 +1723,18 @@
"format": "const",
"const": "logging/setLevel"
},
"SetLevelRequestParam": {
"SetLevelRequestParams": {
"description": "Parameters for setting the logging level",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"level": {
"description": "The desired logging level",
"allOf": [
@ -1672,10 +1753,18 @@
"format": "const",
"const": "resources/subscribe"
},
"SubscribeRequestParam": {
"SubscribeRequestParams": {
"description": "Parameters for subscribing to resource updates",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to subscribe to",
"type": "string"
@ -1720,10 +1809,18 @@
"format": "const",
"const": "resources/unsubscribe"
},
"UnsubscribeRequestParam": {
"UnsubscribeRequestParams": {
"description": "Parameters for unsubscribing from resource updates",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"uri": {
"description": "The URI of the resource to unsubscribe from",
"type": "string"

View file

@ -504,10 +504,18 @@
}
]
},
"CreateElicitationRequestParam": {
"description": "Parameters for creating an elicitation request to gather user input.\n\nThis structure contains everything needed to request interactive input from a user:\n- A human-readable message explaining what information is needed\n- A type-safe schema defining the expected structure of the response\n\n# Example\n\n```rust\nuse rmcp::model::*;\n\nlet params = CreateElicitationRequestParam {\n message: \"Please provide your email\".to_string(),\n requested_schema: ElicitationSchema::builder()\n .required_email(\"email\")\n .build()\n .unwrap(),\n};\n```",
"CreateElicitationRequestParams": {
"description": "Parameters for creating an elicitation request to gather user input.\n\nThis structure contains everything needed to request interactive input from a user:\n- A human-readable message explaining what information is needed\n- A type-safe schema defining the expected structure of the response\n\n# Example\n\n```rust\nuse rmcp::model::*;\n\nlet params = CreateElicitationRequestParams {\n meta: None,\n message: \"Please provide your email\".to_string(),\n requested_schema: ElicitationSchema::builder()\n .required_email(\"email\")\n .build()\n .unwrap(),\n};\n```",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"message": {
"description": "Human-readable message explaining what input is needed from the user.\nThis should be clear and provide sufficient context for the user to understand\nwhat information they need to provide.",
"type": "string"
@ -551,10 +559,18 @@
"format": "const",
"const": "sampling/createMessage"
},
"CreateMessageRequestParam": {
"description": "Parameters for creating a message through LLM sampling.\n\nThis structure contains all the necessary information for a client to\ngenerate an LLM response, including conversation history, model preferences,\nand generation parameters.",
"CreateMessageRequestParams": {
"description": "Parameters for creating a message through LLM sampling.\n\nThis structure contains all the necessary information for a client to\ngenerate an LLM response, including conversation history, model preferences,\nand generation parameters.\n\nThis implements `TaskAugmentedRequestParamsMeta` as sampling requests can be\nlong-running and may benefit from task-based execution.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"includeContext": {
"description": "How much context to include from MCP servers",
"anyOf": [
@ -610,6 +626,14 @@
"null"
]
},
"task": {
"description": "Task metadata for async task management (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"temperature": {
"description": "Temperature for controlling randomness (0.0 to 1.0)",
"type": [
@ -2111,7 +2135,7 @@
"$ref": "#/definitions/CreateMessageRequestMethod"
},
"params": {
"$ref": "#/definitions/CreateMessageRequestParam"
"$ref": "#/definitions/CreateMessageRequestParams"
}
},
"required": [
@ -2127,7 +2151,7 @@
"$ref": "#/definitions/ElicitationCreateRequestMethod"
},
"params": {
"$ref": "#/definitions/CreateElicitationRequestParam"
"$ref": "#/definitions/CreateElicitationRequestParams"
}
},
"required": [

View file

@ -504,10 +504,18 @@
}
]
},
"CreateElicitationRequestParam": {
"description": "Parameters for creating an elicitation request to gather user input.\n\nThis structure contains everything needed to request interactive input from a user:\n- A human-readable message explaining what information is needed\n- A type-safe schema defining the expected structure of the response\n\n# Example\n\n```rust\nuse rmcp::model::*;\n\nlet params = CreateElicitationRequestParam {\n message: \"Please provide your email\".to_string(),\n requested_schema: ElicitationSchema::builder()\n .required_email(\"email\")\n .build()\n .unwrap(),\n};\n```",
"CreateElicitationRequestParams": {
"description": "Parameters for creating an elicitation request to gather user input.\n\nThis structure contains everything needed to request interactive input from a user:\n- A human-readable message explaining what information is needed\n- A type-safe schema defining the expected structure of the response\n\n# Example\n\n```rust\nuse rmcp::model::*;\n\nlet params = CreateElicitationRequestParams {\n meta: None,\n message: \"Please provide your email\".to_string(),\n requested_schema: ElicitationSchema::builder()\n .required_email(\"email\")\n .build()\n .unwrap(),\n};\n```",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"message": {
"description": "Human-readable message explaining what input is needed from the user.\nThis should be clear and provide sufficient context for the user to understand\nwhat information they need to provide.",
"type": "string"
@ -551,10 +559,18 @@
"format": "const",
"const": "sampling/createMessage"
},
"CreateMessageRequestParam": {
"description": "Parameters for creating a message through LLM sampling.\n\nThis structure contains all the necessary information for a client to\ngenerate an LLM response, including conversation history, model preferences,\nand generation parameters.",
"CreateMessageRequestParams": {
"description": "Parameters for creating a message through LLM sampling.\n\nThis structure contains all the necessary information for a client to\ngenerate an LLM response, including conversation history, model preferences,\nand generation parameters.\n\nThis implements `TaskAugmentedRequestParamsMeta` as sampling requests can be\nlong-running and may benefit from task-based execution.",
"type": "object",
"properties": {
"_meta": {
"description": "Protocol-level metadata for this request (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"includeContext": {
"description": "How much context to include from MCP servers",
"anyOf": [
@ -610,6 +626,14 @@
"null"
]
},
"task": {
"description": "Task metadata for async task management (SEP-1319)",
"type": [
"object",
"null"
],
"additionalProperties": true
},
"temperature": {
"description": "Temperature for controlling randomness (0.0 to 1.0)",
"type": [
@ -2111,7 +2135,7 @@
"$ref": "#/definitions/CreateMessageRequestMethod"
},
"params": {
"$ref": "#/definitions/CreateMessageRequestParam"
"$ref": "#/definitions/CreateMessageRequestParams"
}
},
"required": [
@ -2127,7 +2151,7 @@
"$ref": "#/definitions/ElicitationCreateRequestMethod"
},
"params": {
"$ref": "#/definitions/CreateElicitationRequestParam"
"$ref": "#/definitions/CreateElicitationRequestParams"
}
},
"required": [

View file

@ -4,7 +4,7 @@ use rmcp::{
ClientHandler, ServerHandler, ServiceExt,
model::{
ClientNotification, CustomNotification, ResourceUpdatedNotificationParam,
ServerCapabilities, ServerInfo, ServerNotification, SubscribeRequestParam,
ServerCapabilities, ServerInfo, ServerNotification, SubscribeRequestParams,
},
};
use serde_json::json;
@ -27,7 +27,7 @@ impl ServerHandler for Server {
async fn subscribe(
&self,
request: rmcp::model::SubscribeRequestParam,
request: rmcp::model::SubscribeRequestParams,
context: rmcp::service::RequestContext<rmcp::RoleServer>,
) -> Result<(), rmcp::ErrorData> {
let uri = request.uri;
@ -87,7 +87,8 @@ async fn test_server_notification() -> anyhow::Result<()> {
.serve(client_transport)
.await?;
client
.subscribe(SubscribeRequestParam {
.subscribe(SubscribeRequestParams {
meta: None,
uri: "test://test-resource".to_owned(),
})
.await?;

View file

@ -2,7 +2,7 @@ use futures::StreamExt;
use rmcp::{
ClientHandler, Peer, RoleServer, ServerHandler, ServiceExt,
handler::{client::progress::ProgressDispatcher, server::tool::ToolRouter},
model::{CallToolRequestParam, ClientRequest, Meta, ProgressNotificationParam, Request},
model::{CallToolRequestParams, ClientRequest, Meta, ProgressNotificationParam, Request},
service::PeerRequestOptions,
tool, tool_handler, tool_router,
};
@ -107,7 +107,8 @@ async fn test_progress_subscriber() -> anyhow::Result<()> {
let client_service = client.serve(transport_client).await?;
let handle = client_service
.send_cancellable_request(
ClientRequest::CallToolRequest(Request::new(CallToolRequestParam {
ClientRequest::CallToolRequest(Request::new(CallToolRequestParams {
meta: None,
name: "some_progress".into(),
arguments: None,
task: None,

View file

@ -6,7 +6,7 @@
use rmcp::{
RoleServer, ServerHandler,
handler::server::router::prompt::PromptRouter,
model::{GetPromptRequestParam, GetPromptResult, ListPromptsResult, PaginatedRequestParam},
model::{GetPromptRequestParams, GetPromptResult, ListPromptsResult, PaginatedRequestParams},
prompt_handler,
service::RequestContext,
};

View file

@ -6,8 +6,8 @@ use rmcp::{
ClientHandler, RoleServer, ServerHandler, ServiceExt,
handler::server::{router::prompt::PromptRouter, wrapper::Parameters},
model::{
ClientInfo, GetPromptRequestParam, GetPromptResult, ListPromptsResult,
PaginatedRequestParam, PromptMessage, PromptMessageRole,
ClientInfo, GetPromptRequestParams, GetPromptResult, ListPromptsResult,
PaginatedRequestParams, PromptMessage, PromptMessageRole,
},
prompt, prompt_handler, prompt_router,
service::RequestContext,
@ -327,7 +327,8 @@ async fn test_optional_i64_field_with_null_input() -> anyhow::Result<()> {
// Test null case
let result = client
.get_prompt(GetPromptRequestParam {
.get_prompt(GetPromptRequestParams {
meta: None,
name: "test_optional_i64".into(),
arguments: Some(
serde_json::json!({
@ -353,7 +354,8 @@ async fn test_optional_i64_field_with_null_input() -> anyhow::Result<()> {
// Test Some case
let some_result = client
.get_prompt(GetPromptRequestParam {
.get_prompt(GetPromptRequestParams {
meta: None,
name: "test_optional_i64".into(),
arguments: Some(
serde_json::json!({

View file

@ -31,7 +31,9 @@ async fn test_basic_sampling_message_creation() -> Result<()> {
#[tokio::test]
async fn test_sampling_request_params() -> Result<()> {
// Test sampling request parameters structure
let params = CreateMessageRequestParam {
let params = CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("Hello, world!"),
@ -54,7 +56,7 @@ async fn test_sampling_request_params() -> Result<()> {
// Verify serialization/deserialization
let json = serde_json::to_string(&params)?;
let deserialized: CreateMessageRequestParam = serde_json::from_str(&json)?;
let deserialized: CreateMessageRequestParams = serde_json::from_str(&json)?;
assert_eq!(params, deserialized);
// Verify specific fields
@ -134,7 +136,9 @@ async fn test_sampling_integration_with_test_handlers() -> Result<()> {
// Test sampling with context inclusion
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("What is the capital of France?"),
@ -214,7 +218,9 @@ async fn test_sampling_no_context_inclusion() -> Result<()> {
// Test sampling without context inclusion
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::User,
content: Content::text("Hello"),
@ -283,7 +289,9 @@ async fn test_sampling_error_invalid_message_sequence() -> Result<()> {
// Test sampling with no user messages (should fail)
let request = ServerRequest::CreateMessageRequest(CreateMessageRequest {
method: Default::default(),
params: CreateMessageRequestParam {
params: CreateMessageRequestParams {
meta: None,
task: None,
messages: vec![SamplingMessage {
role: Role::Assistant,
content: Content::text("I'm an assistant message without a user message"),

View file

@ -9,7 +9,7 @@ use std::sync::Arc;
use rmcp::{
ClientHandler, ServerHandler, ServiceExt,
handler::server::{router::tool::ToolRouter, wrapper::Parameters},
model::{CallToolRequestParam, ClientInfo},
model::{CallToolRequestParams, ClientInfo},
tool, tool_handler, tool_router,
};
use schemars::JsonSchema;
@ -309,7 +309,8 @@ async fn test_optional_i64_field_with_null_input() -> anyhow::Result<()> {
// Test null case
let result = client
.call_tool(CallToolRequestParam {
.call_tool(CallToolRequestParams {
meta: None,
name: "test_optional_i64".into(),
arguments: Some(
serde_json::json!({
@ -338,7 +339,8 @@ async fn test_optional_i64_field_with_null_input() -> anyhow::Result<()> {
// Test Some case
let some_result = client
.call_tool(CallToolRequestParam {
.call_tool(CallToolRequestParams {
meta: None,
name: "test_optional_i64".into(),
arguments: Some(
serde_json::json!({