turul_mcp_protocol_2025_06_18/
ping.rs

1//! MCP Ping Protocol Types
2//!
3//! This module defines types for the ping functionality in MCP.
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use serde_json::Value;
8
9/// Request for ping (per MCP spec)
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct PingRequest {
13    /// Method name (always "ping")
14    pub method: String,
15    /// No parameters for ping
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub params: Option<Value>,
18}
19
20impl PingRequest {
21    pub fn new() -> Self {
22        Self {
23            method: "ping".to_string(),
24            params: None,
25        }
26    }
27}
28
29impl Default for PingRequest {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35/// Empty result for successful operations (per MCP spec)
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct EmptyResult {
39    /// Meta information (follows MCP Result interface)
40    #[serde(
41        default,
42        skip_serializing_if = "Option::is_none",
43        alias = "_meta",
44        rename = "_meta"
45    )]
46    pub meta: Option<HashMap<String, Value>>,
47}
48
49impl EmptyResult {
50    pub fn new() -> Self {
51        Self {
52            meta: None,
53        }
54    }
55
56    pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
57        self.meta = Some(meta);
58        self
59    }
60}
61
62impl Default for EmptyResult {
63    fn default() -> Self {
64        Self::new()
65    }
66}
67
68// Trait implementations for EmptyResult
69use crate::traits::{HasData, HasMeta, RpcResult};
70
71impl HasData for EmptyResult {
72    fn data(&self) -> HashMap<String, Value> {
73        HashMap::new()
74    }
75}
76
77impl HasMeta for EmptyResult {
78    fn meta(&self) -> Option<HashMap<String, Value>> {
79        self.meta.clone()
80    }
81}
82
83impl RpcResult for EmptyResult {}
84
85// Trait implementations for protocol compliance
86use crate::traits::Params;
87
88#[derive(Debug, Clone, Serialize, Deserialize, Default)]
89pub struct EmptyParams;
90
91impl Params for EmptyParams {}
92
93// Note: PingRequest contains method field which is handled at the request level
94// The actual ping params would be EmptyParams in the params field
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use serde_json::json;
100
101    #[test]
102    fn test_ping_request() {
103        let ping = PingRequest::new();
104        assert_eq!(ping.method, "ping");
105        assert!(ping.params.is_none());
106        
107        let json = serde_json::to_value(&ping).unwrap();
108        assert_eq!(json["method"], "ping");
109    }
110
111    #[test] 
112    fn test_empty_result() {
113        let result = EmptyResult::new();
114        assert!(result.meta.is_none());
115        
116        let meta = HashMap::from([
117            ("test".to_string(), json!("value"))
118        ]);
119        let result_with_meta = EmptyResult::new().with_meta(meta.clone());
120        assert_eq!(result_with_meta.meta, Some(meta));
121    }
122
123    #[test]
124    fn test_empty_result_serialization() {
125        let result = EmptyResult::new();
126        let json = serde_json::to_value(&result).unwrap();
127        
128        // Should serialize to empty object (no _meta field when None)
129        assert_eq!(json, json!({}));
130        
131        let meta = HashMap::from([
132            ("progressToken".to_string(), json!("test-123"))
133        ]);
134        let result_with_meta = EmptyResult::new().with_meta(meta);
135        let json_with_meta = serde_json::to_value(&result_with_meta).unwrap();
136        assert!(json_with_meta["_meta"].is_object());
137    }
138}