Skip to content

feat: introduce FromMessage trait #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/generated_schema/2024_11_05/mcp_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
///
/// Generated from : <https://github.com/modelcontextprotocol/specification.git>
/// Hash : bb1446ff1810a0df57989d78366d626d2c01b9d7
/// Generated at : 2025-02-19 17:00:34
/// Generated at : 2025-02-19 19:59:01
/// ----------------------------------------------------------------------------
///
/// MCP Protocol Version
Expand Down
154 changes: 154 additions & 0 deletions src/generated_schema/2024_11_05/schema_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ pub trait MCPMessage {
fn message_type(&self) -> MessageTypes;
}

/// A trait for converting a message of type `T` into `Self`.
/// This is useful for transforming mcp messages into a Type that could be serialized into a JsonrpcMessage.
///
/// For example, a ServerMessage can be constructed from a rust_mcp_schema::PingRequest by attaching a RequestId.
/// Eventually, the ServerMessage can be serialized into a valid JsonrpcMessage for transmission over the transport.
pub trait FromMessage<T>
where
Self: Sized,
{
fn from_message(message: T, request_id: Option<RequestId>) -> std::result::Result<Self, JsonrpcErrorError>;
}

//*******************************//
//** RequestId Implementations **//
//*******************************//
Expand Down Expand Up @@ -911,6 +923,148 @@ impl FromStr for JsonrpcError {
}
}

//**************************//
//** MessageFromServer **//
//**************************//

/// An enum representing various types of messages that can be sent from an MCP Server.
/// 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)]
#[serde(untagged)]
pub enum MessageFromServer {
RequestFromServer(RequestFromServer),
ResultFromServer(ResultFromServer),
NotificationFromServer(NotificationFromServer),
Error(JsonrpcErrorError),
}

impl MCPMessage for MessageFromServer {
fn is_response(&self) -> bool {
matches!(self, MessageFromServer::ResultFromServer(_))
}

fn is_request(&self) -> bool {
matches!(self, MessageFromServer::RequestFromServer(_))
}

fn is_notification(&self) -> bool {
matches!(self, MessageFromServer::NotificationFromServer(_))
}

fn is_error(&self) -> bool {
matches!(self, MessageFromServer::Error(_))
}

fn message_type(&self) -> MessageTypes {
match self {
MessageFromServer::RequestFromServer(_) => MessageTypes::Request,
MessageFromServer::ResultFromServer(_) => MessageTypes::Response,
MessageFromServer::NotificationFromServer(_) => MessageTypes::Notification,
MessageFromServer::Error(_) => MessageTypes::Error,
}
}
}

impl FromMessage<MessageFromServer> for ServerMessage {
fn from_message(
message: MessageFromServer,
request_id: Option<RequestId>,
) -> std::result::Result<Self, JsonrpcErrorError> {
match message {
MessageFromServer::RequestFromServer(request_from_server) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Request(ServerJsonrpcRequest::new(
request_id,
request_from_server,
)))
}
MessageFromServer::ResultFromServer(result_from_server) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Response(ServerJsonrpcResponse::new(
request_id,
result_from_server,
)))
}
MessageFromServer::NotificationFromServer(notification_from_server) => {
if request_id.is_some() {
return Err(JsonrpcErrorError::internal_error()
.with_message("request_id expected to be None for Notifications!".to_string()));
}
Ok(ServerMessage::Notification(ServerJsonrpcNotification::new(
notification_from_server,
)))
}
MessageFromServer::Error(jsonrpc_error_error) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Error(JsonrpcError::new(jsonrpc_error_error, request_id)))
}
}
}
}

//**************************//
//** MessageFromClient **//
//**************************//

/// An enum representing various types of messages that can be sent from an MCP Client.
/// 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)]
#[serde(untagged)]
pub enum MessageFromClient {
RequestFromClient(RequestFromClient),
ResultFromClient(ResultFromClient),
NotificationFromClient(NotificationFromClient),
Error(JsonrpcErrorError),
}

impl FromMessage<MessageFromClient> for ClientMessage {
fn from_message(
message: MessageFromClient,
request_id: Option<RequestId>,
) -> std::result::Result<Self, JsonrpcErrorError> {
match message {
MessageFromClient::RequestFromClient(request_from_client) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Request(ClientJsonrpcRequest::new(
request_id,
request_from_client,
)))
}
MessageFromClient::ResultFromClient(result_from_client) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Response(ClientJsonrpcResponse::new(
request_id,
result_from_client,
)))
}
MessageFromClient::NotificationFromClient(notification_from_client) => {
if request_id.is_some() {
return Err(JsonrpcErrorError::internal_error()
.with_message("request_id expected to be None for Notifications!".to_string()));
}

Ok(ClientMessage::Notification(ClientJsonrpcNotification::new(
notification_from_client,
)))
}
MessageFromClient::Error(jsonrpc_error_error) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Error(JsonrpcError::new(jsonrpc_error_error, request_id)))
}
}
}
}

