airsprotocols_mcp/protocol/
message.rs

1//! JSON-RPC 2.0 and MCP Protocol Message Implementation
2//!
3//! This module provides a complete implementation of JSON-RPC 2.0 message types
4//! with shared serialization behavior through traits, plus MCP-specific message
5//! structures built on top of the JSON-RPC foundation.
6//!
7//! # Architecture
8//!
9//! The message layer is organized as follows:
10//! - Core JSON-RPC 2.0 message types with JsonRpcMessage trait
11//! - High-performance streaming JSON parser for large messages
12//! - MCP-specific message structures for protocol operations
13//! - Zero-copy optimizations for high-throughput scenarios
14//!
15//! # Examples
16//!
17//! ```rust
18//! use airsprotocols_mcp::protocol::{JsonRpcRequest, JsonRpcMessageTrait, RequestId};
19//! use serde_json::json;
20//!
21//! let request = JsonRpcRequest::new(
22//!     "ping",
23//!     Some(json!({"message": "hello"})),
24//!     RequestId::new_string("req-123")
25//! );
26//!
27//! // Use trait methods for consistent serialization
28//! let json = request.to_json().unwrap();
29//! let pretty_json = request.to_json_pretty().unwrap();
30//! let parsed = JsonRpcRequest::from_json(&json).unwrap();
31//!
32//! assert_eq!(request, parsed);
33//! ```
34
35// Layer 1: Standard library imports
36use std::fmt;
37
38// Layer 2: Third-party crate imports
39use bytes::{BufMut, Bytes, BytesMut};
40use serde::{Deserialize, Serialize};
41use serde_json::Value;
42
43// Layer 3: Internal module imports
44use super::constants::error_codes::{
45    INTERNAL_ERROR, INVALID_PARAMS, INVALID_REQUEST, METHOD_NOT_FOUND, PARSE_ERROR,
46};
47use super::errors::JsonRpcError;
48
49/// JSON-RPC 2.0 message validation and utilities
50impl JsonRpcMessage {
51    /// Validate a JSON-RPC message according to JSON-RPC 2.0 specification
52    ///
53    /// This function performs comprehensive validation including:
54    /// - JSON-RPC version validation (must be exactly "2.0")
55    /// - Method field validation (must be present and non-empty for requests/notifications)
56    /// - Request ID validation (proper format checking)
57    /// - Mutual exclusion of result/error in responses
58    ///
59    /// # Returns
60    ///
61    /// * `Ok(())` - Message is valid according to JSON-RPC 2.0 spec
62    /// * `Err(JsonRpcError)` - Message violates JSON-RPC 2.0 specification
63    ///
64    /// # Examples
65    ///
66    /// ```rust
67    /// use airsprotocols_mcp::protocol::{JsonRpcMessage, JsonRpcRequest, RequestId};
68    /// use serde_json::json;
69    ///
70    /// let request = JsonRpcMessage::Request(JsonRpcRequest::new(
71    ///     "ping",
72    ///     None,
73    ///     RequestId::new_number(1)
74    /// ));
75    ///
76    /// assert!(request.validate().is_ok());
77    /// ```
78    pub fn validate(&self) -> Result<(), JsonRpcError> {
79        match self {
80            JsonRpcMessage::Request(req) => Self::validate_request(req),
81            JsonRpcMessage::Response(resp) => Self::validate_response(resp),
82            JsonRpcMessage::Notification(notif) => Self::validate_notification(notif),
83        }
84    }
85
86    /// Validate a JSON-RPC request message
87    fn validate_request(request: &JsonRpcRequest) -> Result<(), JsonRpcError> {
88        // Validate JSON-RPC version
89        if request.jsonrpc != "2.0" {
90            return Err(JsonRpcError::invalid_request(format!(
91                "Invalid JSON-RPC version: expected '2.0', got '{}'",
92                request.jsonrpc
93            )));
94        }
95
96        // Validate method field
97        if request.method.is_empty() {
98            return Err(JsonRpcError::invalid_request(
99                "Method field cannot be empty",
100            ));
101        }
102
103        // Method names beginning with "rpc." are reserved for rpc-internal methods
104        if request.method.starts_with("rpc.") {
105            return Err(JsonRpcError::invalid_request(format!(
106                "Method name '{}' is reserved for JSON-RPC internal methods",
107                request.method
108            )));
109        }
110
111        Ok(())
112    }
113
114    /// Validate a JSON-RPC response message
115    fn validate_response(response: &JsonRpcResponse) -> Result<(), JsonRpcError> {
116        // Validate JSON-RPC version
117        if response.jsonrpc != "2.0" {
118            return Err(JsonRpcError::invalid_request(format!(
119                "Invalid JSON-RPC version: expected '2.0', got '{}'",
120                response.jsonrpc
121            )));
122        }
123
124        // Validate mutual exclusion of result and error
125        match (&response.result, &response.error) {
126            (Some(_), Some(_)) => {
127                return Err(JsonRpcError::invalid_request(
128                    "Response cannot have both result and error fields",
129                ));
130            }
131            (None, None) => {
132                return Err(JsonRpcError::invalid_request(
133                    "Response must have either result or error field",
134                ));
135            }
136            _ => {} // Valid: exactly one of result or error is present
137        }
138
139        Ok(())
140    }
141
142    /// Validate a JSON-RPC notification message
143    fn validate_notification(notification: &JsonRpcNotification) -> Result<(), JsonRpcError> {
144        // Validate JSON-RPC version
145        if notification.jsonrpc != "2.0" {
146            return Err(JsonRpcError::invalid_request(format!(
147                "Invalid JSON-RPC version: expected '2.0', got '{}'",
148                notification.jsonrpc
149            )));
150        }
151
152        // Validate method field
153        if notification.method.is_empty() {
154            return Err(JsonRpcError::invalid_request(
155                "Method field cannot be empty",
156            ));
157        }
158
159        // Method names beginning with "rpc." are reserved for rpc-internal methods
160        if notification.method.starts_with("rpc.") {
161            return Err(JsonRpcError::invalid_request(format!(
162                "Method name '{}' is reserved for JSON-RPC internal methods",
163                notification.method
164            )));
165        }
166
167        Ok(())
168    }
169
170    /// Create a standardized JSON-RPC error response
171    ///
172    /// This function creates a properly formatted JSON-RPC 2.0 error response
173    /// according to the specification with the correct error object structure.
174    ///
175    /// # Arguments
176    ///
177    /// * `code` - JSON-RPC error code (use constants from error_codes module)
178    /// * `message` - Human-readable error message
179    /// * `data` - Optional additional error data
180    /// * `id` - Request ID from the original request (None for parse errors)
181    ///
182    /// # Examples
183    ///
184    /// ```rust
185    /// use airsprotocols_mcp::protocol::{JsonRpcMessage, RequestId};
186    /// use airsprotocols_mcp::protocol::constants::error_codes;
187    ///
188    /// let error_response = JsonRpcMessage::create_error_response(
189    ///     error_codes::INVALID_REQUEST,
190    ///     "Missing required field",
191    ///     None,
192    ///     Some(RequestId::new_number(1))
193    /// );
194    /// ```
195    pub fn create_error_response(
196        code: i32,
197        message: &str,
198        data: Option<Value>,
199        id: Option<RequestId>,
200    ) -> Self {
201        let mut error_obj = serde_json::json!({
202            "code": code,
203            "message": message
204        });
205
206        if let Some(data) = data {
207            error_obj["data"] = data;
208        }
209
210        JsonRpcMessage::Response(JsonRpcResponse {
211            jsonrpc: "2.0".to_string(),
212            result: None,
213            error: Some(error_obj),
214            id,
215        })
216    }
217
218    /// Parse and validate a JSON-RPC message from a byte slice
219    ///
220    /// This method combines parsing and validation in a single step,
221    /// providing proper JSON-RPC error responses for invalid messages.
222    /// Works directly with byte slices for optimal performance.
223    ///
224    /// # Performance Benefits
225    /// - No intermediate string allocation
226    /// - Single UTF-8 validation + JSON parsing step
227    /// - Better cache locality for large messages
228    ///
229    /// # Arguments
230    /// * `data` - Raw byte slice containing JSON data
231    ///
232    /// # Returns
233    /// `Ok(JsonRpcMessage)` if parsing and validation succeed,
234    /// `Err(JsonRpcMessage)` containing a JSON-RPC error response if validation fails
235    ///
236    /// # Examples
237    ///
238    /// ```rust
239    /// use airsprotocols_mcp::protocol::JsonRpcMessage;
240    ///
241    /// // Parse from byte slice (most efficient)
242    /// let data = br#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
243    /// let result = JsonRpcMessage::parse_and_validate_from_slice(data);
244    /// assert!(result.is_ok());
245    ///
246    /// // Parse from string (convert to bytes first)
247    /// let json_str = r#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
248    /// let result = JsonRpcMessage::parse_and_validate_from_slice(json_str.as_bytes());
249    /// assert!(result.is_ok());
250    /// ```
251    pub fn parse_and_validate_from_slice(data: &[u8]) -> Result<Self, Self> {
252        // Parse JSON directly from byte slice (handles UTF-8 validation internally)
253        let message = match serde_json::from_slice::<JsonRpcMessage>(data) {
254            Ok(msg) => msg,
255            Err(parse_err) => {
256                return Err(Self::create_error_response(
257                    PARSE_ERROR,
258                    "Parse error",
259                    Some(serde_json::json!({
260                        "details": parse_err.to_string()
261                    })),
262                    None,
263                ));
264            }
265        };
266
267        // Then validate the parsed message
268        if let Err(validation_err) = message.validate() {
269            let error_code = match validation_err {
270                JsonRpcError::ParseError { .. } => PARSE_ERROR,
271                JsonRpcError::InvalidRequest { .. } => INVALID_REQUEST,
272                JsonRpcError::MethodNotFound { .. } => METHOD_NOT_FOUND,
273                JsonRpcError::InvalidParams { .. } => INVALID_PARAMS,
274                JsonRpcError::InternalError { .. } => INTERNAL_ERROR,
275                JsonRpcError::ServerError { code, .. } => code,
276            };
277
278            // Extract request ID if possible for proper error response
279            let request_id = match &message {
280                JsonRpcMessage::Request(req) => Some(req.id.clone()),
281                JsonRpcMessage::Response(resp) => resp.id.clone(),
282                JsonRpcMessage::Notification(_) => None, // Notifications don't have IDs
283            };
284
285            return Err(Self::create_error_response(
286                error_code,
287                &validation_err.to_string(),
288                None,
289                request_id,
290            ));
291        }
292
293        Ok(message)
294    }
295}
296
297/// JSON-RPC message types supporting requests, responses, and notifications
298///
299/// This enum unifies all JSON-RPC 2.0 message types into a single type
300/// for transport and handling. Each variant preserves the specific structure
301/// of its message type while providing unified serialization.
302#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
303#[serde(untagged)]
304pub enum JsonRpcMessage {
305    /// JSON-RPC request message
306    Request(JsonRpcRequest),
307    /// JSON-RPC response message  
308    Response(JsonRpcResponse),
309    /// JSON-RPC notification message
310    Notification(JsonRpcNotification),
311}
312
313/// Trait for JSON-RPC message serialization and deserialization
314///
315/// This trait provides common functionality for all JSON-RPC message types,
316/// eliminating code duplication and ensuring consistent serialization behavior.
317///
318/// Any type that implements `Serialize + Deserialize` automatically gets
319/// the default implementations for JSON conversion methods.
320///
321/// # Examples
322///
323/// ```rust
324/// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest, RequestId};
325///
326/// let request = JsonRpcRequest::new("ping", None, RequestId::new_number(1));
327///
328/// // Uses trait method with default implementation
329/// let json = request.to_json().unwrap();
330/// let parsed = JsonRpcRequest::from_json(&json).unwrap();
331///
332/// assert_eq!(request, parsed);
333/// ```
334#[allow(dead_code)] // Library trait methods - will be used by consuming code
335pub trait JsonRpcMessageTrait: Serialize + for<'de> Deserialize<'de> {
336    /// Serialize this message to JSON string
337    ///
338    /// # Errors
339    ///
340    /// Returns `serde_json::Error` if serialization fails, which should be rare
341    /// given the controlled structure of JSON-RPC messages.
342    ///
343    /// # Examples
344    ///
345    /// ```rust
346    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcNotification};
347    ///
348    /// let notification = JsonRpcNotification::new("heartbeat", None);
349    /// let json = notification.to_json().unwrap();
350    /// assert!(json.contains("heartbeat"));
351    /// ```
352    fn to_json(&self) -> Result<String, serde_json::Error> {
353        serde_json::to_string(self)
354    }
355
356    /// Serialize this message to pretty-printed JSON
357    ///
358    /// Useful for debugging and logging.
359    ///
360    /// # Examples
361    ///
362    /// ```rust
363    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest, RequestId};
364    ///
365    /// let request = JsonRpcRequest::new("ping", None, RequestId::new_number(1));
366    /// let pretty = request.to_json_pretty().unwrap();
367    /// println!("{}", pretty);
368    /// ```
369    fn to_json_pretty(&self) -> Result<String, serde_json::Error> {
370        serde_json::to_string_pretty(self)
371    }
372
373    /// Deserialize from JSON string
374    ///
375    /// # Examples
376    ///
377    /// ```rust
378    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest};
379    ///
380    /// let json = r#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
381    /// let request = JsonRpcRequest::from_json(json).unwrap();
382    /// assert_eq!(request.method, "ping");
383    /// ```
384    fn from_json(json: &str) -> Result<Self, serde_json::Error> {
385        serde_json::from_str(json)
386    }
387
388    /// Zero-copy serialization to buffer
389    ///
390    /// Efficiently serializes the message directly to a buffer, avoiding
391    /// intermediate string allocation. Ideal for high-performance scenarios.
392    ///
393    /// # Arguments
394    ///
395    /// * `buffer` - Target buffer to write JSON data to
396    ///
397    /// # Returns
398    ///
399    /// * `Ok(())` - Message serialized successfully
400    /// * `Err(serde_json::Error)` - Serialization failed
401    ///
402    /// # Performance
403    ///
404    /// More efficient than `to_json().into_bytes()` as it avoids the intermediate String.
405    ///
406    /// # Examples
407    ///
408    /// ```rust
409    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest, RequestId};
410    /// use bytes::BytesMut;
411    ///
412    /// let request = JsonRpcRequest::new("test", None, RequestId::new_string("1"));
413    /// let mut buffer = BytesMut::new();
414    /// request.serialize_to_buffer(&mut buffer).unwrap();
415    ///
416    /// // Can be sent directly over transport without additional allocations
417    /// assert!(buffer.len() > 0);
418    /// ```
419    fn serialize_to_buffer(&self, buffer: &mut BytesMut) -> Result<(), serde_json::Error> {
420        serde_json::to_writer(buffer.writer(), self)
421    }
422
423    /// Serialize this message to bytes
424    ///
425    /// # Returns
426    ///
427    /// * `Ok(Bytes)` - Message serialized successfully
428    /// * `Err(serde_json::Error)` - Serialization failed
429    ///
430    /// # Performance
431    ///
432    /// More efficient than `to_json().into_bytes()` as it avoids the intermediate String.
433    ///
434    /// # Examples
435    ///
436    /// ```rust
437    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest, RequestId};
438    ///
439    /// let request = JsonRpcRequest::new("test", None, RequestId::new_string("1"));
440    /// let bytes = request.to_bytes().unwrap();
441    ///
442    /// // Can be sent directly over transport without additional allocations
443    /// assert!(bytes.len() > 0);
444    /// ```
445    fn to_bytes(&self) -> Result<Bytes, serde_json::Error> {
446        let mut buffer = BytesMut::with_capacity(256);
447        self.serialize_to_buffer(&mut buffer)?;
448        Ok(buffer.freeze())
449    }
450
451    /// Deserialize a message from JSON bytes
452    ///
453    /// More efficient than string-based parsing when working with byte streams.
454    ///
455    /// # Examples
456    ///
457    /// ```rust
458    /// use airsprotocols_mcp::protocol::{JsonRpcMessageTrait, JsonRpcRequest};
459    ///
460    /// let json_bytes = br#"{"jsonrpc":"2.0","method":"ping","id":1}"#;
461    /// let request = JsonRpcRequest::from_json_bytes(json_bytes).unwrap();
462    ///
463    /// assert_eq!(request.method, "ping");
464    /// ```
465    fn from_json_bytes(json: &[u8]) -> Result<Self, serde_json::Error> {
466        serde_json::from_slice(json)
467    }
468}
469
470#[allow(dead_code)] // Library convenience methods - will be used by consuming code
471impl JsonRpcMessage {
472    /// Create a new notification message
473    pub fn from_notification(method: &str, params: Option<Value>) -> Self {
474        JsonRpcMessage::Notification(JsonRpcNotification {
475            jsonrpc: "2.0".to_string(),
476            method: method.to_string(),
477            params,
478        })
479    }
480
481    /// Create a new request message
482    pub fn from_request(method: &str, params: Option<Value>, id: RequestId) -> Self {
483        JsonRpcMessage::Request(JsonRpcRequest {
484            jsonrpc: "2.0".to_string(),
485            method: method.to_string(),
486            params,
487            id,
488        })
489    }
490
491    /// Create a new response message
492    pub fn from_response(
493        result: Option<Value>,
494        error: Option<Value>,
495        id: Option<RequestId>,
496    ) -> Self {
497        JsonRpcMessage::Response(JsonRpcResponse {
498            jsonrpc: "2.0".to_string(),
499            result,
500            error,
501            id,
502        })
503    }
504}
505
506/// Request ID supporting string, numeric, and null formats per JSON-RPC 2.0 specification
507///
508/// The JSON-RPC 2.0 specification allows request IDs to be strings, numbers, or null.
509/// This enum supports all three variants for complete JSON-RPC 2.0 compliance.
510///
511/// # Examples
512///
513/// ```rust
514/// use airsprotocols_mcp::protocol::RequestId;
515///
516/// let string_id = RequestId::String("req-123".to_string());
517/// let numeric_id = RequestId::Number(42);
518/// let null_id = RequestId::Null;
519///
520/// // Serialization preserves the original format
521/// assert_eq!(serde_json::to_string(&string_id).unwrap(), r#""req-123""#);
522/// assert_eq!(serde_json::to_string(&numeric_id).unwrap(), "42");
523/// assert_eq!(serde_json::to_string(&null_id).unwrap(), "null");
524/// ```
525#[derive(Debug, Clone, PartialEq, Eq, Hash)]
526pub enum RequestId {
527    /// String-based request identifier
528    String(String),
529    /// Numeric request identifier
530    Number(i64),
531    /// Null request identifier
532    Null,
533}
534
535impl Serialize for RequestId {
536    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
537    where
538        S: serde::Serializer,
539    {
540        match self {
541            RequestId::String(s) => serializer.serialize_str(s),
542            RequestId::Number(n) => serializer.serialize_i64(*n),
543            RequestId::Null => serializer.serialize_unit(),
544        }
545    }
546}
547
548impl<'de> Deserialize<'de> for RequestId {
549    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
550    where
551        D: serde::Deserializer<'de>,
552    {
553        use serde::de::{self, Visitor};
554
555        struct RequestIdVisitor;
556
557        impl<'de> Visitor<'de> for RequestIdVisitor {
558            type Value = RequestId;
559
560            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
561                formatter.write_str("a string, number, or null")
562            }
563
564            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
565            where
566                E: de::Error,
567            {
568                Ok(RequestId::String(value.to_string()))
569            }
570
571            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
572            where
573                E: de::Error,
574            {
575                Ok(RequestId::Number(value))
576            }
577
578            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
579            where
580                E: de::Error,
581            {
582                if value <= i64::MAX as u64 {
583                    Ok(RequestId::Number(value as i64))
584                } else {
585                    Err(E::custom("number too large for i64"))
586                }
587            }
588
589            fn visit_unit<E>(self) -> Result<Self::Value, E>
590            where
591                E: de::Error,
592            {
593                Ok(RequestId::Null)
594            }
595        }
596
597        deserializer.deserialize_any(RequestIdVisitor)
598    }
599}
600
601impl RequestId {
602    /// Create a new string-based request ID
603    ///
604    /// # Examples
605    ///
606    /// ```rust
607    /// use airsprotocols_mcp::protocol::RequestId;
608    ///
609    /// let id = RequestId::new_string("my-request-id");
610    /// ```
611    pub fn new_string(id: impl Into<String>) -> Self {
612        RequestId::String(id.into())
613    }
614
615    /// Create a new numeric request ID
616    ///
617    /// # Examples
618    ///
619    /// ```rust
620    /// use airsprotocols_mcp::protocol::RequestId;
621    ///
622    /// let id = RequestId::new_number(123);
623    /// ```
624    pub fn new_number(id: i64) -> Self {
625        RequestId::Number(id)
626    }
627
628    /// Create a new null request ID
629    ///
630    /// # Examples
631    ///
632    /// ```rust
633    /// use airsprotocols_mcp::protocol::RequestId;
634    ///
635    /// let id = RequestId::new_null();
636    /// ```
637    pub fn new_null() -> Self {
638        RequestId::Null
639    }
640}
641
642impl fmt::Display for RequestId {
643    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
644        match self {
645            RequestId::String(s) => write!(f, "{s}"),
646            RequestId::Number(n) => write!(f, "{n}"),
647            RequestId::Null => write!(f, "null"),
648        }
649    }
650}
651
652/// JSON-RPC 2.0 Request Message
653///
654/// Represents a request to invoke a method on the remote peer. All fields are required
655/// except for params, which may be omitted if the method takes no parameters.
656///
657/// # JSON-RPC 2.0 Specification Compliance
658///
659/// - `jsonrpc`: MUST be exactly "2.0"
660/// - `method`: MUST be a String containing the name of the method to invoke
661/// - `params`: MAY be omitted. If present, MUST be Structured values (Object) or Ordered values (Array)
662/// - `id`: MUST be a String, Number, or NULL value
663///
664/// # Examples
665///
666/// ```rust
667/// use airsprotocols_mcp::protocol::{JsonRpcRequest, JsonRpcMessageTrait, RequestId};
668/// use serde_json::json;
669///
670/// // Request with parameters
671/// let request = JsonRpcRequest::new(
672///     "subtract",
673///     Some(json!([42, 23])),
674///     RequestId::new_number(1)
675/// );
676///
677/// // Use trait methods for serialization
678/// let json = request.to_json().unwrap();
679/// let parsed = JsonRpcRequest::from_json(&json).unwrap();
680/// assert_eq!(request, parsed);
681/// ```
682#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
683pub struct JsonRpcRequest {
684    /// Protocol version - always "2.0" for JSON-RPC 2.0 compliance
685    pub jsonrpc: String,
686
687    /// Name of the method to invoke
688    pub method: String,
689
690    /// Parameters for the method (null, object, or array)
691    #[serde(skip_serializing_if = "Option::is_none")]
692    pub params: Option<Value>,
693
694    /// Unique identifier for this request
695    pub id: RequestId,
696}
697
698impl JsonRpcRequest {
699    /// Create a new JSON-RPC 2.0 request
700    ///
701    /// # Parameters
702    ///
703    /// - `method`: Name of the method to invoke
704    /// - `params`: Optional parameters (will be serialized as JSON)
705    /// - `id`: Unique request identifier
706    ///
707    /// # Examples
708    ///
709    /// ```rust
710    /// use airsprotocols_mcp::protocol::{JsonRpcRequest, RequestId};
711    /// use serde_json::json;
712    ///
713    /// let request = JsonRpcRequest::new(
714    ///     "calculate",
715    ///     Some(json!({"operation": "add", "values": [1, 2, 3]})),
716    ///     RequestId::new_string("calc-123")
717    /// );
718    /// ```
719    pub fn new(method: impl Into<String>, params: Option<Value>, id: RequestId) -> Self {
720        Self {
721            jsonrpc: "2.0".to_string(),
722            method: method.into(),
723            params,
724            id,
725        }
726    }
727
728    /// Create and validate a new JSON-RPC 2.0 request
729    ///
730    /// This function performs validation during construction to catch
731    /// invalid requests early.
732    ///
733    /// # Parameters
734    ///
735    /// - `method`: Name of the method to invoke (must be non-empty)
736    /// - `params`: Optional parameters (will be serialized as JSON)
737    /// - `id`: Unique request identifier
738    ///
739    /// # Returns
740    ///
741    /// * `Ok(JsonRpcRequest)` - Valid request created successfully
742    /// * `Err(JsonRpcError)` - Request violates JSON-RPC 2.0 specification
743    ///
744    /// # Examples
745    ///
746    /// ```rust
747    /// use airsprotocols_mcp::protocol::{JsonRpcRequest, RequestId};
748    /// use serde_json::json;
749    ///
750    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
751    /// let request = JsonRpcRequest::new_validated(
752    ///     "calculate",
753    ///     Some(json!({"operation": "add", "values": [1, 2, 3]})),
754    ///     RequestId::new_string("calc-123")
755    /// )?;
756    /// # Ok(())
757    /// # }
758    /// ```
759    pub fn new_validated(
760        method: impl Into<String>,
761        params: Option<Value>,
762        id: RequestId,
763    ) -> Result<Self, JsonRpcError> {
764        let method_str = method.into();
765
766        // Validate method field
767        if method_str.is_empty() {
768            return Err(JsonRpcError::invalid_request(
769                "Method field cannot be empty",
770            ));
771        }
772
773        // Method names beginning with "rpc." are reserved for rpc-internal methods
774        if method_str.starts_with("rpc.") {
775            return Err(JsonRpcError::invalid_request(format!(
776                "Method name '{method_str}' is reserved for JSON-RPC internal methods"
777            )));
778        }
779
780        Ok(Self {
781            jsonrpc: "2.0".to_string(),
782            method: method_str,
783            params,
784            id,
785        })
786    }
787}
788
789// Automatic trait implementation - no more duplicated code!
790impl JsonRpcMessageTrait for JsonRpcRequest {}
791
792/// JSON-RPC 2.0 Response Message
793///
794/// Represents the response to a JSON-RPC request. Contains either a successful result
795/// or error information, but never both (mutual exclusion enforced by JSON-RPC spec).
796///
797/// # JSON-RPC 2.0 Specification Compliance
798///
799/// - `jsonrpc`: MUST be exactly "2.0"
800/// - `result`: MUST exist and contain the result if the call succeeded (omitted on error)
801/// - `error`: MUST exist and contain error details if the call failed (omitted on success)
802/// - `id`: MUST be the same as the request that triggered this response, or null for parse errors
803///
804/// # Examples
805///
806/// ```rust
807/// use airsprotocols_mcp::protocol::{JsonRpcResponse, JsonRpcMessageTrait, RequestId};
808/// use serde_json::json;
809///
810/// // Success response
811/// let success = JsonRpcResponse::success(
812///     json!({"result": "operation completed"}),
813///     RequestId::new_number(1)
814/// );
815///
816/// // Use trait methods for serialization
817/// let json = success.to_json().unwrap();
818/// let parsed = JsonRpcResponse::from_json(&json).unwrap();
819/// assert_eq!(success, parsed);
820/// ```
821#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
822pub struct JsonRpcResponse {
823    /// Protocol version - always "2.0" for JSON-RPC 2.0 compliance
824    pub jsonrpc: String,
825
826    /// Result of successful method invocation (mutually exclusive with error)
827    #[serde(skip_serializing_if = "Option::is_none")]
828    pub result: Option<Value>,
829
830    /// Error information for failed method invocation (mutually exclusive with result)
831    #[serde(skip_serializing_if = "Option::is_none")]
832    pub error: Option<Value>,
833
834    /// Request identifier from the original request (null for parse errors)
835    #[serde(skip_serializing_if = "Option::is_none")]
836    pub id: Option<RequestId>,
837}
838
839impl JsonRpcResponse {
840    /// Create a successful JSON-RPC 2.0 response
841    ///
842    /// # Parameters
843    ///
844    /// - `result`: The successful result of the method invocation
845    /// - `id`: Request identifier from the original request
846    ///
847    /// # Examples
848    ///
849    /// ```rust
850    /// use airsprotocols_mcp::protocol::{JsonRpcResponse, RequestId};
851    /// use serde_json::json;
852    ///
853    /// let response = JsonRpcResponse::success(
854    ///     json!({"status": "ok", "data": [1, 2, 3]}),
855    ///     RequestId::new_string("req-456")
856    /// );
857    /// ```
858    pub fn success(result: Value, id: RequestId) -> Self {
859        Self {
860            jsonrpc: "2.0".to_string(),
861            result: Some(result),
862            error: None,
863            id: Some(id),
864        }
865    }
866
867    /// Create an error JSON-RPC 2.0 response
868    ///
869    /// # Parameters
870    ///
871    /// - `error`: Error information (should conform to JSON-RPC error object structure)
872    /// - `id`: Request identifier from the original request (None for parse errors)
873    ///
874    /// # Examples
875    ///
876    /// ```rust
877    /// use airsprotocols_mcp::protocol::{JsonRpcResponse, RequestId};
878    /// use serde_json::json;
879    ///
880    /// let response = JsonRpcResponse::error(
881    ///     json!({"code": -32602, "message": "Invalid params"}),
882    ///     Some(RequestId::new_number(789))
883    /// );
884    /// ```
885    pub fn error(error: Value, id: Option<RequestId>) -> Self {
886        Self {
887            jsonrpc: "2.0".to_string(),
888            result: None,
889            error: Some(error),
890            id,
891        }
892    }
893
894    /// Create a standardized JSON-RPC 2.0 error response
895    ///
896    /// This function creates a properly formatted JSON-RPC 2.0 error response
897    /// with the correct error object structure according to the specification.
898    ///
899    /// # Parameters
900    ///
901    /// - `code`: JSON-RPC error code (use constants from error_codes module)
902    /// - `message`: Human-readable error message
903    /// - `data`: Optional additional error data
904    /// - `id`: Request identifier from the original request (None for parse errors)
905    ///
906    /// # Examples
907    ///
908    /// ```rust
909    /// use airsprotocols_mcp::protocol::{JsonRpcResponse, RequestId};
910    /// use airsprotocols_mcp::protocol::constants::error_codes;
911    ///
912    /// let response = JsonRpcResponse::error_standard(
913    ///     error_codes::INVALID_PARAMS,
914    ///     "Missing required parameter 'name'",
915    ///     Some(serde_json::json!({"parameter": "name"})),
916    ///     Some(RequestId::new_number(123))
917    /// );
918    /// ```
919    pub fn error_standard(
920        code: i32,
921        message: &str,
922        data: Option<Value>,
923        id: Option<RequestId>,
924    ) -> Self {
925        let mut error_obj = serde_json::json!({
926            "code": code,
927            "message": message
928        });
929
930        if let Some(data) = data {
931            error_obj["data"] = data;
932        }
933
934        Self {
935            jsonrpc: "2.0".to_string(),
936            result: None,
937            error: Some(error_obj),
938            id,
939        }
940    }
941
942    /// Create a parse error response (-32700)
943    pub fn parse_error(message: &str, data: Option<Value>) -> Self {
944        Self::error_standard(
945            PARSE_ERROR,
946            message,
947            data,
948            None, // Parse errors don't have request IDs
949        )
950    }
951
952    /// Create an invalid request error response (-32600)
953    pub fn invalid_request(message: &str, data: Option<Value>, id: Option<RequestId>) -> Self {
954        Self::error_standard(INVALID_REQUEST, message, data, id)
955    }
956
957    /// Create a method not found error response (-32601)
958    pub fn method_not_found(method: &str, id: Option<RequestId>) -> Self {
959        Self::error_standard(
960            METHOD_NOT_FOUND,
961            &format!("Method '{method}' not found"),
962            Some(serde_json::json!({"method": method})),
963            id,
964        )
965    }
966
967    /// Create an invalid params error response (-32602)
968    pub fn invalid_params(message: &str, data: Option<Value>, id: Option<RequestId>) -> Self {
969        Self::error_standard(INVALID_PARAMS, message, data, id)
970    }
971
972    /// Create an internal error response (-32603)
973    pub fn internal_error(message: &str, data: Option<Value>, id: Option<RequestId>) -> Self {
974        Self::error_standard(INTERNAL_ERROR, message, data, id)
975    }
976}
977
978// Automatic trait implementation - elegant and DRY!
979impl JsonRpcMessageTrait for JsonRpcResponse {}
980
981/// JSON-RPC 2.0 Notification Message
982///
983/// Represents a notification - a request that does not expect a response.
984/// Notifications are "fire and forget" messages used for events or one-way communication.
985///
986/// # JSON-RPC 2.0 Specification Compliance
987///
988/// - `jsonrpc`: MUST be exactly "2.0"
989/// - `method`: MUST be a String containing the name of the notification method
990/// - `params`: MAY be omitted. If present, MUST be Structured values (Object) or Ordered values (Array)
991/// - `id`: MUST NOT be present (this is what distinguishes notifications from requests)
992///
993/// # Examples
994///
995/// ```rust
996/// use airsprotocols_mcp::protocol::{JsonRpcNotification, JsonRpcMessageTrait};
997/// use serde_json::json;
998///
999/// // Notification with parameters
1000/// let notification = JsonRpcNotification::new(
1001///     "user_logged_in",
1002///     Some(json!({"user_id": 12345, "timestamp": "2025-07-28T10:30:00Z"}))
1003/// );
1004///
1005/// // Use trait methods for serialization
1006/// let json = notification.to_json().unwrap();
1007/// let parsed = JsonRpcNotification::from_json(&json).unwrap();
1008/// assert_eq!(notification, parsed);
1009/// ```
1010#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1011pub struct JsonRpcNotification {
1012    /// Protocol version - always "2.0" for JSON-RPC 2.0 compliance
1013    pub jsonrpc: String,
1014
1015    /// Name of the notification method
1016    pub method: String,
1017
1018    /// Parameters for the notification (null, object, or array)
1019    #[serde(skip_serializing_if = "Option::is_none")]
1020    pub params: Option<Value>,
1021    // Note: No `id` field - this is what makes it a notification instead of a request
1022}
1023
1024impl JsonRpcNotification {
1025    /// Create a new JSON-RPC 2.0 notification
1026    ///
1027    /// # Parameters
1028    ///
1029    /// - `method`: Name of the notification method
1030    /// - `params`: Optional parameters (will be serialized as JSON)
1031    ///
1032    /// # Examples
1033    ///
1034    /// ```rust
1035    /// use airsprotocols_mcp::protocol::JsonRpcNotification;
1036    /// use serde_json::json;
1037    ///
1038    /// let notification = JsonRpcNotification::new(
1039    ///     "status_changed",
1040    ///     Some(json!({"old_status": "pending", "new_status": "active"}))
1041    /// );
1042    /// ```
1043    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
1044        Self {
1045            jsonrpc: "2.0".to_string(),
1046            method: method.into(),
1047            params,
1048        }
1049    }
1050
1051    /// Create and validate a new JSON-RPC 2.0 notification
1052    ///
1053    /// This function performs validation during construction to catch
1054    /// invalid notifications early.
1055    ///
1056    /// # Parameters
1057    ///
1058    /// - `method`: Name of the notification method (must be non-empty)
1059    /// - `params`: Optional parameters (will be serialized as JSON)
1060    ///
1061    /// # Returns
1062    ///
1063    /// * `Ok(JsonRpcNotification)` - Valid notification created successfully
1064    /// * `Err(JsonRpcError)` - Notification violates JSON-RPC 2.0 specification
1065    ///
1066    /// # Examples
1067    ///
1068    /// ```rust
1069    /// use airsprotocols_mcp::protocol::JsonRpcNotification;
1070    /// use serde_json::json;
1071    ///
1072    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1073    /// let notification = JsonRpcNotification::new_validated(
1074    ///     "status_changed",
1075    ///     Some(json!({"old_status": "pending", "new_status": "active"}))
1076    /// )?;
1077    /// # Ok(())
1078    /// # }
1079    /// ```
1080    pub fn new_validated(
1081        method: impl Into<String>,
1082        params: Option<Value>,
1083    ) -> Result<Self, JsonRpcError> {
1084        let method_str = method.into();
1085
1086        // Validate method field
1087        if method_str.is_empty() {
1088            return Err(JsonRpcError::invalid_request(
1089                "Method field cannot be empty",
1090            ));
1091        }
1092
1093        // Method names beginning with "rpc." are reserved for rpc-internal methods
1094        if method_str.starts_with("rpc.") {
1095            return Err(JsonRpcError::invalid_request(format!(
1096                "Method name '{method_str}' is reserved for JSON-RPC internal methods"
1097            )));
1098        }
1099
1100        Ok(Self {
1101            jsonrpc: "2.0".to_string(),
1102            method: method_str,
1103            params,
1104        })
1105    }
1106}
1107
1108// Automatic trait implementation - consistency without repetition!
1109impl JsonRpcMessageTrait for JsonRpcNotification {}
1110
1111// Implement the trait for the unified message enum
1112impl JsonRpcMessageTrait for JsonRpcMessage {}
1113
1114// TODO(DEBT-ARCH): Add MCP-specific message structures and protocol optimizations
1115// Will be implemented once the core migration is complete
1116// Reference: MCP protocol specification for message structures