gestura_core_mcp/
lifecycle.rs1use super::types::{
5 ClientCapabilities, ClientInfo, InitializeParams, InitializeResult, LoggingCapability,
6 PROTOCOL_VERSION, PingResult, PromptsCapability, ResourcesCapability, ServerCapabilities,
7 ServerInfo, SessionState, ToolsCapability,
8};
9use std::sync::Arc;
10use std::sync::atomic::{AtomicU8, Ordering};
11
12#[derive(Debug)]
14pub struct SessionManager {
15 state: AtomicU8,
16 client_info: std::sync::RwLock<Option<ClientInfo>>,
17 client_capabilities: std::sync::RwLock<Option<ClientCapabilities>>,
18 server_info: ServerInfo,
19 server_capabilities: ServerCapabilities,
20}
21
22impl Default for SessionManager {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl SessionManager {
29 pub fn new() -> Self {
31 Self {
32 state: AtomicU8::new(SessionState::Uninitialized as u8),
33 client_info: std::sync::RwLock::new(None),
34 client_capabilities: std::sync::RwLock::new(None),
35 server_info: ServerInfo::default(),
36 server_capabilities: Self::default_capabilities(),
37 }
38 }
39
40 fn default_capabilities() -> ServerCapabilities {
42 ServerCapabilities {
43 tools: Some(ToolsCapability { list_changed: true }),
44 resources: Some(ResourcesCapability {
45 subscribe: false,
46 list_changed: true,
47 }),
48 prompts: Some(PromptsCapability { list_changed: true }),
49 logging: Some(LoggingCapability {}),
50 }
51 }
52
53 pub fn state(&self) -> SessionState {
55 match self.state.load(Ordering::SeqCst) {
56 0 => SessionState::Uninitialized,
57 1 => SessionState::Initializing,
58 2 => SessionState::Ready,
59 3 => SessionState::ShuttingDown,
60 4 => SessionState::Closed,
61 _ => SessionState::Uninitialized,
62 }
63 }
64
65 fn set_state(&self, state: SessionState) {
67 self.state.store(state as u8, Ordering::SeqCst);
68 }
69
70 pub fn is_ready(&self) -> bool {
72 self.state() == SessionState::Ready
73 }
74
75 pub fn initialize(&self, params: InitializeParams) -> Result<InitializeResult, String> {
77 let current_state = self.state();
78 if current_state != SessionState::Uninitialized {
79 return Err(format!(
80 "Cannot initialize: session is in {:?} state",
81 current_state
82 ));
83 }
84
85 if params.protocol_version != PROTOCOL_VERSION {
87 tracing::warn!(
88 "Client protocol version {} differs from server version {}",
89 params.protocol_version,
90 PROTOCOL_VERSION
91 );
92 }
93
94 if let Ok(mut info) = self.client_info.write() {
96 *info = Some(params.client_info.clone());
97 }
98
99 if let Ok(mut caps) = self.client_capabilities.write() {
101 *caps = Some(params.capabilities);
102 }
103
104 self.set_state(SessionState::Initializing);
105
106 tracing::info!(
107 "MCP session initializing with client: {} v{}",
108 params.client_info.name,
109 params.client_info.version
110 );
111
112 Ok(InitializeResult {
113 protocol_version: PROTOCOL_VERSION.to_string(),
114 capabilities: self.server_capabilities.clone(),
115 server_info: self.server_info.clone(),
116 instructions: Some(
117 "Gestura is a voice-first AI assistant with haptic feedback support.".to_string(),
118 ),
119 })
120 }
121
122 pub fn initialized(&self) -> Result<(), String> {
124 let current_state = self.state();
125 if current_state != SessionState::Initializing {
126 return Err(format!(
127 "Cannot complete initialization: session is in {:?} state",
128 current_state
129 ));
130 }
131
132 self.set_state(SessionState::Ready);
133 tracing::info!("MCP session initialized and ready");
134 Ok(())
135 }
136
137 pub fn ping(&self) -> PingResult {
139 PingResult {}
140 }
141
142 pub fn shutdown(&self) -> Result<(), String> {
144 let current_state = self.state();
145 if current_state == SessionState::Closed {
146 return Err("Session already closed".to_string());
147 }
148
149 self.set_state(SessionState::ShuttingDown);
150 tracing::info!("MCP session shutting down");
151
152 if let Ok(mut info) = self.client_info.write() {
154 *info = None;
155 }
156 if let Ok(mut caps) = self.client_capabilities.write() {
157 *caps = None;
158 }
159
160 self.set_state(SessionState::Closed);
161 tracing::info!("MCP session closed");
162 Ok(())
163 }
164
165 pub fn client_info(&self) -> Option<ClientInfo> {
167 self.client_info.read().ok()?.clone()
168 }
169
170 pub fn client_capabilities(&self) -> Option<ClientCapabilities> {
172 self.client_capabilities.read().ok()?.clone()
173 }
174
175 pub fn server_info(&self) -> &ServerInfo {
177 &self.server_info
178 }
179
180 pub fn server_capabilities(&self) -> &ServerCapabilities {
182 &self.server_capabilities
183 }
184}
185
186pub fn create_session_manager() -> Arc<SessionManager> {
188 Arc::new(SessionManager::new())
189}