ultrafast_mcp_core/protocol/
lifecycle.rs1use crate::types::*;
3use crate::types::{ClientCapabilities, ServerCapabilities};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum LifecyclePhase {
9 Uninitialized,
10 Initializing,
11 Initialized,
12 Operating,
13 ShuttingDown,
14 Shutdown,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct InitializeRequest {
20 #[serde(rename = "protocolVersion")]
22 pub protocol_version: String,
23
24 pub capabilities: ClientCapabilities,
26
27 #[serde(rename = "clientInfo")]
29 pub client_info: ClientInfo,
30}
31
32impl InitializeRequest {
33 pub fn validate_protocol_version(&self) -> Result<(), crate::error::ProtocolError> {
35 if !self
37 .protocol_version
38 .chars()
39 .all(|c| c.is_ascii_digit() || c == '-')
40 {
41 return Err(crate::error::ProtocolError::InvalidVersion(
42 "Protocol version must contain only digits and hyphens".to_string(),
43 ));
44 }
45
46 let parts: Vec<&str> = self.protocol_version.split('-').collect();
48 if parts.len() != 3 {
49 return Err(crate::error::ProtocolError::InvalidVersion(
50 "Protocol version must be in YYYY-MM-DD format".to_string(),
51 ));
52 }
53
54 if parts[0].len() != 4 || parts[1].len() != 2 || parts[2].len() != 2 {
56 return Err(crate::error::ProtocolError::InvalidVersion(
57 "Protocol version must be in YYYY-MM-DD format".to_string(),
58 ));
59 }
60
61 if let (Ok(year), Ok(month), Ok(day)) = (
63 parts[0].parse::<u16>(),
64 parts[1].parse::<u8>(),
65 parts[2].parse::<u8>(),
66 ) {
67 if !(2020..=2030).contains(&year) {
68 return Err(crate::error::ProtocolError::InvalidVersion(
69 "Year must be between 2020 and 2030".to_string(),
70 ));
71 }
72 if !(1..=12).contains(&month) {
73 return Err(crate::error::ProtocolError::InvalidVersion(
74 "Month must be between 1 and 12".to_string(),
75 ));
76 }
77 if !(1..=31).contains(&day) {
78 return Err(crate::error::ProtocolError::InvalidVersion(
79 "Day must be between 1 and 31".to_string(),
80 ));
81 }
82 } else {
83 return Err(crate::error::ProtocolError::InvalidVersion(
84 "Protocol version components must be valid numbers".to_string(),
85 ));
86 }
87
88 let supported_versions = ["2025-06-18", "2025-03-26", "2024-11-05"];
90 if !supported_versions.contains(&self.protocol_version.as_str()) {
91 return Err(crate::error::ProtocolError::InvalidVersion(format!(
92 "Unsupported protocol version: {}",
93 self.protocol_version
94 )));
95 }
96
97 Ok(())
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct InitializeResponse {
104 #[serde(rename = "protocolVersion")]
106 pub protocol_version: String,
107
108 pub capabilities: ServerCapabilities,
110
111 #[serde(rename = "serverInfo")]
113 pub server_info: ServerInfo,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub instructions: Option<String>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct InitializedNotification {
123 }
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct ShutdownRequest {
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub reason: Option<String>,
131}
132
133#[async_trait::async_trait]
135pub trait LifecycleManager {
136 fn phase(&self) -> LifecyclePhase;
138
139 async fn initialize(
141 &mut self,
142 request: InitializeRequest,
143 ) -> Result<InitializeResponse, crate::error::MCPError>;
144
145 async fn initialized(&mut self) -> Result<(), crate::error::MCPError>;
147
148 async fn shutdown(&mut self, request: ShutdownRequest) -> Result<(), crate::error::MCPError>;
150
151 fn can_operate(&self) -> bool {
155 matches!(
156 self.phase(),
157 LifecyclePhase::Initialized | LifecyclePhase::Operating
158 )
159 }
160}
161
162#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
171 fn test_lifecycle_phases() {
172 assert_ne!(LifecyclePhase::Uninitialized, LifecyclePhase::Initialized);
173 assert_eq!(LifecyclePhase::Operating, LifecyclePhase::Operating);
174 }
175
176 #[test]
177 fn test_protocol_version_validation() {
178 let valid_request = InitializeRequest {
180 protocol_version: "2025-06-18".to_string(),
181 capabilities: Default::default(),
182 client_info: Default::default(),
183 };
184 assert!(valid_request.validate_protocol_version().is_ok());
185
186 let valid_request2 = InitializeRequest {
187 protocol_version: "2024-11-05".to_string(),
188 capabilities: Default::default(),
189 client_info: Default::default(),
190 };
191 assert!(valid_request2.validate_protocol_version().is_ok());
192
193 let invalid_request = InitializeRequest {
195 protocol_version: "invalid".to_string(),
196 capabilities: Default::default(),
197 client_info: Default::default(),
198 };
199 assert!(invalid_request.validate_protocol_version().is_err());
200
201 let invalid_request2 = InitializeRequest {
202 protocol_version: "2025-6-18".to_string(), capabilities: Default::default(),
204 client_info: Default::default(),
205 };
206 assert!(invalid_request2.validate_protocol_version().is_err());
207
208 let invalid_request3 = InitializeRequest {
209 protocol_version: "2025-06-18-extra".to_string(), capabilities: Default::default(),
211 client_info: Default::default(),
212 };
213 assert!(invalid_request3.validate_protocol_version().is_err());
214
215 let invalid_request4 = InitializeRequest {
216 protocol_version: "2019-06-18".to_string(), capabilities: Default::default(),
218 client_info: Default::default(),
219 };
220 assert!(invalid_request4.validate_protocol_version().is_err());
221
222 let invalid_request5 = InitializeRequest {
223 protocol_version: "2031-06-18".to_string(), capabilities: Default::default(),
225 client_info: Default::default(),
226 };
227 assert!(invalid_request5.validate_protocol_version().is_err());
228 }
229}