1use crate::error::Result;
31use crate::server::handler::CratesDocsHandler;
32use crate::server::CratesDocsServer;
33use rust_mcp_sdk::{
34 error::McpSdkError,
35 event_store,
36 mcp_server::{hyper_server, server_runtime, HyperServerOptions, McpServerOptions},
37 McpServer, StdioTransport, ToMcpServerHandler, TransportOptions,
38};
39use std::sync::Arc;
40
41pub async fn run_stdio_server(server: &CratesDocsServer) -> Result<()> {
68 tracing::info!("Starting Stdio MCP server...");
69
70 let server_info = server.server_info();
71 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
72
73 let transport = StdioTransport::new(TransportOptions::default())
75 .map_err(|e| crate::error::Error::mcp("transport", e.to_string()))?;
76
77 let mcp_server: Arc<rust_mcp_sdk::mcp_server::ServerRuntime> =
79 server_runtime::create_server(McpServerOptions {
80 server_details: server_info,
81 transport,
82 handler: handler.to_mcp_server_handler(),
83 task_store: None,
84 client_task_store: None,
85 message_observer: None,
86 });
87
88 tracing::info!("Stdio MCP server started, waiting for connections...");
89 mcp_server
90 .start()
91 .await
92 .map_err(|e: McpSdkError| crate::error::Error::mcp("server_start", e.to_string()))?;
93
94 Ok(())
95}
96
97pub async fn run_http_server(server: &CratesDocsServer) -> Result<()> {
124 let config = server.config();
125 tracing::info!(
126 "Starting HTTP MCP server on {}:{}...",
127 config.server.host,
128 config.server.port
129 );
130
131 let server_info = server.server_info();
132 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
133
134 let options = HyperServerOptions {
136 host: config.server.host.clone(),
137 port: config.server.port,
138 transport_options: Arc::new(TransportOptions::default()),
139 sse_support: false, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
141 task_store: None,
142 client_task_store: None,
143 allowed_hosts: Some(config.server.allowed_hosts.clone()),
144 allowed_origins: Some(config.server.allowed_origins.clone()),
145 health_endpoint: Some("/health".to_string()),
146 ..Default::default()
147 };
148
149 let mcp_server =
151 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
152
153 tracing::info!(
154 "HTTP MCP server started, listening on {}:{}",
155 config.server.host,
156 config.server.port
157 );
158 mcp_server
159 .start()
160 .await
161 .map_err(|e: McpSdkError| crate::error::Error::mcp("server_start", e.to_string()))?;
162
163 Ok(())
164}
165
166pub async fn run_sse_server(server: &CratesDocsServer) -> Result<()> {
193 let config = server.config();
194 tracing::info!(
195 "Starting SSE MCP server on {}:{}...",
196 config.server.host,
197 config.server.port
198 );
199
200 let server_info = server.server_info();
201 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
202
203 let options = HyperServerOptions {
205 host: config.server.host.clone(),
206 port: config.server.port,
207 transport_options: Arc::new(TransportOptions::default()),
208 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
210 task_store: None,
211 client_task_store: None,
212 allowed_hosts: Some(config.server.allowed_hosts.clone()),
213 allowed_origins: Some(config.server.allowed_origins.clone()),
214 health_endpoint: Some("/health".to_string()),
215 ..Default::default()
216 };
217
218 let mcp_server =
220 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
221
222 tracing::info!(
223 "SSE MCP server started, listening on {}:{}",
224 config.server.host,
225 config.server.port
226 );
227 mcp_server
228 .start()
229 .await
230 .map_err(|e: McpSdkError| crate::error::Error::mcp("server_start", e.to_string()))?;
231
232 Ok(())
233}
234
235pub async fn run_hybrid_server(server: &CratesDocsServer) -> Result<()> {
262 let config = server.config();
263 tracing::info!(
264 "Starting hybrid MCP server on {}:{}...",
265 config.server.host,
266 config.server.port
267 );
268
269 let server_info = server.server_info();
270 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
271
272 let options = HyperServerOptions {
274 host: config.server.host.clone(),
275 port: config.server.port,
276 transport_options: Arc::new(TransportOptions::default()),
277 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
279 task_store: None,
280 client_task_store: None,
281 allowed_hosts: Some(config.server.allowed_hosts.clone()),
282 allowed_origins: Some(config.server.allowed_origins.clone()),
283 health_endpoint: Some("/health".to_string()),
284 ..Default::default()
285 };
286
287 let mcp_server =
289 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
290
291 tracing::info!(
292 "Hybrid MCP server started, listening on {}:{} (HTTP + SSE)",
293 config.server.host,
294 config.server.port
295 );
296 mcp_server
297 .start()
298 .await
299 .map_err(|e: McpSdkError| crate::error::Error::mcp("server_start", e.to_string()))?;
300
301 Ok(())
302}
303
304#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
326pub enum TransportMode {
327 Stdio,
329 Http,
331 Sse,
333 Hybrid,
335}
336
337impl std::str::FromStr for TransportMode {
338 type Err = String;
339
340 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
341 match s.to_lowercase().as_str() {
342 "stdio" => Ok(TransportMode::Stdio),
343 "http" => Ok(TransportMode::Http),
344 "sse" => Ok(TransportMode::Sse),
345 "hybrid" => Ok(TransportMode::Hybrid),
346 _ => Err(format!("Unknown transport mode: {s}")),
347 }
348 }
349}
350
351impl std::fmt::Display for TransportMode {
352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 match self {
354 TransportMode::Stdio => write!(f, "stdio"),
355 TransportMode::Http => write!(f, "http"),
356 TransportMode::Sse => write!(f, "sse"),
357 TransportMode::Hybrid => write!(f, "hybrid"),
358 }
359 }
360}
361
362pub async fn run_server_with_mode(server: &CratesDocsServer, mode: TransportMode) -> Result<()> {
364 match mode {
365 TransportMode::Stdio => run_stdio_server(server).await,
366 TransportMode::Http => run_http_server(server).await,
367 TransportMode::Sse => run_sse_server(server).await,
368 TransportMode::Hybrid => run_hybrid_server(server).await,
369 }
370}