/// BEGIN AUTO GENERATED
impl ::serde::Serialize for ClientJsonrpcRequest {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
Expand Down
2 changes: 1 addition & 1 deletion src/generated_schema/draft/mcp_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
///
/// Generated from : <https://github.com/modelcontextprotocol/specification.git>
/// Hash : bb1446ff1810a0df57989d78366d626d2c01b9d7
/// Generated at : 2025-02-19 17:00:35
/// Generated at : 2025-02-19 19:59:01
/// ----------------------------------------------------------------------------
///
/// MCP Protocol Version
Expand Down
154 changes: 154 additions & 0 deletions src/generated_schema/draft/schema_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ pub trait MCPMessage {
fn message_type(&self) -> MessageTypes;
}

/// A trait for converting a message of type `T` into `Self`.
/// This is useful for transforming mcp messages into a Type that could be serialized into a JsonrpcMessage.
///
/// For example, a ServerMessage can be constructed from a rust_mcp_schema::PingRequest by attaching a RequestId.
/// Eventually, the ServerMessage can be serialized into a valid JsonrpcMessage for transmission over the transport.
pub trait FromMessage<T>
where
Self: Sized,
{
fn from_message(message: T, request_id: Option<RequestId>) -> std::result::Result<Self, JsonrpcErrorError>;
}

//*******************************//
//** RequestId Implementations **//
//*******************************//
Expand Down Expand Up @@ -911,6 +923,148 @@ impl FromStr for JsonrpcError {
}
}

//**************************//
//** MessageFromServer **//
//**************************//

/// An enum representing various types of messages that can be sent from an MCP Server.
/// 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)]
#[serde(untagged)]
pub enum MessageFromServer {
RequestFromServer(RequestFromServer),
ResultFromServer(ResultFromServer),
NotificationFromServer(NotificationFromServer),
Error(JsonrpcErrorError),
}

impl MCPMessage for MessageFromServer {
fn is_response(&self) -> bool {
matches!(self, MessageFromServer::ResultFromServer(_))
}

fn is_request(&self) -> bool {
matches!(self, MessageFromServer::RequestFromServer(_))
}

fn is_notification(&self) -> bool {
matches!(self, MessageFromServer::NotificationFromServer(_))
}

fn is_error(&self) -> bool {
matches!(self, MessageFromServer::Error(_))
}

fn message_type(&self) -> MessageTypes {
match self {
MessageFromServer::RequestFromServer(_) => MessageTypes::Request,
MessageFromServer::ResultFromServer(_) => MessageTypes::Response,
MessageFromServer::NotificationFromServer(_) => MessageTypes::Notification,
MessageFromServer::Error(_) => MessageTypes::Error,
}
}
}

impl FromMessage<MessageFromServer> for ServerMessage {
fn from_message(
message: MessageFromServer,
request_id: Option<RequestId>,
) -> std::result::Result<Self, JsonrpcErrorError> {
match message {
MessageFromServer::RequestFromServer(request_from_server) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Request(ServerJsonrpcRequest::new(
request_id,
request_from_server,
)))
}
MessageFromServer::ResultFromServer(result_from_server) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Response(ServerJsonrpcResponse::new(
request_id,
result_from_server,
)))
}
MessageFromServer::NotificationFromServer(notification_from_server) => {
if request_id.is_some() {
return Err(JsonrpcErrorError::internal_error()
.with_message("request_id expected to be None for Notifications!".to_string()));
}
Ok(ServerMessage::Notification(ServerJsonrpcNotification::new(
notification_from_server,
)))
}
MessageFromServer::Error(jsonrpc_error_error) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ServerMessage::Error(JsonrpcError::new(jsonrpc_error_error, request_id)))
}
}
}
}

//**************************//
//** MessageFromClient **//
//**************************//

/// An enum representing various types of messages that can be sent from an MCP Client.
/// 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)]
#[serde(untagged)]
pub enum MessageFromClient {
RequestFromClient(RequestFromClient),
ResultFromClient(ResultFromClient),
NotificationFromClient(NotificationFromClient),
Error(JsonrpcErrorError),
}

impl FromMessage<MessageFromClient> for ClientMessage {
fn from_message(
message: MessageFromClient,
request_id: Option<RequestId>,
) -> std::result::Result<Self, JsonrpcErrorError> {
match message {
MessageFromClient::RequestFromClient(request_from_client) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Request(ClientJsonrpcRequest::new(
request_id,
request_from_client,
)))
}
MessageFromClient::ResultFromClient(result_from_client) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Response(ClientJsonrpcResponse::new(
request_id,
result_from_client,
)))
}
MessageFromClient::NotificationFromClient(notification_from_client) => {
if request_id.is_some() {
return Err(JsonrpcErrorError::internal_error()
.with_message("request_id expected to be None for Notifications!".to_string()));
}

Ok(ClientMessage::Notification(ClientJsonrpcNotification::new(
notification_from_client,
)))
}
MessageFromClient::Error(jsonrpc_error_error) => {
let request_id = request_id
.ok_or_else(|| JsonrpcErrorError::internal_error().with_message("request_id is None!".to_string()))?;
Ok(ClientMessage::Error(JsonrpcError::new(jsonrpc_error_error, request_id)))
}
}
}
}

/// BEGIN AUTO GENERATED
impl ::serde::Serialize for ClientJsonrpcRequest {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
Expand Down