mcp_ectors/messages/mcp/
mcp_messages.rs

1use actix::prelude::*;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use mcp_spec::protocol::JsonRpcResponse;
5use mcp_spec::protocol::JsonRpcRequest;
6pub const JSONRPC_VERSION: &str = "2.0";
7
8/// A unified type for handling all JSON-RPC requests and notifications.
9#[derive(Message)]
10#[rtype(result = "Result<JsonRpcResponse, ()>")]
11pub enum JsonRpcRequestMessage {
12    Initialize(InitializeRequest),
13    Ping(PingRequest),
14    Complete(CompleteRequest),
15    ListRoots(ListRootsRequest),
16    ListPrompts(ListPromptsRequest),
17    GetPrompt(GetPromptRequest),
18    ListResources(ListResourcesRequest),
19    ListResourceTemplates(ListResourceTemplatesRequest),
20    ReadResource(ReadResourceRequest),
21    Subscribe(SubscribeRequest),
22    Unsubscribe(UnsubscribeRequest),
23    CallTool(CallToolRequest),
24    ListTools(ListToolsRequest),
25    SetLevel(SetLevelRequest),
26    CreateMessage(CreateMessageRequest),
27}
28
29/// A unified type for handling all JSON-RPC notifications.
30#[derive(Message)]
31#[rtype(result = "()")]
32pub enum JsonRpcNotificationMessage {
33    Initialized(InitializedNotification),
34    Cancelled(CancelledNotification),
35    Progress(ProgressNotification),
36    RootsListChanged(RootsListChangedNotification),
37    LoggingMessage(LoggingMessageNotification),
38    ResourceListChanged(ResourceListChangedNotification),
39    ResourceUpdated(ResourceUpdatedNotification),
40    ToolListChanged(ToolListChangedNotification),
41    PromptListChanged(PromptListChangedNotification),
42}
43
44
45/* ==== REQUESTS (Expecting a Response) ==== */
46
47macro_rules! create_request {
48    ($struct_name:ident, $method:expr) => {
49        #[derive(Message, Debug, Clone, Serialize, Deserialize,)]
50        #[rtype(result = "Result<JsonRpcResponse, ()>")]
51        pub struct $struct_name {
52            pub request: JsonRpcRequest,
53        }
54
55        impl $struct_name {
56            pub const METHOD: &'static str = $method;
57        }
58    };
59}
60
61// Define all MCP standard requests
62create_request!(InitializeRequest, "initialize");
63create_request!(InitializedNotificationRequest, "notifications/initialized");
64create_request!(PingRequest, "ping");
65create_request!(CompleteRequest, "completion/complete");
66create_request!(ListRootsRequest, "roots/list");
67create_request!(ListPromptsRequest, "prompts/list");
68create_request!(GetPromptRequest, "prompts/get");
69create_request!(ListResourcesRequest, "resources/list");
70create_request!(ListResourceTemplatesRequest, "resources/templates/list");
71create_request!(ReadResourceRequest, "resources/read");
72create_request!(SubscribeRequest, "resources/subscribe");
73create_request!(UnsubscribeRequest, "resources/unsubscribe");
74create_request!(CallToolRequest, "tools/call");
75create_request!(ListToolsRequest, "tools/list");
76create_request!(SetLevelRequest, "logging/setLevel");
77create_request!(CreateMessageRequest, "sampling/createMessage");
78
79/* ==== NOTIFICATIONS (Do Not Expect a Response) ==== */
80
81macro_rules! create_notification {
82    ($struct_name:ident, $method:expr) => {
83        #[derive(Message, Debug, Clone, Serialize, Deserialize,)]
84        #[rtype(result = "()")]
85        pub struct $struct_name {
86            pub params: Option<Value>,
87        }
88
89        impl $struct_name {
90            pub const METHOD: &'static str = $method;
91        }
92    };
93}
94
95// Define all MCP standard notifications
96create_notification!(InitializedNotification, "notifications/initialized");
97create_notification!(CancelledNotification, "notifications/cancelled");
98create_notification!(ProgressNotification, "notifications/progress");
99create_notification!(RootsListChangedNotification, "notifications/roots/list_changed");
100create_notification!(LoggingMessageNotification, "notifications/message");
101create_notification!(ResourceListChangedNotification, "notifications/resources/list_changed");
102create_notification!(ResourceUpdatedNotification, "notifications/resources/updated");
103create_notification!(ToolListChangedNotification, "notifications/tools/list_changed");
104create_notification!(PromptListChangedNotification, "notifications/prompts/list_changed");
105
106/* ==== Message Type Enum for Handling All Requests/Notifications ==== */
107
108/// Enum representing all MCP messages.
109#[derive(Debug, Clone)]
110pub enum McpMessage {
111    Request(JsonRpcRequest),
112    Response(JsonRpcResponse),
113    Notification(String, Option<Value>), // (method, params)
114}
115
116impl McpMessage {
117    /// Parses a JSON-RPC message into a structured `McpMessage`.
118    pub fn from_json(value: Value) -> Result<Self, String> {
119        if let Some(jsonrpc) = value.get("jsonrpc") {
120            if jsonrpc != JSONRPC_VERSION {
121                return Err("Invalid JSON-RPC version".to_string());
122            }
123        }
124
125        if let Some(method) = value.get("method").and_then(|v| v.as_str()) {
126            if value.get("id").is_some() {
127                // It's a request
128                serde_json::from_value::<JsonRpcRequest>(value.clone())
129                    .map(McpMessage::Request)
130                    .map_err(|e| e.to_string())
131            } else {
132                // It's a notification
133                let params = value.get("params").cloned();
134                Ok(McpMessage::Notification(method.to_string(), params))
135            }
136        } else if value.get("id").is_some() {
137            // It's a response
138            serde_json::from_value::<JsonRpcResponse>(value.clone())
139                .map(McpMessage::Response)
140                .map_err(|e| e.to_string())
141        } else {
142            Err("Unknown MCP message type".to_string())
143        }
144    }
145}