crates_docs/server/transport.rs
1//! 传输模块
2//!
3//! 提供 Stdio、HTTP 和 SSE 传输协议支持。
4//!
5//! # 支持的传输模式
6//!
7//! - **Stdio**: 标准输入输出,适合与 MCP 客户端集成
8//! - **HTTP**: Streamable HTTP,支持无状态请求
9//! - **SSE**: Server-Sent Events,支持服务器推送
10//! - **Hybrid**: 混合模式,同时支持 HTTP 和 SSE
11//!
12//! # 示例
13//!
14//! ```rust,no_run
15//! use crates_docs::server::transport::{run_stdio_server, TransportMode};
16//! use crates_docs::{AppConfig, CratesDocsServer};
17//!
18//! #[tokio::main]
19//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//! let config = AppConfig::default();
21//! let server = CratesDocsServer::new(config)?;
22//!
23//! // 运行 Stdio 服务器
24//! run_stdio_server(&server).await?;
25//!
26//! Ok(())
27//! }
28//! ```
29
30use 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
41/// 运行 Stdio 服务器
42///
43/// 通过标准输入输出与 MCP 客户端通信。
44///
45/// # 参数
46///
47/// * `server` - `CratesDocsServer` 实例
48///
49/// # 错误
50///
51/// 如果服务器启动失败,返回错误
52///
53/// # 示例
54///
55/// ```rust,no_run
56/// use crates_docs::server::transport::run_stdio_server;
57/// use crates_docs::{AppConfig, CratesDocsServer};
58///
59/// #[tokio::main]
60/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
61/// let config = AppConfig::default();
62/// let server = CratesDocsServer::new(config)?;
63/// run_stdio_server(&server).await?;
64/// Ok(())
65/// }
66/// ```
67pub 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 // Create Stdio transport
74 let transport = StdioTransport::new(TransportOptions::default())
75 .map_err(|e| crate::error::Error::mcp("transport", e.to_string()))?;
76
77 // Create MCP server
78 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
97/// Internal helper to run a Hyper-based MCP server with the given configuration.
98///
99/// This function consolidates the common logic for HTTP, SSE, and Hybrid servers,
100/// which only differ in their SSE support and log messages.
101///
102/// # Arguments
103///
104/// * `server` - `CratesDocsServer` 实例
105/// * `protocol_name` - Protocol name for logging (e.g., "HTTP", "SSE", "Hybrid")
106/// * `sse_support` - Whether SSE support is enabled
107async fn run_hyper_server(
108 server: &CratesDocsServer,
109 protocol_name: &str,
110 sse_support: bool,
111) -> Result<()> {
112 let config = server.config();
113 let server_info = server.server_info();
114 let handler = CratesDocsHandler::new(Arc::new(server.clone()));
115
116 tracing::info!(
117 "Starting {} MCP server on {}:{}...",
118 protocol_name,
119 config.server.host,
120 config.server.port
121 );
122
123 // Create Hyper server options with security settings from config
124 let options = HyperServerOptions {
125 host: config.server.host.clone(),
126 port: config.server.port,
127 transport_options: Arc::new(TransportOptions::default()),
128 sse_support,
129 event_store: Some(Arc::new(event_store::InMemoryEventStore::default())),
130 task_store: None,
131 client_task_store: None,
132 allowed_hosts: Some(config.server.allowed_hosts.clone()),
133 allowed_origins: Some(config.server.allowed_origins.clone()),
134 health_endpoint: Some("/health".to_string()),
135 ..Default::default()
136 };
137
138 // Create HTTP/SSE/Hybrid server
139 let mcp_server =
140 hyper_server::create_server(server_info, handler.to_mcp_server_handler(), options);
141
142 // Build the started message based on the protocol
143 let started_msg = if sse_support && protocol_name != "SSE" {
144 // Hybrid mode
145 format!(
146 "{} MCP server started, listening on {}:{} (HTTP + SSE)",
147 protocol_name, config.server.host, config.server.port
148 )
149 } else {
150 format!(
151 "{} MCP server started, listening on {}:{}",
152 protocol_name, config.server.host, config.server.port
153 )
154 };
155 tracing::info!("{}", started_msg);
156
157 mcp_server
158 .start()
159 .await
160 .map_err(|e: McpSdkError| crate::error::Error::mcp("server_start", e.to_string()))?;
161
162 Ok(())
163}
164
165/// 运行 HTTP 服务器(Streamable HTTP)
166///
167/// 启动支持 Streamable HTTP 协议的 MCP 服务器。
168///
169/// # 参数
170///
171/// * `server` - `CratesDocsServer` 实例
172///
173/// # 错误
174///
175/// 如果服务器启动失败,返回错误
176///
177/// # 示例
178///
179/// ```rust,no_run
180/// use crates_docs::server::transport::run_http_server;
181/// use crates_docs::{AppConfig, CratesDocsServer};
182///
183/// #[tokio::main]
184/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
185/// let config = AppConfig::default();
186/// let server = CratesDocsServer::new(config)?;
187/// run_http_server(&server).await?;
188/// Ok(())
189/// }
190/// ```
191pub async fn run_http_server(server: &CratesDocsServer) -> Result<()> {
192 run_hyper_server(server, "HTTP", false).await
193}
194
195/// 运行 SSE 服务器(Server-Sent Events)
196///
197/// 启动支持 Server-Sent Events 协议的 MCP 服务器。
198///
199/// # 参数
200///
201/// * `server` - `CratesDocsServer` 实例
202///
203/// # 错误
204///
205/// 如果服务器启动失败,返回错误
206///
207/// # 示例
208///
209/// ```rust,no_run
210/// use crates_docs::server::transport::run_sse_server;
211/// use crates_docs::{AppConfig, CratesDocsServer};
212///
213/// #[tokio::main]
214/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
215/// let config = AppConfig::default();
216/// let server = CratesDocsServer::new(config)?;
217/// run_sse_server(&server).await?;
218/// Ok(())
219/// }
220/// ```
221pub async fn run_sse_server(server: &CratesDocsServer) -> Result<()> {
222 run_hyper_server(server, "SSE", true).await
223}
224
225/// 运行混合服务器(同时支持 HTTP 和 SSE)
226///
227/// 启动同时支持 HTTP 和 SSE 协议的 MCP 服务器。
228///
229/// # 参数
230///
231/// * `server` - `CratesDocsServer` 实例
232///
233/// # 错误
234///
235/// 如果服务器启动失败,返回错误
236///
237/// # 示例
238///
239/// ```rust,no_run
240/// use crates_docs::server::transport::run_hybrid_server;
241/// use crates_docs::{AppConfig, CratesDocsServer};
242///
243/// #[tokio::main]
244/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
245/// let config = AppConfig::default();
246/// let server = CratesDocsServer::new(config)?;
247/// run_hybrid_server(&server).await?;
248/// Ok(())
249/// }
250/// ```
251pub async fn run_hybrid_server(server: &CratesDocsServer) -> Result<()> {
252 run_hyper_server(server, "Hybrid", true).await
253}
254
255/// 传输模式
256///
257/// 定义 MCP 服务器支持的传输协议类型。
258///
259/// # 变体
260///
261/// - `Stdio`: 标准输入输出,适合与 MCP 客户端集成
262/// - `Http`: Streamable HTTP,支持无状态请求
263/// - `Sse`: Server-Sent Events,支持服务器推送
264/// - `Hybrid`: 混合模式,同时支持 HTTP 和 SSE
265///
266/// # 示例
267///
268/// ```rust
269/// use crates_docs::server::transport::TransportMode;
270/// use std::str::FromStr;
271///
272/// let mode = TransportMode::from_str("http").unwrap();
273/// assert_eq!(mode, TransportMode::Http);
274/// assert_eq!(mode.to_string(), "http");
275/// ```
276#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
277pub enum TransportMode {
278 /// Stdio 传输(用于 CLI 集成)
279 Stdio,
280 /// HTTP 传输(Streamable HTTP)
281 Http,
282 /// SSE 传输(Server-Sent Events)
283 Sse,
284 /// 混合模式(同时支持 HTTP 和 SSE)
285 Hybrid,
286}
287
288impl std::str::FromStr for TransportMode {
289 type Err = String;
290
291 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
292 match s.to_lowercase().as_str() {
293 "stdio" => Ok(TransportMode::Stdio),
294 "http" => Ok(TransportMode::Http),
295 "sse" => Ok(TransportMode::Sse),
296 "hybrid" => Ok(TransportMode::Hybrid),
297 _ => Err(format!("Unknown transport mode: {s}")),
298 }
299 }
300}
301
302impl std::fmt::Display for TransportMode {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 match self {
305 TransportMode::Stdio => write!(f, "stdio"),
306 TransportMode::Http => write!(f, "http"),
307 TransportMode::Sse => write!(f, "sse"),
308 TransportMode::Hybrid => write!(f, "hybrid"),
309 }
310 }
311}
312
313/// Run server with the specified transport mode
314pub async fn run_server_with_mode(server: &CratesDocsServer, mode: TransportMode) -> Result<()> {
315 match mode {
316 TransportMode::Stdio => run_stdio_server(server).await,
317 TransportMode::Http => run_http_server(server).await,
318 TransportMode::Sse => run_sse_server(server).await,
319 TransportMode::Hybrid => run_hybrid_server(server).await,
320 }
321}