reasonkit/mcp/
lifecycle.rs

1//! MCP Lifecycle Management
2//!
3//! Initialize, ping, and shutdown protocol messages.
4
5use super::types::{Implementation, ServerCapabilities, ServerInfo};
6use serde::{Deserialize, Serialize};
7
8/// Client information
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ClientInfo {
11    /// Client name
12    pub name: String,
13    /// Client version
14    pub version: String,
15}
16
17/// Initialize request parameters
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct InitializeParams {
20    /// Protocol version
21    #[serde(rename = "protocolVersion")]
22    pub protocol_version: String,
23
24    /// Client capabilities
25    pub capabilities: ClientCapabilities,
26
27    /// Client information
28    #[serde(rename = "clientInfo")]
29    pub client_info: ClientInfo,
30}
31
32/// Client capabilities
33#[derive(Debug, Clone, Default, Serialize, Deserialize)]
34pub struct ClientCapabilities {
35    /// Supports sampling
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub sampling: Option<SamplingCapability>,
38
39    /// Supports roots
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub roots: Option<RootsCapability>,
42
43    /// Experimental capabilities
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub experimental: Option<serde_json::Value>,
46}
47
48/// Sampling capability (for LLM sampling)
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct SamplingCapability {}
51
52/// Roots capability (for workspace roots)
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct RootsCapability {
55    /// Whether list_changed notifications are supported
56    #[serde(default, rename = "listChanged")]
57    pub list_changed: bool,
58}
59
60/// Initialize result
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct InitializeResult {
63    /// Protocol version
64    #[serde(rename = "protocolVersion")]
65    pub protocol_version: String,
66
67    /// Server capabilities
68    pub capabilities: ServerCapabilities,
69
70    /// Server information
71    #[serde(rename = "serverInfo")]
72    pub server_info: ServerInfo,
73
74    /// Server implementation details
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub implementation: Option<Implementation>,
77}
78
79/// Shutdown request (no parameters)
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ShutdownRequest {}
82
83/// Ping request (for health checks)
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct PingRequest {}
86
87/// Ping response
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct PingResponse {}
90
91impl InitializeParams {
92    /// Create default initialize parameters for ReasonKit
93    pub fn reasonkit() -> Self {
94        Self {
95            protocol_version: crate::mcp::MCP_VERSION.to_string(),
96            capabilities: ClientCapabilities::default(),
97            client_info: ClientInfo {
98                name: "reasonkit-core".to_string(),
99                version: env!("CARGO_PKG_VERSION").to_string(),
100            },
101        }
102    }
103
104    /// Create initialize parameters with custom client info
105    pub fn with_client_info(name: impl Into<String>, version: impl Into<String>) -> Self {
106        Self {
107            protocol_version: crate::mcp::MCP_VERSION.to_string(),
108            capabilities: ClientCapabilities::default(),
109            client_info: ClientInfo {
110                name: name.into(),
111                version: version.into(),
112            },
113        }
114    }
115}
116
117impl InitializeResult {
118    /// Create an initialize result
119    pub fn new(server_info: ServerInfo, capabilities: ServerCapabilities) -> Self {
120        Self {
121            protocol_version: crate::mcp::MCP_VERSION.to_string(),
122            capabilities,
123            server_info,
124            implementation: Some(Implementation {
125                name: "reasonkit-core".to_string(),
126                version: env!("CARGO_PKG_VERSION").to_string(),
127            }),
128        }
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_initialize_params() {
138        let params = InitializeParams::reasonkit();
139        assert_eq!(params.client_info.name, "reasonkit-core");
140        assert_eq!(params.protocol_version, crate::mcp::MCP_VERSION);
141    }
142
143    #[test]
144    fn test_initialize_serialization() {
145        let params = InitializeParams::reasonkit();
146        let json = serde_json::to_string(&params).unwrap();
147        assert!(json.contains("protocolVersion"));
148        assert!(json.contains("clientInfo"));
149    }
150}