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 message_observer: None,
36 });
37
38 tracing::info!("Stdio MCP server started, waiting for connections...");
39 mcp_server
40 .start()
41 .await
42 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
43
44 Ok(())
45}
46
47pub async fn run_http_server(server: &CratesDocsServer) -> Result<()> {
49 let config = server.config();
50 tracing::info!(
51 "Starting HTTP MCP server on {}:{}...",
52 config.server.host,
53 config.server.port
54 );
55
56 let server_info = server.server_info();
57 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
58
59 let options = HyperServerOptions {
61 host: config.server.host.clone(),
62 port: config.server.port,
63 transport_options: Arc::new(TransportOptions::default()),
64 sse_support: false, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
66 task_store: None,
67 client_task_store: None,
68 allowed_hosts: Some(config.server.allowed_hosts.clone()),
69 allowed_origins: Some(config.server.allowed_origins.clone()),
70 ..Default::default()
71 };
72
73 let mcp_server =
75 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
76
77 tracing::info!(
78 "HTTP MCP server started, listening on {}:{}",
79 config.server.host,
80 config.server.port
81 );
82 mcp_server
83 .start()
84 .await
85 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
86
87 Ok(())
88}
89
90pub async fn run_sse_server(server: &CratesDocsServer) -> Result<()> {
92 let config = server.config();
93 tracing::info!(
94 "Starting SSE MCP server on {}:{}...",
95 config.server.host,
96 config.server.port
97 );
98
99 let server_info = server.server_info();
100 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
101
102 let options = HyperServerOptions {
104 host: config.server.host.clone(),
105 port: config.server.port,
106 transport_options: Arc::new(TransportOptions::default()),
107 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
109 task_store: None,
110 client_task_store: None,
111 allowed_hosts: Some(config.server.allowed_hosts.clone()),
112 allowed_origins: Some(config.server.allowed_origins.clone()),
113 ..Default::default()
114 };
115
116 let mcp_server =
118 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
119
120 tracing::info!(
121 "SSE MCP server started, listening on {}:{}",
122 config.server.host,
123 config.server.port
124 );
125 mcp_server
126 .start()
127 .await
128 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
129
130 Ok(())
131}
132
133pub async fn run_hybrid_server(server: &CratesDocsServer) -> Result<()> {
135 let config = server.config();
136 tracing::info!(
137 "Starting hybrid MCP server on {}:{}...",
138 config.server.host,
139 config.server.port
140 );
141
142 let server_info = server.server_info();
143 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
144
145 let options = HyperServerOptions {
147 host: config.server.host.clone(),
148 port: config.server.port,
149 transport_options: Arc::new(TransportOptions::default()),
150 sse_support: true, event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
152 task_store: None,
153 client_task_store: None,
154 allowed_hosts: Some(config.server.allowed_hosts.clone()),
155 allowed_origins: Some(config.server.allowed_origins.clone()),
156 ..Default::default()
157 };
158
159 let mcp_server =
161 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
162
163 tracing::info!(
164 "Hybrid MCP server started, listening on {}:{} (HTTP + SSE)",
165 config.server.host,
166 config.server.port
167 );
168 mcp_server
169 .start()
170 .await
171 .map_err(|e: McpSdkError| crate::error::Error::Mcp(e.to_string()))?;
172
173 Ok(())
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
178pub enum TransportMode {
179 Stdio,
181 Http,
183 Sse,
185 Hybrid,
187}
188
189impl std::str::FromStr for TransportMode {
190 type Err = String;
191
192 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
193 match s.to_lowercase().as_str() {
194 "stdio" => Ok(TransportMode::Stdio),
195 "http" => Ok(TransportMode::Http),
196 "sse" => Ok(TransportMode::Sse),
197 "hybrid" => Ok(TransportMode::Hybrid),
198 _ => Err(format!("Unknown transport mode: {s}")),
199 }
200 }
201}
202
203impl std::fmt::Display for TransportMode {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 match self {
206 TransportMode::Stdio => write!(f, "stdio"),
207 TransportMode::Http => write!(f, "http"),
208 TransportMode::Sse => write!(f, "sse"),
209 TransportMode::Hybrid => write!(f, "hybrid"),
210 }
211 }
212}
213
214pub async fn run_server_with_mode(server: &CratesDocsServer, mode: TransportMode) -> Result<()> {
216 match mode {
217 TransportMode::Stdio => run_stdio_server(server).await,
218 TransportMode::Http => run_http_server(server).await,
219 TransportMode::Sse => run_sse_server(server).await,
220 TransportMode::Hybrid => run_hybrid_server(server).await,
221 }
222}