1use std::collections::HashMap;
7use std::sync::Arc;
8
9use tracing::info;
10
11use turul_http_mcp_server::{ServerConfig, StreamConfig, StreamManager};
12use turul_mcp_protocol::{Implementation, ServerCapabilities};
13use turul_mcp_server::{
14 McpCompletion, McpElicitation, McpLogger, McpNotification, McpPrompt, McpResource, McpRoot,
15 McpSampling, McpTool, handlers::McpHandler, session::SessionManager,
16};
17use turul_mcp_session_storage::BoxedSessionStorage;
18
19use crate::error::Result;
20use crate::handler::LambdaMcpHandler;
21
22#[cfg(feature = "cors")]
23use crate::cors::CorsConfig;
24
25#[allow(dead_code)]
30pub struct LambdaMcpServer {
31 pub implementation: Implementation,
33 pub capabilities: ServerCapabilities,
35 tools: HashMap<String, Arc<dyn McpTool>>,
37 resources: HashMap<String, Arc<dyn McpResource>>,
39 prompts: HashMap<String, Arc<dyn McpPrompt>>,
41 elicitations: HashMap<String, Arc<dyn McpElicitation>>,
43 sampling: HashMap<String, Arc<dyn McpSampling>>,
45 completions: HashMap<String, Arc<dyn McpCompletion>>,
47 loggers: HashMap<String, Arc<dyn McpLogger>>,
49 root_providers: HashMap<String, Arc<dyn McpRoot>>,
51 notifications: HashMap<String, Arc<dyn McpNotification>>,
53 handlers: HashMap<String, Arc<dyn McpHandler>>,
55 roots: Vec<turul_mcp_protocol::roots::Root>,
57 instructions: Option<String>,
59 session_manager: Arc<SessionManager>,
61 session_storage: Arc<BoxedSessionStorage>,
63 strict_lifecycle: bool,
65 server_config: ServerConfig,
67 enable_sse: bool,
69 stream_config: StreamConfig,
71 #[cfg(feature = "cors")]
73 cors_config: Option<CorsConfig>,
74 middleware_stack: turul_http_mcp_server::middleware::MiddlewareStack,
76}
77
78impl LambdaMcpServer {
79 #[allow(clippy::too_many_arguments)]
81 pub(crate) fn new(
82 implementation: Implementation,
83 capabilities: ServerCapabilities,
84 tools: HashMap<String, Arc<dyn McpTool>>,
85 resources: HashMap<String, Arc<dyn McpResource>>,
86 prompts: HashMap<String, Arc<dyn McpPrompt>>,
87 elicitations: HashMap<String, Arc<dyn McpElicitation>>,
88 sampling: HashMap<String, Arc<dyn McpSampling>>,
89 completions: HashMap<String, Arc<dyn McpCompletion>>,
90 loggers: HashMap<String, Arc<dyn McpLogger>>,
91 root_providers: HashMap<String, Arc<dyn McpRoot>>,
92 notifications: HashMap<String, Arc<dyn McpNotification>>,
93 handlers: HashMap<String, Arc<dyn McpHandler>>,
94 roots: Vec<turul_mcp_protocol::roots::Root>,
95 instructions: Option<String>,
96 session_storage: Arc<BoxedSessionStorage>,
97 strict_lifecycle: bool,
98 server_config: ServerConfig,
99 enable_sse: bool,
100 stream_config: StreamConfig,
101 #[cfg(feature = "cors")] cors_config: Option<CorsConfig>,
102 middleware_stack: turul_http_mcp_server::middleware::MiddlewareStack,
103 ) -> Self {
104 let session_manager = Arc::new(SessionManager::with_storage_and_timeouts(
106 Arc::clone(&session_storage),
107 capabilities.clone(),
108 std::time::Duration::from_secs(30 * 60), std::time::Duration::from_secs(60), ));
111
112 Self {
113 implementation,
114 capabilities,
115 tools,
116 resources,
117 prompts,
118 elicitations,
119 sampling,
120 completions,
121 loggers,
122 root_providers,
123 notifications,
124 handlers,
125 roots,
126 instructions,
127 session_manager,
128 session_storage,
129 strict_lifecycle,
130 server_config,
131 enable_sse,
132 stream_config,
133 #[cfg(feature = "cors")]
134 cors_config,
135 middleware_stack,
136 }
137 }
138
139 pub async fn handler(&self) -> Result<LambdaMcpHandler> {
143 info!(
144 "Creating Lambda MCP handler: {} v{}",
145 self.implementation.name, self.implementation.version
146 );
147 info!("Session management: enabled with automatic cleanup");
148
149 if self.enable_sse {
150 info!("SSE notifications: enabled for Lambda responses");
151
152 #[cfg(not(feature = "streaming"))]
154 {
155 use tracing::warn;
156 warn!("⚠️ SSE is enabled but 'streaming' feature is not available!");
157 warn!(
158 " For real SSE streaming, use handle_streaming() with run_with_streaming_response"
159 );
160 warn!(
161 " Current handle() method will return SSE snapshots, not real-time streams"
162 );
163 warn!(" To enable streaming: add 'streaming' feature to turul-mcp-aws-lambda");
164 }
165 }
166
167 let _cleanup_task = self.session_manager.clone().start_cleanup_task();
169
170 let stream_manager = Arc::new(StreamManager::with_config(
172 self.session_storage.clone(),
173 self.stream_config.clone(),
174 ));
175
176 use turul_mcp_json_rpc_server::JsonRpcDispatcher;
178 let mut dispatcher = JsonRpcDispatcher::new();
179
180 use turul_mcp_server::SessionAwareInitializeHandler;
182 let init_handler = SessionAwareInitializeHandler::new(
183 self.implementation.clone(),
184 self.capabilities.clone(),
185 self.instructions.clone(),
186 self.session_manager.clone(),
187 self.strict_lifecycle,
188 );
189 dispatcher.register_method("initialize".to_string(), init_handler);
190
191 use turul_mcp_server::ListToolsHandler;
193 let list_handler = ListToolsHandler::new(self.tools.clone());
194 dispatcher.register_method("tools/list".to_string(), list_handler);
195
196 use turul_mcp_server::SessionAwareToolHandler;
198 let tool_handler = SessionAwareToolHandler::new(
199 self.tools.clone(),
200 self.session_manager.clone(),
201 self.strict_lifecycle,
202 );
203 dispatcher.register_method("tools/call".to_string(), tool_handler);
204
205 use turul_mcp_server::SessionAwareMcpHandlerBridge;
207 for (method, handler) in &self.handlers {
208 let bridge_handler = SessionAwareMcpHandlerBridge::new(
209 handler.clone(),
210 self.session_manager.clone(),
211 self.strict_lifecycle,
212 );
213 dispatcher.register_method(method.clone(), bridge_handler);
214 }
215
216 let middleware_stack = Arc::new(self.middleware_stack.clone());
218
219 Ok(LambdaMcpHandler::with_middleware(
220 self.server_config.clone(),
221 Arc::new(dispatcher),
222 self.session_storage.clone(),
223 stream_manager,
224 self.stream_config.clone(),
225 self.capabilities.clone(),
226 middleware_stack,
227 self.enable_sse,
228 ))
229 }
230
231 pub fn session_storage_info(&self) -> &str {
233 "Session storage configured"
234 }
235}