Skip to main content

fastmcp_client/
session.rs

1//! Client session state.
2
3use fastmcp_protocol::{ClientCapabilities, ClientInfo, ServerCapabilities, ServerInfo};
4
5/// Client-side session state.
6#[derive(Debug)]
7pub struct ClientSession {
8    /// Client info sent during initialization.
9    client_info: ClientInfo,
10    /// Client capabilities sent during initialization.
11    client_capabilities: ClientCapabilities,
12    /// Server info received during initialization.
13    server_info: ServerInfo,
14    /// Server capabilities received during initialization.
15    server_capabilities: ServerCapabilities,
16    /// Negotiated protocol version.
17    protocol_version: String,
18}
19
20impl ClientSession {
21    /// Creates a new client session after successful initialization.
22    #[must_use]
23    pub fn new(
24        client_info: ClientInfo,
25        client_capabilities: ClientCapabilities,
26        server_info: ServerInfo,
27        server_capabilities: ServerCapabilities,
28        protocol_version: String,
29    ) -> Self {
30        Self {
31            client_info,
32            client_capabilities,
33            server_info,
34            server_capabilities,
35            protocol_version,
36        }
37    }
38
39    /// Returns the client info.
40    #[must_use]
41    pub fn client_info(&self) -> &ClientInfo {
42        &self.client_info
43    }
44
45    /// Returns the client capabilities.
46    #[must_use]
47    pub fn client_capabilities(&self) -> &ClientCapabilities {
48        &self.client_capabilities
49    }
50
51    /// Returns the server info.
52    #[must_use]
53    pub fn server_info(&self) -> &ServerInfo {
54        &self.server_info
55    }
56
57    /// Returns the server capabilities.
58    #[must_use]
59    pub fn server_capabilities(&self) -> &ServerCapabilities {
60        &self.server_capabilities
61    }
62
63    /// Returns the negotiated protocol version.
64    #[must_use]
65    pub fn protocol_version(&self) -> &str {
66        &self.protocol_version
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use fastmcp_protocol::{PromptsCapability, ResourcesCapability, ToolsCapability};
74
75    fn test_session() -> ClientSession {
76        ClientSession::new(
77            ClientInfo {
78                name: "test-client".to_string(),
79                version: "1.0.0".to_string(),
80            },
81            ClientCapabilities::default(),
82            ServerInfo {
83                name: "test-server".to_string(),
84                version: "2.0.0".to_string(),
85            },
86            ServerCapabilities {
87                tools: Some(ToolsCapability { list_changed: true }),
88                resources: Some(ResourcesCapability {
89                    subscribe: true,
90                    list_changed: false,
91                }),
92                prompts: Some(PromptsCapability {
93                    list_changed: false,
94                }),
95                logging: None,
96                tasks: None,
97            },
98            "2024-11-05".to_string(),
99        )
100    }
101
102    #[test]
103    fn session_client_info() {
104        let session = test_session();
105        assert_eq!(session.client_info().name, "test-client");
106        assert_eq!(session.client_info().version, "1.0.0");
107    }
108
109    #[test]
110    fn session_client_capabilities() {
111        let session = test_session();
112        let caps = session.client_capabilities();
113        assert!(caps.sampling.is_none());
114        assert!(caps.elicitation.is_none());
115        assert!(caps.roots.is_none());
116    }
117
118    #[test]
119    fn session_server_info() {
120        let session = test_session();
121        assert_eq!(session.server_info().name, "test-server");
122        assert_eq!(session.server_info().version, "2.0.0");
123    }
124
125    #[test]
126    fn session_server_capabilities() {
127        let session = test_session();
128        let caps = session.server_capabilities();
129        assert!(caps.tools.is_some());
130        assert!(caps.tools.as_ref().unwrap().list_changed);
131        assert!(caps.resources.is_some());
132        assert!(caps.resources.as_ref().unwrap().subscribe);
133        assert!(!caps.resources.as_ref().unwrap().list_changed);
134        assert!(caps.prompts.is_some());
135        assert!(caps.logging.is_none());
136        assert!(caps.tasks.is_none());
137    }
138
139    #[test]
140    fn session_protocol_version() {
141        let session = test_session();
142        assert_eq!(session.protocol_version(), "2024-11-05");
143    }
144
145    #[test]
146    fn session_with_sampling_capabilities() {
147        let session = ClientSession::new(
148            ClientInfo {
149                name: "sampler".to_string(),
150                version: "0.1.0".to_string(),
151            },
152            ClientCapabilities {
153                sampling: Some(fastmcp_protocol::SamplingCapability {}),
154                elicitation: None,
155                roots: None,
156            },
157            ServerInfo {
158                name: "srv".to_string(),
159                version: "1.0.0".to_string(),
160            },
161            ServerCapabilities::default(),
162            "2024-11-05".to_string(),
163        );
164        assert!(session.client_capabilities().sampling.is_some());
165    }
166
167    #[test]
168    fn session_with_empty_server_capabilities() {
169        let session = ClientSession::new(
170            ClientInfo {
171                name: "c".to_string(),
172                version: "0.1.0".to_string(),
173            },
174            ClientCapabilities::default(),
175            ServerInfo {
176                name: "s".to_string(),
177                version: "0.1.0".to_string(),
178            },
179            ServerCapabilities::default(),
180            String::new(),
181        );
182        assert!(session.server_capabilities().tools.is_none());
183        assert!(session.server_capabilities().resources.is_none());
184        assert!(session.server_capabilities().prompts.is_none());
185        assert!(session.server_capabilities().logging.is_none());
186        assert!(session.server_capabilities().tasks.is_none());
187        assert!(session.protocol_version().is_empty());
188    }
189}