1use mcpkit_core::capability::{ClientCapabilities, ServerCapabilities, ServerInfo};
17use mcpkit_core::error::McpError;
18use mcpkit_core::protocol_version::ProtocolVersion;
19use std::marker::PhantomData;
20use std::sync::Arc;
21
22pub mod markers {
27 #[derive(Debug, Clone, Copy)]
31 pub struct Disconnected;
32
33 #[derive(Debug, Clone, Copy)]
35 pub struct Connected;
36
37 #[derive(Debug, Clone, Copy)]
39 pub struct Initializing;
40
41 #[derive(Debug, Clone, Copy)]
43 pub struct Ready;
44
45 #[derive(Debug, Clone, Copy)]
47 pub struct Closing;
48}
49
50#[doc(hidden)]
55#[deprecated(since = "0.2.6", note = "Use `markers` module instead")]
56pub mod state {
57 pub use super::markers::*;
58}
59
60#[doc(hidden)]
62#[derive(Debug)]
63pub struct ConnectionData {
64 pub client_capabilities: Option<ClientCapabilities>,
66 pub server_capabilities: ServerCapabilities,
68 pub server_info: ServerInfo,
70 pub protocol_version: Option<ProtocolVersion>,
74 pub session_id: Option<String>,
76}
77
78impl ConnectionData {
79 #[must_use]
81 pub const fn new(server_info: ServerInfo, server_capabilities: ServerCapabilities) -> Self {
82 Self {
83 client_capabilities: None,
84 server_capabilities,
85 server_info,
86 protocol_version: None,
87 session_id: None,
88 }
89 }
90}
91
92pub struct Connection<S> {
115 inner: Arc<ConnectionData>,
117 _state: PhantomData<S>,
119}
120
121impl<S> Clone for Connection<S> {
122 fn clone(&self) -> Self {
123 Self {
124 inner: Arc::clone(&self.inner),
125 _state: PhantomData,
126 }
127 }
128}
129
130impl<S> std::fmt::Debug for Connection<S> {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 f.debug_struct("Connection")
133 .field("inner", &self.inner)
134 .field("state", &std::any::type_name::<S>())
135 .finish()
136 }
137}
138
139impl Connection<markers::Disconnected> {
140 #[must_use]
142 pub fn new(server_info: ServerInfo, server_capabilities: ServerCapabilities) -> Self {
143 Self {
144 inner: Arc::new(ConnectionData::new(server_info, server_capabilities)),
145 _state: PhantomData,
146 }
147 }
148
149 pub async fn connect(self) -> Result<Connection<markers::Connected>, McpError> {
153 Ok(Connection {
155 inner: self.inner,
156 _state: PhantomData,
157 })
158 }
159}
160
161impl Connection<markers::Connected> {
162 pub async fn initialize(
166 self,
167 _protocol_version: ProtocolVersion,
168 ) -> Result<Connection<markers::Initializing>, McpError> {
169 Ok(Connection {
171 inner: self.inner,
172 _state: PhantomData,
173 })
174 }
175
176 pub async fn close(self) -> Result<(), McpError> {
178 Ok(())
180 }
181}
182
183impl Connection<markers::Initializing> {
184 pub async fn complete(
188 self,
189 client_capabilities: ClientCapabilities,
190 protocol_version: ProtocolVersion,
191 ) -> Result<Connection<markers::Ready>, McpError> {
192 let mut data = ConnectionData::new(
195 self.inner.server_info.clone(),
196 self.inner.server_capabilities.clone(),
197 );
198 data.client_capabilities = Some(client_capabilities);
199 data.protocol_version = Some(protocol_version);
200
201 Ok(Connection {
202 inner: Arc::new(data),
203 _state: PhantomData,
204 })
205 }
206
207 pub async fn abort(self) -> Result<Connection<markers::Disconnected>, McpError> {
209 Ok(Connection {
210 inner: self.inner,
211 _state: PhantomData,
212 })
213 }
214}
215
216impl Connection<markers::Ready> {
217 #[must_use]
225 pub fn client_capabilities(&self) -> &ClientCapabilities {
226 self.inner
227 .client_capabilities
228 .as_ref()
229 .expect("Ready connection must have client capabilities")
230 }
231
232 #[must_use]
236 pub fn try_client_capabilities(&self) -> Option<&ClientCapabilities> {
237 self.inner.client_capabilities.as_ref()
238 }
239
240 #[must_use]
242 pub fn server_capabilities(&self) -> &ServerCapabilities {
243 &self.inner.server_capabilities
244 }
245
246 #[must_use]
248 pub fn server_info(&self) -> &ServerInfo {
249 &self.inner.server_info
250 }
251
252 #[must_use]
260 pub fn protocol_version(&self) -> ProtocolVersion {
261 self.inner
262 .protocol_version
263 .expect("Ready connection must have protocol version")
264 }
265
266 #[must_use]
270 pub fn try_protocol_version(&self) -> Option<ProtocolVersion> {
271 self.inner.protocol_version
272 }
273
274 pub async fn shutdown(self) -> Result<Connection<markers::Closing>, McpError> {
278 Ok(Connection {
279 inner: self.inner,
280 _state: PhantomData,
281 })
282 }
283}
284
285impl Connection<markers::Closing> {
286 pub async fn disconnect(self) -> Result<(), McpError> {
288 Ok(())
290 }
291}
292
293#[derive(Debug)]
298pub enum ConnectionState {
299 Disconnected(Connection<markers::Disconnected>),
301 Connected(Connection<markers::Connected>),
303 Initializing(Connection<markers::Initializing>),
305 Ready(Connection<markers::Ready>),
307 Closing(Connection<markers::Closing>),
309}
310
311impl ConnectionState {
312 #[must_use]
314 pub fn new(server_info: ServerInfo, server_capabilities: ServerCapabilities) -> Self {
315 Self::Disconnected(Connection::new(server_info, server_capabilities))
316 }
317
318 #[must_use]
320 pub const fn is_ready(&self) -> bool {
321 matches!(self, Self::Ready(_))
322 }
323
324 #[must_use]
326 pub const fn is_disconnected(&self) -> bool {
327 matches!(self, Self::Disconnected(_))
328 }
329
330 #[must_use]
332 pub const fn state_name(&self) -> &'static str {
333 match self {
334 Self::Disconnected(_) => "Disconnected",
335 Self::Connected(_) => "Connected",
336 Self::Initializing(_) => "Initializing",
337 Self::Ready(_) => "Ready",
338 Self::Closing(_) => "Closing",
339 }
340 }
341}
342
343#[derive(Debug, Clone)]
345pub enum ConnectionEvent {
346 Connected,
348 InitializeStarted,
350 InitializeCompleted {
352 protocol_version: ProtocolVersion,
354 },
355 InitializeFailed {
357 error: String,
359 },
360 ShutdownRequested,
362 Disconnected,
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 use mcpkit_core::capability::{ServerCapabilities, ServerInfo};
370 use mcpkit_core::protocol_version::ProtocolVersion;
371
372 #[test]
373 fn test_connection_creation() {
374 let info = ServerInfo::new("test", "1.0.0");
375 let caps = ServerCapabilities::default();
376 let conn: Connection<markers::Disconnected> = Connection::new(info, caps);
377
378 assert!(std::any::type_name_of_val(&conn._state).contains("Disconnected"));
379 }
380
381 #[tokio::test]
382 async fn test_connection_lifecycle() -> Result<(), Box<dyn std::error::Error>> {
383 let info = ServerInfo::new("test", "1.0.0");
384 let caps = ServerCapabilities::default();
385
386 let conn = Connection::new(info, caps);
388
389 let conn = conn.connect().await?;
391
392 let conn = conn.initialize(ProtocolVersion::V2025_11_25).await?;
394
395 let conn = conn
397 .complete(ClientCapabilities::default(), ProtocolVersion::V2025_11_25)
398 .await?;
399
400 assert_eq!(conn.protocol_version(), ProtocolVersion::V2025_11_25);
402
403 let conn = conn.shutdown().await?;
405
406 conn.disconnect().await?;
408
409 Ok(())
410 }
411
412 #[test]
413 fn test_connection_state_enum() {
414 let info = ServerInfo::new("test", "1.0.0");
415 let caps = ServerCapabilities::default();
416
417 let state = ConnectionState::new(info, caps);
418 assert!(state.is_disconnected());
419 assert!(!state.is_ready());
420 assert_eq!(state.state_name(), "Disconnected");
421 }
422}