Skip to main content

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}