From 86fd2b3be84dea92f8b12e80d6ba5a9de2770e9c Mon Sep 17 00:00:00 2001 From: Ali Hashemi Date: Sun, 27 Jul 2025 15:43:57 -0300 Subject: [PATCH 1/2] feat: enhance schema_utils by introducing new types and utility functions --- src/generated_schema/2025_06_18/schema_utils.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/generated_schema/2025_06_18/schema_utils.rs b/src/generated_schema/2025_06_18/schema_utils.rs index 0635d3c..3f5c7fd 100644 --- a/src/generated_schema/2025_06_18/schema_utils.rs +++ b/src/generated_schema/2025_06_18/schema_utils.rs @@ -107,6 +107,12 @@ impl PartialEq for RequestId { } } +impl PartialEq for &RequestId { + fn eq(&self, other: &RequestId) -> bool { + (*self).eq(other) + } +} + impl Eq for RequestId {} // Implement Hash for RequestId, so we can store it in HashMaps, HashSets, etc. From b7330887a071446f64615e8d914a372e4f4dcd55 Mon Sep 17 00:00:00 2001 From: Ali Hashemi Date: Sun, 27 Jul 2025 15:44:22 -0300 Subject: [PATCH 2/2] feat: enhance schema_utils by introducing new types and utility functions --- src/generated_schema/2024_11_05/mcp_schema.rs | 6 +- .../2024_11_05/schema_utils.rs | 362 ++++++++++++++++- src/generated_schema/2025_03_26/mcp_schema.rs | 6 +- .../2025_03_26/schema_utils.rs | 363 ++++++++++++++++- src/generated_schema/2025_06_18/mcp_schema.rs | 6 +- .../2025_06_18/schema_utils.rs | 358 ++++++++++++++++- src/generated_schema/draft/mcp_schema.rs | 24 +- src/generated_schema/draft/schema_utils.rs | 364 +++++++++++++++++- src/generated_schema/protocol_version.rs | 27 +- 9 files changed, 1481 insertions(+), 35 deletions(-) diff --git a/src/generated_schema/2024_11_05/mcp_schema.rs b/src/generated_schema/2024_11_05/mcp_schema.rs index 1809a54..9010456 100644 --- a/src/generated_schema/2024_11_05/mcp_schema.rs +++ b/src/generated_schema/2024_11_05/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.4.1. +/// This file is auto-generated by mcp-schema-gen v0.4.2. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 1cfdf1e7a8aa5065b7e3cb3e35e653df9542e0de -/// Generated at : 2025-07-01 14:46:39 +/// Hash : 0695a497eb50a804fc0e88c18a93a21a675d6b3e +/// Generated at : 2025-07-27 15:33:20 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version diff --git a/src/generated_schema/2024_11_05/schema_utils.rs b/src/generated_schema/2024_11_05/schema_utils.rs index b794a59..056023e 100644 --- a/src/generated_schema/2024_11_05/schema_utils.rs +++ b/src/generated_schema/2024_11_05/schema_utils.rs @@ -108,6 +108,12 @@ impl PartialEq for RequestId { } } +impl PartialEq for &RequestId { + fn eq(&self, other: &RequestId) -> bool { + (*self).eq(other) + } +} + impl Eq for RequestId {} // Implement Hash for RequestId, so we can store it in HashMaps, HashSets, etc. @@ -225,6 +231,29 @@ impl ClientMessage { ))) } } + + /// Returns `true` if message is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::Request(request) if request.request.is_initialize_request()) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcResponse) -> Self { + Self::Response(value) + } } impl RpcMessage for ClientMessage { @@ -385,6 +414,10 @@ impl RequestFromClient { RequestFromClient::CustomRequest(request) => request["method"].as_str().unwrap(), } } + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, RequestFromClient::ClientRequest(ClientRequest::InitializeRequest(_))) + } } impl From for RequestFromClient { @@ -739,6 +772,24 @@ impl ServerMessage { } } +impl From for ServerMessage { + fn from(value: ServerJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcResponse) -> Self { + Self::Response(value) + } +} + impl RpcMessage for ServerMessage { // Retrieves the request ID associated with the message, if applicable fn request_id(&self) -> Option<&RequestId> { @@ -1152,7 +1203,7 @@ impl FromStr for JsonrpcError { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromServer { RequestFromServer(RequestFromServer), @@ -1257,7 +1308,7 @@ impl FromMessage for ServerMessage { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromClient { RequestFromClient(RequestFromClient), @@ -1266,6 +1317,13 @@ pub enum MessageFromClient { Error(RpcError), } +impl MessageFromClient { + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::RequestFromClient(request) if request.is_initialize_request()) + } +} + impl From for MessageFromClient { fn from(value: RequestFromClient) -> Self { Self::RequestFromClient(value) @@ -1450,6 +1508,224 @@ impl> From for TextContent { } } + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ClientMessages { + Single(ClientMessage), + Batch(Vec), +} + +impl ClientMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ClientMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ClientMessages::Single(client_message) => client_message.is_request(), + ClientMessages::Batch(client_messages) => client_messages.iter().any(ClientMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ClientMessages::Single(client_message) => Ok(client_message), + ClientMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessages::Batch to ClientMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ClientMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessage::Single to ClientMessages::Batch")), + ClientMessages::Batch(client_messages) => Ok(client_messages), + } + } +} + +impl From for ClientMessages { + fn from(value: ClientMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ClientMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ClientMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ServerMessages { + Single(ServerMessage), + Batch(Vec), +} + +impl ServerMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ServerMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ServerMessages::Single(server_message) => server_message.is_request(), + ServerMessages::Batch(server_messages) => server_messages.iter().any(ServerMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ServerMessages::Single(server_message) => Ok(server_message), + ServerMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessages::Batch to ServerMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ServerMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessage::Single to ServerMessages::Batch")), + ServerMessages::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for ServerMessages { + fn from(value: ServerMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ServerMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ServerMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromServer { + Single(MessageFromServer), + Batch(Vec), +} + +impl MessagesFromServer { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromServer::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromServer::Single(server_message) => server_message.is_request(), + MessagesFromServer::Batch(server_messages) => server_messages.iter().any(MessageFromServer::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromServer::Single(server_message) => Ok(server_message), + MessagesFromServer::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromServer::Batch to MessageFromServer::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromServer::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromServer::Single to MessagesFromServer::Batch")), + MessagesFromServer::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromServer { + fn from(value: MessageFromServer) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromServer { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromClient { + Single(MessageFromClient), + Batch(Vec), +} + +impl MessagesFromClient { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromClient::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromClient::Single(server_message) => server_message.is_request(), + MessagesFromClient::Batch(server_messages) => server_messages.iter().any(MessageFromClient::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromClient::Single(server_message) => Ok(server_message), + MessagesFromClient::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromClient::Batch to MessageFromClient::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromClient::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromClient::Single to MessagesFromClient::Batch")), + MessagesFromClient::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromClient { + fn from(value: MessageFromClient) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromClient { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + #[deprecated(since = "0.4.0", note = "This trait was renamed to RpcMessage. Use RpcMessage instead.")] pub type RPCMessage = (); #[deprecated(since = "0.4.0", note = "This trait was renamed to McpMessage. Use McpMessage instead.")] @@ -2132,12 +2408,28 @@ impl From for MessageFromClient { pub enum SdkErrorCodes { CONNECTION_CLOSED = -32000, REQUEST_TIMEOUT = -32001, + RESOURCE_NOT_FOUND = -32002, + BAD_REQUEST = -32015, + SESSION_NOT_FOUND = -32016, + INVALID_REQUEST = -32600, + METHOD_NOT_FOUND = -32601, + INVALID_PARAMS = -32602, + INTERNAL_ERROR = -32603, + PARSE_ERROR = -32700, } impl core::fmt::Display for SdkErrorCodes { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { SdkErrorCodes::CONNECTION_CLOSED => write!(f, "Connection closed"), SdkErrorCodes::REQUEST_TIMEOUT => write!(f, "Request timeout"), + SdkErrorCodes::INVALID_REQUEST => write!(f, "Invalid request"), + SdkErrorCodes::METHOD_NOT_FOUND => write!(f, "Method not found"), + SdkErrorCodes::INVALID_PARAMS => write!(f, "Invalid params"), + SdkErrorCodes::INTERNAL_ERROR => write!(f, "Internal error"), + SdkErrorCodes::PARSE_ERROR => write!(f, "Parse Error"), + SdkErrorCodes::RESOURCE_NOT_FOUND => write!(f, "Resource not found"), + SdkErrorCodes::BAD_REQUEST => write!(f, "Bad request"), + SdkErrorCodes::SESSION_NOT_FOUND => write!(f, "Session not found"), } } } @@ -2146,7 +2438,7 @@ impl From for i64 { code as i64 } } -#[derive(Debug)] +#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] pub struct SdkError { ///The error type that occurred. pub code: i64, @@ -2191,6 +2483,70 @@ impl SdkError { message: SdkErrorCodes::REQUEST_TIMEOUT.to_string(), } } + pub fn session_not_found() -> Self { + Self { + code: SdkErrorCodes::SESSION_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::SESSION_NOT_FOUND.to_string(), + } + } + pub fn invalid_request() -> Self { + Self { + code: SdkErrorCodes::INVALID_REQUEST.into(), + data: None, + message: SdkErrorCodes::INVALID_REQUEST.to_string(), + } + } + pub fn method_not_found() -> Self { + Self { + code: SdkErrorCodes::METHOD_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::METHOD_NOT_FOUND.to_string(), + } + } + pub fn invalid_params() -> Self { + Self { + code: SdkErrorCodes::INVALID_PARAMS.into(), + data: None, + message: SdkErrorCodes::INVALID_PARAMS.to_string(), + } + } + pub fn internal_error() -> Self { + Self { + code: SdkErrorCodes::INTERNAL_ERROR.into(), + data: None, + message: SdkErrorCodes::INTERNAL_ERROR.to_string(), + } + } + pub fn parse_error() -> Self { + Self { + code: SdkErrorCodes::PARSE_ERROR.into(), + data: None, + message: SdkErrorCodes::PARSE_ERROR.to_string(), + } + } + pub fn resource_not_found() -> Self { + Self { + code: SdkErrorCodes::RESOURCE_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn bad_request() -> Self { + Self { + code: SdkErrorCodes::BAD_REQUEST.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn with_message(mut self, message: &str) -> Self { + self.message = message.to_string(); + self + } + pub fn with_data(mut self, data: ::std::option::Option<::serde_json::Value>) -> Self { + self.data = data; + self + } } /// Enum representing standard JSON-RPC error codes. #[allow(non_camel_case_types)] diff --git a/src/generated_schema/2025_03_26/mcp_schema.rs b/src/generated_schema/2025_03_26/mcp_schema.rs index f3240b0..587d210 100644 --- a/src/generated_schema/2025_03_26/mcp_schema.rs +++ b/src/generated_schema/2025_03_26/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.4.1. +/// This file is auto-generated by mcp-schema-gen v0.4.2. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 1cfdf1e7a8aa5065b7e3cb3e35e653df9542e0de -/// Generated at : 2025-07-01 14:46:41 +/// Hash : 0695a497eb50a804fc0e88c18a93a21a675d6b3e +/// Generated at : 2025-07-27 15:33:21 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version diff --git a/src/generated_schema/2025_03_26/schema_utils.rs b/src/generated_schema/2025_03_26/schema_utils.rs index a17284a..12eed17 100644 --- a/src/generated_schema/2025_03_26/schema_utils.rs +++ b/src/generated_schema/2025_03_26/schema_utils.rs @@ -108,6 +108,12 @@ impl PartialEq for RequestId { } } +impl PartialEq for &RequestId { + fn eq(&self, other: &RequestId) -> bool { + (*self).eq(other) + } +} + impl Eq for RequestId {} // Implement Hash for RequestId, so we can store it in HashMaps, HashSets, etc. @@ -225,6 +231,29 @@ impl ClientMessage { ))) } } + + /// Returns `true` if message is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::Request(request) if request.request.is_initialize_request()) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcResponse) -> Self { + Self::Response(value) + } } impl RpcMessage for ClientMessage { @@ -385,6 +414,10 @@ impl RequestFromClient { RequestFromClient::CustomRequest(request) => request["method"].as_str().unwrap(), } } + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, RequestFromClient::ClientRequest(ClientRequest::InitializeRequest(_))) + } } impl From for RequestFromClient { @@ -739,6 +772,24 @@ impl ServerMessage { } } +impl From for ServerMessage { + fn from(value: ServerJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcResponse) -> Self { + Self::Response(value) + } +} + impl RpcMessage for ServerMessage { // Retrieves the request ID associated with the message, if applicable fn request_id(&self) -> Option<&RequestId> { @@ -1152,7 +1203,7 @@ impl FromStr for JsonrpcError { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromServer { RequestFromServer(RequestFromServer), @@ -1257,7 +1308,7 @@ impl FromMessage for ServerMessage { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromClient { RequestFromClient(RequestFromClient), @@ -1266,6 +1317,13 @@ pub enum MessageFromClient { Error(RpcError), } +impl MessageFromClient { + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::RequestFromClient(request) if request.is_initialize_request()) + } +} + impl From for MessageFromClient { fn from(value: RequestFromClient) -> Self { Self::RequestFromClient(value) @@ -1450,6 +1508,225 @@ impl> From for TextContent { } } + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ClientMessages { + Single(ClientMessage), + Batch(Vec), +} + +impl ClientMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ClientMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ClientMessages::Single(client_message) => client_message.is_request(), + ClientMessages::Batch(client_messages) => client_messages.iter().any(ClientMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ClientMessages::Single(client_message) => Ok(client_message), + ClientMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessages::Batch to ClientMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ClientMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessage::Single to ClientMessages::Batch")), + ClientMessages::Batch(client_messages) => Ok(client_messages), + } + } +} + +impl From for ClientMessages { + fn from(value: ClientMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ClientMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ClientMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ServerMessages { + Single(ServerMessage), + Batch(Vec), +} + +impl ServerMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ServerMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ServerMessages::Single(server_message) => server_message.is_request(), + ServerMessages::Batch(server_messages) => server_messages.iter().any(ServerMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ServerMessages::Single(server_message) => Ok(server_message), + ServerMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessages::Batch to ServerMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ServerMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessage::Single to ServerMessages::Batch")), + ServerMessages::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for ServerMessages { + fn from(value: ServerMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ServerMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ServerMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromServer { + Single(MessageFromServer), + Batch(Vec), +} + +impl MessagesFromServer { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromServer::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromServer::Single(server_message) => server_message.is_request(), + MessagesFromServer::Batch(server_messages) => server_messages.iter().any(MessageFromServer::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromServer::Single(server_message) => Ok(server_message), + MessagesFromServer::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromServer::Batch to MessageFromServer::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromServer::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromServer::Single to MessagesFromServer::Batch")), + MessagesFromServer::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromServer { + fn from(value: MessageFromServer) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromServer { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromClient { + Single(MessageFromClient), + Batch(Vec), +} + +impl MessagesFromClient { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromClient::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromClient::Single(server_message) => server_message.is_request(), + MessagesFromClient::Batch(server_messages) => server_messages.iter().any(MessageFromClient::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromClient::Single(server_message) => Ok(server_message), + MessagesFromClient::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromClient::Batch to MessageFromClient::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromClient::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromClient::Single to MessagesFromClient::Batch")), + MessagesFromClient::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromClient { + fn from(value: MessageFromClient) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromClient { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + + #[deprecated(since = "0.4.0", note = "This trait was renamed to RpcMessage. Use RpcMessage instead.")] pub type RPCMessage = (); #[deprecated(since = "0.4.0", note = "This trait was renamed to McpMessage. Use McpMessage instead.")] @@ -2132,12 +2409,28 @@ impl From for MessageFromClient { pub enum SdkErrorCodes { CONNECTION_CLOSED = -32000, REQUEST_TIMEOUT = -32001, + RESOURCE_NOT_FOUND = -32002, + BAD_REQUEST = -32015, + SESSION_NOT_FOUND = -32016, + INVALID_REQUEST = -32600, + METHOD_NOT_FOUND = -32601, + INVALID_PARAMS = -32602, + INTERNAL_ERROR = -32603, + PARSE_ERROR = -32700, } impl core::fmt::Display for SdkErrorCodes { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { SdkErrorCodes::CONNECTION_CLOSED => write!(f, "Connection closed"), SdkErrorCodes::REQUEST_TIMEOUT => write!(f, "Request timeout"), + SdkErrorCodes::INVALID_REQUEST => write!(f, "Invalid request"), + SdkErrorCodes::METHOD_NOT_FOUND => write!(f, "Method not found"), + SdkErrorCodes::INVALID_PARAMS => write!(f, "Invalid params"), + SdkErrorCodes::INTERNAL_ERROR => write!(f, "Internal error"), + SdkErrorCodes::PARSE_ERROR => write!(f, "Parse Error"), + SdkErrorCodes::RESOURCE_NOT_FOUND => write!(f, "Resource not found"), + SdkErrorCodes::BAD_REQUEST => write!(f, "Bad request"), + SdkErrorCodes::SESSION_NOT_FOUND => write!(f, "Session not found"), } } } @@ -2146,7 +2439,7 @@ impl From for i64 { code as i64 } } -#[derive(Debug)] +#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] pub struct SdkError { ///The error type that occurred. pub code: i64, @@ -2191,6 +2484,70 @@ impl SdkError { message: SdkErrorCodes::REQUEST_TIMEOUT.to_string(), } } + pub fn session_not_found() -> Self { + Self { + code: SdkErrorCodes::SESSION_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::SESSION_NOT_FOUND.to_string(), + } + } + pub fn invalid_request() -> Self { + Self { + code: SdkErrorCodes::INVALID_REQUEST.into(), + data: None, + message: SdkErrorCodes::INVALID_REQUEST.to_string(), + } + } + pub fn method_not_found() -> Self { + Self { + code: SdkErrorCodes::METHOD_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::METHOD_NOT_FOUND.to_string(), + } + } + pub fn invalid_params() -> Self { + Self { + code: SdkErrorCodes::INVALID_PARAMS.into(), + data: None, + message: SdkErrorCodes::INVALID_PARAMS.to_string(), + } + } + pub fn internal_error() -> Self { + Self { + code: SdkErrorCodes::INTERNAL_ERROR.into(), + data: None, + message: SdkErrorCodes::INTERNAL_ERROR.to_string(), + } + } + pub fn parse_error() -> Self { + Self { + code: SdkErrorCodes::PARSE_ERROR.into(), + data: None, + message: SdkErrorCodes::PARSE_ERROR.to_string(), + } + } + pub fn resource_not_found() -> Self { + Self { + code: SdkErrorCodes::RESOURCE_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn bad_request() -> Self { + Self { + code: SdkErrorCodes::BAD_REQUEST.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn with_message(mut self, message: &str) -> Self { + self.message = message.to_string(); + self + } + pub fn with_data(mut self, data: ::std::option::Option<::serde_json::Value>) -> Self { + self.data = data; + self + } } /// Enum representing standard JSON-RPC error codes. #[allow(non_camel_case_types)] diff --git a/src/generated_schema/2025_06_18/mcp_schema.rs b/src/generated_schema/2025_06_18/mcp_schema.rs index 552a5bc..65778ec 100644 --- a/src/generated_schema/2025_06_18/mcp_schema.rs +++ b/src/generated_schema/2025_06_18/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.4.1. +/// This file is auto-generated by mcp-schema-gen v0.4.2. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 1cfdf1e7a8aa5065b7e3cb3e35e653df9542e0de -/// Generated at : 2025-07-01 14:46:41 +/// Hash : 0695a497eb50a804fc0e88c18a93a21a675d6b3e +/// Generated at : 2025-07-27 15:33:21 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version diff --git a/src/generated_schema/2025_06_18/schema_utils.rs b/src/generated_schema/2025_06_18/schema_utils.rs index 3f5c7fd..6d237e5 100644 --- a/src/generated_schema/2025_06_18/schema_utils.rs +++ b/src/generated_schema/2025_06_18/schema_utils.rs @@ -230,6 +230,29 @@ impl ClientMessage { ))) } } + + /// Returns `true` if message is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::Request(request) if request.request.is_initialize_request()) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcResponse) -> Self { + Self::Response(value) + } } impl RpcMessage for ClientMessage { @@ -391,6 +414,10 @@ impl RequestFromClient { RequestFromClient::CustomRequest(request) => request["method"].as_str().unwrap(), } } + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, RequestFromClient::ClientRequest(ClientRequest::InitializeRequest(_))) + } } impl From for RequestFromClient { @@ -746,6 +773,24 @@ impl ServerMessage { } } +impl From for ServerMessage { + fn from(value: ServerJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcResponse) -> Self { + Self::Response(value) + } +} + impl RpcMessage for ServerMessage { // Retrieves the request ID associated with the message, if applicable fn request_id(&self) -> Option<&RequestId> { @@ -1159,7 +1204,7 @@ impl FromStr for JsonrpcError { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromServer { RequestFromServer(RequestFromServer), @@ -1264,7 +1309,7 @@ impl FromMessage for ServerMessage { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromClient { RequestFromClient(RequestFromClient), @@ -1273,6 +1318,13 @@ pub enum MessageFromClient { Error(RpcError), } +impl MessageFromClient { + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::RequestFromClient(request) if request.is_initialize_request()) + } +} + impl From for MessageFromClient { fn from(value: RequestFromClient) -> Self { Self::RequestFromClient(value) @@ -1462,6 +1514,226 @@ impl> From for TextContent { } } + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ClientMessages { + Single(ClientMessage), + Batch(Vec), +} + +impl ClientMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ClientMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ClientMessages::Single(client_message) => client_message.is_request(), + ClientMessages::Batch(client_messages) => client_messages.iter().any(ClientMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ClientMessages::Single(client_message) => Ok(client_message), + ClientMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessages::Batch to ClientMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ClientMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessage::Single to ClientMessages::Batch")), + ClientMessages::Batch(client_messages) => Ok(client_messages), + } + } +} + +impl From for ClientMessages { + fn from(value: ClientMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ClientMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ClientMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ServerMessages { + Single(ServerMessage), + Batch(Vec), +} + +impl ServerMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ServerMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ServerMessages::Single(server_message) => server_message.is_request(), + ServerMessages::Batch(server_messages) => server_messages.iter().any(ServerMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ServerMessages::Single(server_message) => Ok(server_message), + ServerMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessages::Batch to ServerMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ServerMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessage::Single to ServerMessages::Batch")), + ServerMessages::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for ServerMessages { + fn from(value: ServerMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ServerMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ServerMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromServer { + Single(MessageFromServer), + Batch(Vec), +} + +impl MessagesFromServer { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromServer::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromServer::Single(server_message) => server_message.is_request(), + MessagesFromServer::Batch(server_messages) => server_messages.iter().any(MessageFromServer::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromServer::Single(server_message) => Ok(server_message), + MessagesFromServer::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromServer::Batch to MessageFromServer::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromServer::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromServer::Single to MessagesFromServer::Batch")), + MessagesFromServer::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromServer { + fn from(value: MessageFromServer) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromServer { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromClient { + Single(MessageFromClient), + Batch(Vec), +} + +impl MessagesFromClient { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromClient::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromClient::Single(server_message) => server_message.is_request(), + MessagesFromClient::Batch(server_messages) => server_messages.iter().any(MessageFromClient::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromClient::Single(server_message) => Ok(server_message), + MessagesFromClient::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromClient::Batch to MessageFromClient::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromClient::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromClient::Single to MessagesFromClient::Batch")), + MessagesFromClient::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromClient { + fn from(value: MessageFromClient) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromClient { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + + #[deprecated(since = "0.4.0", note = "This trait was renamed to RpcMessage. Use RpcMessage instead.")] pub type RPCMessage = (); #[deprecated(since = "0.4.0", note = "This trait was renamed to McpMessage. Use McpMessage instead.")] @@ -2155,12 +2427,28 @@ impl From for MessageFromClient { pub enum SdkErrorCodes { CONNECTION_CLOSED = -32000, REQUEST_TIMEOUT = -32001, + RESOURCE_NOT_FOUND = -32002, + BAD_REQUEST = -32015, + SESSION_NOT_FOUND = -32016, + INVALID_REQUEST = -32600, + METHOD_NOT_FOUND = -32601, + INVALID_PARAMS = -32602, + INTERNAL_ERROR = -32603, + PARSE_ERROR = -32700, } impl core::fmt::Display for SdkErrorCodes { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { SdkErrorCodes::CONNECTION_CLOSED => write!(f, "Connection closed"), SdkErrorCodes::REQUEST_TIMEOUT => write!(f, "Request timeout"), + SdkErrorCodes::INVALID_REQUEST => write!(f, "Invalid request"), + SdkErrorCodes::METHOD_NOT_FOUND => write!(f, "Method not found"), + SdkErrorCodes::INVALID_PARAMS => write!(f, "Invalid params"), + SdkErrorCodes::INTERNAL_ERROR => write!(f, "Internal error"), + SdkErrorCodes::PARSE_ERROR => write!(f, "Parse Error"), + SdkErrorCodes::RESOURCE_NOT_FOUND => write!(f, "Resource not found"), + SdkErrorCodes::BAD_REQUEST => write!(f, "Bad request"), + SdkErrorCodes::SESSION_NOT_FOUND => write!(f, "Session not found"), } } } @@ -2169,7 +2457,7 @@ impl From for i64 { code as i64 } } -#[derive(Debug)] +#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] pub struct SdkError { ///The error type that occurred. pub code: i64, @@ -2214,6 +2502,70 @@ impl SdkError { message: SdkErrorCodes::REQUEST_TIMEOUT.to_string(), } } + pub fn session_not_found() -> Self { + Self { + code: SdkErrorCodes::SESSION_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::SESSION_NOT_FOUND.to_string(), + } + } + pub fn invalid_request() -> Self { + Self { + code: SdkErrorCodes::INVALID_REQUEST.into(), + data: None, + message: SdkErrorCodes::INVALID_REQUEST.to_string(), + } + } + pub fn method_not_found() -> Self { + Self { + code: SdkErrorCodes::METHOD_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::METHOD_NOT_FOUND.to_string(), + } + } + pub fn invalid_params() -> Self { + Self { + code: SdkErrorCodes::INVALID_PARAMS.into(), + data: None, + message: SdkErrorCodes::INVALID_PARAMS.to_string(), + } + } + pub fn internal_error() -> Self { + Self { + code: SdkErrorCodes::INTERNAL_ERROR.into(), + data: None, + message: SdkErrorCodes::INTERNAL_ERROR.to_string(), + } + } + pub fn parse_error() -> Self { + Self { + code: SdkErrorCodes::PARSE_ERROR.into(), + data: None, + message: SdkErrorCodes::PARSE_ERROR.to_string(), + } + } + pub fn resource_not_found() -> Self { + Self { + code: SdkErrorCodes::RESOURCE_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn bad_request() -> Self { + Self { + code: SdkErrorCodes::BAD_REQUEST.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn with_message(mut self, message: &str) -> Self { + self.message = message.to_string(); + self + } + pub fn with_data(mut self, data: ::std::option::Option<::serde_json::Value>) -> Self { + self.data = data; + self + } } /// Enum representing standard JSON-RPC error codes. #[allow(non_camel_case_types)] diff --git a/src/generated_schema/draft/mcp_schema.rs b/src/generated_schema/draft/mcp_schema.rs index b81ecf0..72bbcbb 100644 --- a/src/generated_schema/draft/mcp_schema.rs +++ b/src/generated_schema/draft/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.4.1. +/// This file is auto-generated by mcp-schema-gen v0.4.2. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 1cfdf1e7a8aa5065b7e3cb3e35e653df9542e0de -/// Generated at : 2025-07-01 14:46:41 +/// Hash : 0695a497eb50a804fc0e88c18a93a21a675d6b3e +/// Generated at : 2025-07-27 15:33:21 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version @@ -1773,12 +1773,12 @@ impl ElicitRequestParamsRequestedSchema { /// "additionalProperties": {} /// }, /// "action": { -/// "description": "The user action in response to the elicitation.\n- \"accept\": User submitted the form/confirmed the action\n- \"reject\": User explicitly rejected the action\n- \"cancel\": User dismissed without making an explicit choice", +/// "description": "The user action in response to the elicitation.\n- \"accept\": User submitted the form/confirmed the action\n- \"decline\": User explicitly decline the action\n- \"cancel\": User dismissed without making an explicit choice", /// "type": "string", /// "enum": [ /// "accept", /// "cancel", -/// "reject" +/// "decline" /// ] /// }, /// "content": { @@ -1800,7 +1800,7 @@ impl ElicitRequestParamsRequestedSchema { pub struct ElicitResult { /**The user action in response to the elicitation. - "accept": User submitted the form/confirmed the action - - "reject": User explicitly rejected the action + - "decline": User explicitly decline the action - "cancel": User dismissed without making an explicit choice*/ pub action: ElicitResultAction, /**The submitted form data, only present when action is "accept". @@ -1813,19 +1813,19 @@ pub struct ElicitResult { } /**The user action in response to the elicitation. - "accept": User submitted the form/confirmed the action -- "reject": User explicitly rejected the action +- "decline": User explicitly decline the action - "cancel": User dismissed without making an explicit choice*/ /// ///
JSON schema /// /// ```json ///{ -/// "description": "The user action in response to the elicitation.\n- \"accept\": User submitted the form/confirmed the action\n- \"reject\": User explicitly rejected the action\n- \"cancel\": User dismissed without making an explicit choice", +/// "description": "The user action in response to the elicitation.\n- \"accept\": User submitted the form/confirmed the action\n- \"decline\": User explicitly decline the action\n- \"cancel\": User dismissed without making an explicit choice", /// "type": "string", /// "enum": [ /// "accept", /// "cancel", -/// "reject" +/// "decline" /// ] ///} /// ``` @@ -1836,15 +1836,15 @@ pub enum ElicitResultAction { Accept, #[serde(rename = "cancel")] Cancel, - #[serde(rename = "reject")] - Reject, + #[serde(rename = "decline")] + Decline, } impl ::std::fmt::Display for ElicitResultAction { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::Accept => write!(f, "accept"), Self::Cancel => write!(f, "cancel"), - Self::Reject => write!(f, "reject"), + Self::Decline => write!(f, "decline"), } } } diff --git a/src/generated_schema/draft/schema_utils.rs b/src/generated_schema/draft/schema_utils.rs index c92e911..0be01d0 100644 --- a/src/generated_schema/draft/schema_utils.rs +++ b/src/generated_schema/draft/schema_utils.rs @@ -108,6 +108,12 @@ impl PartialEq for RequestId { } } +impl PartialEq for &RequestId { + fn eq(&self, other: &RequestId) -> bool { + (*self).eq(other) + } +} + impl Eq for RequestId {} // Implement Hash for RequestId, so we can store it in HashMaps, HashSets, etc. @@ -225,6 +231,29 @@ impl ClientMessage { ))) } } + + /// Returns `true` if message is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::Request(request) if request.request.is_initialize_request()) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ClientMessage { + fn from(value: ClientJsonrpcResponse) -> Self { + Self::Response(value) + } } impl RpcMessage for ClientMessage { @@ -386,6 +415,10 @@ impl RequestFromClient { RequestFromClient::CustomRequest(request) => request["method"].as_str().unwrap(), } } + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, RequestFromClient::ClientRequest(ClientRequest::InitializeRequest(_))) + } } impl From for RequestFromClient { @@ -741,6 +774,24 @@ impl ServerMessage { } } +impl From for ServerMessage { + fn from(value: ServerJsonrpcNotification) -> Self { + Self::Notification(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcRequest) -> Self { + Self::Request(value) + } +} + +impl From for ServerMessage { + fn from(value: ServerJsonrpcResponse) -> Self { + Self::Response(value) + } +} + impl RpcMessage for ServerMessage { // Retrieves the request ID associated with the message, if applicable fn request_id(&self) -> Option<&RequestId> { @@ -1154,7 +1205,7 @@ impl FromStr for JsonrpcError { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromServer { RequestFromServer(RequestFromServer), @@ -1259,7 +1310,7 @@ impl FromMessage for ServerMessage { /// It provides a typed structure for the message payload while skipping internal details like /// `requestId` and protocol version, which are used solely by the transport layer and /// do not need to be exposed to the user. -#[derive(::serde::Serialize, Clone, Debug)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)] #[serde(untagged)] pub enum MessageFromClient { RequestFromClient(RequestFromClient), @@ -1268,6 +1319,13 @@ pub enum MessageFromClient { Error(RpcError), } +impl MessageFromClient { + /// Returns `true` if the request is an `InitializeRequest`. + pub fn is_initialize_request(&self) -> bool { + matches!(self, Self::RequestFromClient(request) if request.is_initialize_request()) + } +} + impl From for MessageFromClient { fn from(value: RequestFromClient) -> Self { Self::RequestFromClient(value) @@ -1457,6 +1515,226 @@ impl> From for TextContent { } } + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ClientMessages { + Single(ClientMessage), + Batch(Vec), +} + +impl ClientMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ClientMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ClientMessages::Single(client_message) => client_message.is_request(), + ClientMessages::Batch(client_messages) => client_messages.iter().any(ClientMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ClientMessages::Single(client_message) => Ok(client_message), + ClientMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessages::Batch to ClientMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ClientMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ClientMessage::Single to ClientMessages::Batch")), + ClientMessages::Batch(client_messages) => Ok(client_messages), + } + } +} + +impl From for ClientMessages { + fn from(value: ClientMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ClientMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ClientMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ServerMessages { + Single(ServerMessage), + Batch(Vec), +} + +impl ServerMessages { + pub fn is_batch(&self) -> bool { + matches!(self, ServerMessages::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + ServerMessages::Single(server_message) => server_message.is_request(), + ServerMessages::Batch(server_messages) => server_messages.iter().any(ServerMessage::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + ServerMessages::Single(server_message) => Ok(server_message), + ServerMessages::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessages::Batch to ServerMessage::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + ServerMessages::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert ServerMessage::Single to ServerMessages::Batch")), + ServerMessages::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for ServerMessages { + fn from(value: ServerMessage) -> Self { + Self::Single(value) + } +} + +impl From> for ServerMessages { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +impl Display for ServerMessages { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|err| format!("Serialization error: {err}")) + ) + } +} + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromServer { + Single(MessageFromServer), + Batch(Vec), +} + +impl MessagesFromServer { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromServer::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromServer::Single(server_message) => server_message.is_request(), + MessagesFromServer::Batch(server_messages) => server_messages.iter().any(MessageFromServer::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromServer::Single(server_message) => Ok(server_message), + MessagesFromServer::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromServer::Batch to MessageFromServer::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromServer::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromServer::Single to MessagesFromServer::Batch")), + MessagesFromServer::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromServer { + fn from(value: MessageFromServer) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromServer { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum MessagesFromClient { + Single(MessageFromClient), + Batch(Vec), +} + +impl MessagesFromClient { + pub fn is_batch(&self) -> bool { + matches!(self, MessagesFromClient::Batch(_)) + } + + pub fn includes_request(&self) -> bool { + match self { + MessagesFromClient::Single(server_message) => server_message.is_request(), + MessagesFromClient::Batch(server_messages) => server_messages.iter().any(MessageFromClient::is_request), + } + } + + pub fn as_single(self) -> result::Result { + match self { + MessagesFromClient::Single(server_message) => Ok(server_message), + MessagesFromClient::Batch(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessagesFromClient::Batch to MessageFromClient::Single")), + } + } + pub fn as_batch(self) -> result::Result, SdkError> { + match self { + MessagesFromClient::Single(_) => Err(SdkError::internal_error() + .with_message("Error: cannot convert MessageFromClient::Single to MessagesFromClient::Batch")), + MessagesFromClient::Batch(server_messages) => Ok(server_messages), + } + } +} + +impl From for MessagesFromClient { + fn from(value: MessageFromClient) -> Self { + Self::Single(value) + } +} + +impl From> for MessagesFromClient { + fn from(value: Vec) -> Self { + Self::Batch(value) + } +} + + #[deprecated(since = "0.4.0", note = "This trait was renamed to RpcMessage. Use RpcMessage instead.")] pub type RPCMessage = (); #[deprecated(since = "0.4.0", note = "This trait was renamed to McpMessage. Use McpMessage instead.")] @@ -2150,12 +2428,28 @@ impl From for MessageFromClient { pub enum SdkErrorCodes { CONNECTION_CLOSED = -32000, REQUEST_TIMEOUT = -32001, + RESOURCE_NOT_FOUND = -32002, + BAD_REQUEST = -32015, + SESSION_NOT_FOUND = -32016, + INVALID_REQUEST = -32600, + METHOD_NOT_FOUND = -32601, + INVALID_PARAMS = -32602, + INTERNAL_ERROR = -32603, + PARSE_ERROR = -32700, } impl core::fmt::Display for SdkErrorCodes { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { SdkErrorCodes::CONNECTION_CLOSED => write!(f, "Connection closed"), SdkErrorCodes::REQUEST_TIMEOUT => write!(f, "Request timeout"), + SdkErrorCodes::INVALID_REQUEST => write!(f, "Invalid request"), + SdkErrorCodes::METHOD_NOT_FOUND => write!(f, "Method not found"), + SdkErrorCodes::INVALID_PARAMS => write!(f, "Invalid params"), + SdkErrorCodes::INTERNAL_ERROR => write!(f, "Internal error"), + SdkErrorCodes::PARSE_ERROR => write!(f, "Parse Error"), + SdkErrorCodes::RESOURCE_NOT_FOUND => write!(f, "Resource not found"), + SdkErrorCodes::BAD_REQUEST => write!(f, "Bad request"), + SdkErrorCodes::SESSION_NOT_FOUND => write!(f, "Session not found"), } } } @@ -2164,7 +2458,7 @@ impl From for i64 { code as i64 } } -#[derive(Debug)] +#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] pub struct SdkError { ///The error type that occurred. pub code: i64, @@ -2209,6 +2503,70 @@ impl SdkError { message: SdkErrorCodes::REQUEST_TIMEOUT.to_string(), } } + pub fn session_not_found() -> Self { + Self { + code: SdkErrorCodes::SESSION_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::SESSION_NOT_FOUND.to_string(), + } + } + pub fn invalid_request() -> Self { + Self { + code: SdkErrorCodes::INVALID_REQUEST.into(), + data: None, + message: SdkErrorCodes::INVALID_REQUEST.to_string(), + } + } + pub fn method_not_found() -> Self { + Self { + code: SdkErrorCodes::METHOD_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::METHOD_NOT_FOUND.to_string(), + } + } + pub fn invalid_params() -> Self { + Self { + code: SdkErrorCodes::INVALID_PARAMS.into(), + data: None, + message: SdkErrorCodes::INVALID_PARAMS.to_string(), + } + } + pub fn internal_error() -> Self { + Self { + code: SdkErrorCodes::INTERNAL_ERROR.into(), + data: None, + message: SdkErrorCodes::INTERNAL_ERROR.to_string(), + } + } + pub fn parse_error() -> Self { + Self { + code: SdkErrorCodes::PARSE_ERROR.into(), + data: None, + message: SdkErrorCodes::PARSE_ERROR.to_string(), + } + } + pub fn resource_not_found() -> Self { + Self { + code: SdkErrorCodes::RESOURCE_NOT_FOUND.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn bad_request() -> Self { + Self { + code: SdkErrorCodes::BAD_REQUEST.into(), + data: None, + message: SdkErrorCodes::RESOURCE_NOT_FOUND.to_string(), + } + } + pub fn with_message(mut self, message: &str) -> Self { + self.message = message.to_string(); + self + } + pub fn with_data(mut self, data: ::std::option::Option<::serde_json::Value>) -> Self { + self.data = data; + self + } } /// Enum representing standard JSON-RPC error codes. #[allow(non_camel_case_types)] diff --git a/src/generated_schema/protocol_version.rs b/src/generated_schema/protocol_version.rs index 8f34621..55e2e7f 100644 --- a/src/generated_schema/protocol_version.rs +++ b/src/generated_schema/protocol_version.rs @@ -1,11 +1,24 @@ use std::fmt::Display; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum ProtocolVersion { V2024_11_05, V2025_03_26, V2025_06_18, Draft, } +impl ProtocolVersion { + pub fn supported_versions(include_draft: bool) -> Vec { + let mut versions = vec![ + ProtocolVersion::V2024_11_05, + ProtocolVersion::V2025_03_26, + ProtocolVersion::V2025_06_18, + ]; + if include_draft { + versions.push(ProtocolVersion::Draft); + } + versions + } +} impl Display for ProtocolVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -22,7 +35,16 @@ pub struct ParseProtocolVersionError { } impl std::fmt::Display for ParseProtocolVersionError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "Protocol version parse error: {}", self.details) + write!( + f, + "Unsupported protocol version : {}. Supported versions: {}", + self.details, + ProtocolVersion::supported_versions(false) + .iter() + .map(|p| p.to_string()) + .collect::>() + .join(", ") + ) } } impl std::error::Error for ParseProtocolVersionError {} @@ -34,6 +56,7 @@ impl TryFrom<&str> for ProtocolVersion { "2025-03-26" => Ok(ProtocolVersion::V2025_03_26), "2025-06-18" => Ok(ProtocolVersion::V2025_06_18), "DRAFT-2025-v3" => Ok(ProtocolVersion::Draft), + "DRAFT" => Ok(ProtocolVersion::Draft), other => Err(ParseProtocolVersionError { details: other.to_string(), }),