1use crate::error::Result;
6use crate::server::handler::CratesDocsHandler;
7use crate::server::CratesDocsServer;
8use rust_mcp_sdk::{
9 error::McpSdkError,
10 event_store,
11 mcp_server::{hyper_server, server_runtime, HyperServerOptions, McpServerOptions},
12 McpServer, StdioTransport, ToMcpServerHandler, TransportOptions,
13};
14use std::sync::Arc;
15
16pub async fn run_stdio_server(server: &CratesDocsServer) -> Result<()> {
18 tracing::info!("Starting Stdio MCP server...");
19
20 let server_info = server.server_info();
21 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
22
23 let transport = StdioTransport::new(TransportOptions::default())
25 .map_err(|e| crate::error::Error::Mcp(e.to_string()))?;
26
27 let mcp_server: Arc<rust_mcp_sdk::mcp_server::ServerRuntime> =
29 server_runtime::create_server(McpServerOptions {
30 server_details: server_info,
31 transport,
32 handler: handler.to_mcp_server_handler(),
33 task_store: None,
34 client_task_store: None,
35 });
36
37 tracing::info!("Stdio MCP server started, waiting for connections...");
38 mcp_server
39 .start()
40 .await
41 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
42
43 Ok(())
44}
45
46pub async fn run_http_server(server: &CratesDocsServer) -> Result<()> {
48 let config = server.config();
49 tracing::info!(
50 "Starting HTTP MCP server on {}:{}...",
51 config.host,
52 config.port
53 );
54
55 let server_info = server.server_info();
56 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
57
58 let options = HyperServerOptions {
60 host: config.host.clone(),
61 port: config.port,
62 transport_options: Arc::new(TransportOptions::default()),
63 sse_support: false, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
65 task_store: None,
66 client_task_store: None,
67 allowed_hosts: Some(config.allowed_hosts.clone()),
68 allowed_origins: Some(config.allowed_origins.clone()),
69 ..Default::default()
70 };
71
72 let mcp_server =
74 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
75
76 tracing::info!(
77 "HTTP MCP server started, listening on {}:{}",
78 config.host,
79 config.port
80 );
81 mcp_server
82 .start()
83 .await
84 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
85
86 Ok(())
87}
88
89pub async fn run_sse_server(server: &CratesDocsServer) -> Result<()> {
91 let config = server.config();
92 tracing::info!(
93 "Starting SSE MCP server on {}:{}...",
94 config.host,
95 config.port
96 );
97
98 let server_info = server.server_info();
99 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
100
101 let options = HyperServerOptions {
103 host: config.host.clone(),
104 port: config.port,
105 transport_options: Arc::new(TransportOptions::default()),
106 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
108 task_store: None,
109 client_task_store: None,
110 allowed_hosts: Some(config.allowed_hosts.clone()),
111 allowed_origins: Some(config.allowed_origins.clone()),
112 ..Default::default()
113 };
114
115 let mcp_server =
117 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
118
119 tracing::info!(
120 "SSE MCP server started, listening on {}:{}",
121 config.host,
122 config.port
123 );
124 mcp_server
125 .start()
126 .await
127 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
128
129 Ok(())
130}
131
132pub async fn run_hybrid_server(server: &CratesDocsServer) -> Result<()> {
134 let config = server.config();
135 tracing::info!(
136 "Starting hybrid MCP server on {}:{}...",
137 config.host,
138 config.port
139 );
140
141 let server_info = server.server_info();
142 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
143
144 let options = HyperServerOptions {
146 host: config.host.clone(),
147 port: config.port,
148 transport_options: Arc::new(TransportOptions::default()),
149 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
151 task_store: None,
152 client_task_store: None,
153 allowed_hosts: Some(config.allowed_hosts.clone()),
154 allowed_origins: Some(config.allowed_origins.clone()),
155 ..Default::default()
156 };
157
158 let mcp_server =
160 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
161
162 tracing::info!(
163 "Hybrid MCP server started, listening on {}:{} (HTTP + SSE)",
164 config.host,
165 config.port
166 );
167 mcp_server
168 .start()
169 .await
170 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
171
172 Ok(())
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
177pub enum TransportMode {
178 Stdio,
180 Http,
182 Sse,
184 Hybrid,
186}
187
188impl std::str::FromStr for TransportMode {
189 type Err = String;
190
191 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
192 match s.to_lowercase().as_str() {
193 "stdio" => Ok(TransportMode::Stdio),
194 "http" => Ok(TransportMode::Http),
195 "sse" => Ok(TransportMode::Sse),
196 "hybrid" => Ok(TransportMode::Hybrid),
197 _ => Err(format!("Unknown transport mode: {s}")),
198 }
199 }
200}
201
202impl std::fmt::Display for TransportMode {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 match self {
205 TransportMode::Stdio => write!(f, "stdio"),
206 TransportMode::Http => write!(f, "http"),
207 TransportMode::Sse => write!(f, "sse"),
208 TransportMode::Hybrid => write!(f, "hybrid"),
209 }
210 }
211}
212
213pub async fn run_server_with_mode(server: &CratesDocsServer, mode: TransportMode) -> Result<()> {
215 match mode {
216 TransportMode::Stdio => run_stdio_server(server).await,
217 TransportMode::Http => run_http_server(server).await,
218 TransportMode::Sse => run_sse_server(server).await,
219 TransportMode::Hybrid => run_hybrid_server(server).await,
220 }
221}