codeprism_mcp/
protocol.rs

1//! MCP Protocol types and JSON-RPC 2.0 implementation
2//!
3//! This module implements the core Model Context Protocol types according to the specification.
4//! All message types follow JSON-RPC 2.0 format as required by MCP.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// JSON-RPC 2.0 Request message
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct JsonRpcRequest {
12    /// JSON-RPC version, must be "2.0"
13    pub jsonrpc: String,
14    /// Request ID (number or string)
15    pub id: serde_json::Value,
16    /// Method name
17    pub method: String,
18    /// Optional parameters
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub params: Option<serde_json::Value>,
21}
22
23/// JSON-RPC 2.0 Response message
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct JsonRpcResponse {
26    /// JSON-RPC version, must be "2.0"
27    pub jsonrpc: String,
28    /// Request ID matching the original request
29    pub id: serde_json::Value,
30    /// Successful result (mutually exclusive with error)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub result: Option<serde_json::Value>,
33    /// Error information (mutually exclusive with result)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub error: Option<JsonRpcError>,
36}
37
38/// JSON-RPC 2.0 Notification message (no response expected)
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct JsonRpcNotification {
41    /// JSON-RPC version, must be "2.0"
42    pub jsonrpc: String,
43    /// Method name
44    pub method: String,
45    /// Optional parameters
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub params: Option<serde_json::Value>,
48}
49
50/// JSON-RPC 2.0 Error object
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct JsonRpcError {
53    /// Error code
54    pub code: i32,
55    /// Error message
56    pub message: String,
57    /// Optional additional error data
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub data: Option<serde_json::Value>,
60}
61
62/// MCP Initialize request parameters
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct InitializeParams {
65    /// Protocol version supported by client
66    #[serde(rename = "protocolVersion")]
67    pub protocol_version: String,
68    /// Client capabilities
69    pub capabilities: ClientCapabilities,
70    /// Client implementation information
71    #[serde(rename = "clientInfo")]
72    pub client_info: ClientInfo,
73}
74
75/// MCP Initialize response
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct InitializeResult {
78    /// Protocol version supported by server
79    #[serde(rename = "protocolVersion")]
80    pub protocol_version: String,
81    /// Server capabilities
82    pub capabilities: ServerCapabilities,
83    /// Server implementation information
84    #[serde(rename = "serverInfo")]
85    pub server_info: ServerInfo,
86}
87
88/// Client capabilities
89#[derive(Debug, Clone, Serialize, Deserialize, Default)]
90pub struct ClientCapabilities {
91    /// Experimental capabilities
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub experimental: Option<HashMap<String, serde_json::Value>>,
94    /// Sampling capability
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub sampling: Option<SamplingCapability>,
97}
98
99/// Server capabilities
100#[derive(Debug, Clone, Serialize, Deserialize, Default)]
101pub struct ServerCapabilities {
102    /// Experimental capabilities
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub experimental: Option<HashMap<String, serde_json::Value>>,
105    /// Resources capability
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub resources: Option<crate::resources::ResourceCapabilities>,
108    /// Tools capability
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub tools: Option<crate::tools::ToolCapabilities>,
111    /// Prompts capability
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub prompts: Option<crate::prompts::PromptCapabilities>,
114}
115
116/// Sampling capability
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct SamplingCapability {}
119
120/// Client information
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ClientInfo {
123    /// Client name
124    pub name: String,
125    /// Client version
126    pub version: String,
127}
128
129/// Server information
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct ServerInfo {
132    /// Server name
133    pub name: String,
134    /// Server version
135    pub version: String,
136}
137
138impl JsonRpcRequest {
139    /// Create a new JSON-RPC request
140    pub fn new(id: serde_json::Value, method: String, params: Option<serde_json::Value>) -> Self {
141        Self {
142            jsonrpc: "2.0".to_string(),
143            id,
144            method,
145            params,
146        }
147    }
148}
149
150impl JsonRpcResponse {
151    /// Create a successful JSON-RPC response
152    pub fn success(id: serde_json::Value, result: serde_json::Value) -> Self {
153        Self {
154            jsonrpc: "2.0".to_string(),
155            id,
156            result: Some(result),
157            error: None,
158        }
159    }
160
161    /// Create an error JSON-RPC response
162    pub fn error(id: serde_json::Value, error: JsonRpcError) -> Self {
163        Self {
164            jsonrpc: "2.0".to_string(),
165            id,
166            result: None,
167            error: Some(error),
168        }
169    }
170}
171
172impl JsonRpcNotification {
173    /// Create a new JSON-RPC notification
174    pub fn new(method: String, params: Option<serde_json::Value>) -> Self {
175        Self {
176            jsonrpc: "2.0".to_string(),
177            method,
178            params,
179        }
180    }
181}
182
183impl JsonRpcError {
184    /// Standard JSON-RPC error codes
185    pub const PARSE_ERROR: i32 = -32700;
186    pub const INVALID_REQUEST: i32 = -32600;
187    pub const METHOD_NOT_FOUND: i32 = -32601;
188    pub const INVALID_PARAMS: i32 = -32602;
189    pub const INTERNAL_ERROR: i32 = -32603;
190
191    /// Create a new JSON-RPC error
192    pub fn new(code: i32, message: String, data: Option<serde_json::Value>) -> Self {
193        Self {
194            code,
195            message,
196            data,
197        }
198    }
199
200    /// Create a method not found error
201    pub fn method_not_found(method: &str) -> Self {
202        Self::new(
203            Self::METHOD_NOT_FOUND,
204            format!("Method not found: {}", method),
205            None,
206        )
207    }
208
209    /// Create an invalid parameters error
210    pub fn invalid_params(message: String) -> Self {
211        Self::new(Self::INVALID_PARAMS, message, None)
212    }
213
214    /// Create an internal error
215    pub fn internal_error(message: String) -> Self {
216        Self::new(Self::INTERNAL_ERROR, message, None)
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223
224    #[test]
225    fn test_json_rpc_request_serialization() {
226        let request = JsonRpcRequest::new(
227            serde_json::Value::Number(1.into()),
228            "test_method".to_string(),
229            Some(serde_json::json!({"param": "value"})),
230        );
231
232        let json = serde_json::to_string(&request).unwrap();
233        let deserialized: JsonRpcRequest = serde_json::from_str(&json).unwrap();
234
235        assert_eq!(request.jsonrpc, deserialized.jsonrpc);
236        assert_eq!(request.id, deserialized.id);
237        assert_eq!(request.method, deserialized.method);
238        assert_eq!(request.params, deserialized.params);
239    }
240
241    #[test]
242    fn test_json_rpc_response_success() {
243        let response = JsonRpcResponse::success(
244            serde_json::Value::Number(1.into()),
245            serde_json::json!({"success": true}),
246        );
247
248        assert_eq!(response.jsonrpc, "2.0");
249        assert!(response.result.is_some());
250        assert!(response.error.is_none());
251    }
252
253    #[test]
254    fn test_json_rpc_response_error() {
255        let error = JsonRpcError::method_not_found("unknown_method");
256        let response = JsonRpcResponse::error(serde_json::Value::Number(1.into()), error);
257
258        assert_eq!(response.jsonrpc, "2.0");
259        assert!(response.result.is_none());
260        assert!(response.error.is_some());
261    }
262
263    #[test]
264    fn test_initialize_params() {
265        let params = InitializeParams {
266            protocol_version: "2024-11-05".to_string(),
267            capabilities: ClientCapabilities::default(),
268            client_info: ClientInfo {
269                name: "test-client".to_string(),
270                version: "1.0.0".to_string(),
271            },
272        };
273
274        let json = serde_json::to_string(&params).unwrap();
275        let deserialized: InitializeParams = serde_json::from_str(&json).unwrap();
276
277        assert_eq!(params.protocol_version, deserialized.protocol_version);
278        assert_eq!(params.client_info.name, deserialized.client_info.name);
279    }
280}