crates_docs/server/mod.rs
1//! 服务器模块
2//!
3//! 提供 MCP 服务器实现,支持多种传输协议(stdio、HTTP、SSE、Hybrid)。
4//!
5//! # 主要组件
6//!
7//! - `CratesDocsServer`: 主服务器结构体
8//! - `handler`: MCP 请求处理
9//! - `transport`: 传输层实现
10//! - `auth`: OAuth 认证支持
11//!
12//! # Handler 设计模式
13//!
14//! 使用组合模式消除代码重复:
15//! - `HandlerCore`: 封装共享核心处理逻辑
16//! - `CratesDocsHandler`: 标准 MCP 处理器(委托给 `HandlerCore`)
17//! - `CratesDocsHandlerCore`: 核心处理器(委托给 `HandlerCore`)
18//! - `HandlerConfig`: 配置类,支持 merge 操作
19//!
20//! # 示例
21//!
22//! ```rust,no_run
23//! use crates_docs::{AppConfig, CratesDocsServer};
24//! use crates_docs::server::handler::{CratesDocsHandler, HandlerConfig};
25//! use std::sync::Arc;
26//!
27//! #[tokio::main]
28//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
29//! let config = AppConfig::default();
30//! let server = Arc::new(CratesDocsServer::new(config)?);
31//!
32//! // 使用 merge 配置创建 handler
33//! let base_config = HandlerConfig::default();
34//! let override_config = HandlerConfig::new().with_verbose_logging();
35//! let handler = CratesDocsHandler::with_merged_config(
36//! server,
37//! base_config,
38//! Some(override_config)
39//! );
40//!
41//! // 运行 HTTP 服务器
42//! crates_docs::server::transport::run_http_server(&handler.server()).await?;
43//!
44//! Ok(())
45//! }
46//! ```
47
48pub mod auth;
49pub mod auth_middleware;
50pub mod handler;
51pub mod transport;
52
53use crate::cache::Cache;
54use crate::config::AppConfig;
55use crate::error::Result;
56use crate::tools::ToolRegistry;
57use rust_mcp_sdk::schema::{
58 Implementation, InitializeResult, ProtocolVersion, ServerCapabilities, ServerCapabilitiesTools,
59};
60use std::sync::Arc;
61
62/// 从配置模块重新导出 `ServerConfig` 以保持向后兼容
63pub use crate::config::ServerConfig;
64
65/// 从 handler 模块重新导出 `CratesDocsHandler`
66pub use handler::CratesDocsHandler;
67
68/// Crates Docs MCP 服务器
69///
70/// 主服务器结构体,管理配置、工具注册表和缓存。
71/// 支持多种传输协议:stdio、HTTP、SSE、Hybrid。
72///
73/// # 字段
74///
75/// - `config`: 应用配置
76/// - `tool_registry`: 工具注册表
77/// - `cache`: 缓存实例
78#[derive(Clone)]
79pub struct CratesDocsServer {
80 config: AppConfig,
81 tool_registry: Arc<ToolRegistry>,
82 cache: Arc<dyn Cache>,
83}
84
85impl CratesDocsServer {
86 /// 从组件创建服务器(内部初始化逻辑)
87 ///
88 /// # 参数
89 ///
90 /// * `config` - 应用配置
91 /// * `cache` - 缓存实例
92 ///
93 /// # 错误
94 ///
95 /// 如果文档服务创建失败,返回错误
96 fn from_parts(config: AppConfig, cache: Arc<dyn Cache>) -> crate::error::Result<Self> {
97 // Initialize global HTTP client with performance config for connection pool reuse
98 // This ensures all HTTP requests share the same connection pool
99 // Note: init_global_http_client will fail if already initialized, which is fine
100 let _ = crate::utils::init_global_http_client(&config.performance);
101
102 // Create document service with cache configuration
103 let doc_service = Arc::new(crate::tools::docs::DocService::with_config(
104 cache.clone(),
105 &config.cache,
106 )?);
107
108 // Create tool registry
109 let tool_registry = Arc::new(crate::tools::create_default_registry(&doc_service));
110
111 Ok(Self {
112 config,
113 tool_registry,
114 cache,
115 })
116 }
117
118 /// 创建新的服务器实例(同步)
119 ///
120 /// # 参数
121 ///
122 /// * `config` - 应用配置
123 ///
124 /// # 错误
125 ///
126 /// 如果缓存创建失败,返回错误
127 ///
128 /// # 注意
129 ///
130 /// 此方法仅支持内存缓存。如需使用 Redis,请使用 [`new_async`](Self::new_async) 方法。
131 ///
132 /// # 示例
133 ///
134 /// ```rust,no_run
135 /// use crates_docs::{AppConfig, CratesDocsServer};
136 ///
137 /// let config = AppConfig::default();
138 /// let server = CratesDocsServer::new(config).expect("Failed to create server");
139 /// ```
140 pub fn new(config: AppConfig) -> Result<Self> {
141 let cache_box: Box<dyn Cache> = crate::cache::create_cache(&config.cache)?;
142 let cache: Arc<dyn Cache> = Arc::from(cache_box);
143 Self::from_parts(config, cache)
144 }
145
146 /// 创建新的服务器实例(异步)
147 ///
148 /// # 参数
149 ///
150 /// * `config` - 应用配置
151 ///
152 /// # 错误
153 ///
154 /// 如果缓存创建失败,返回错误
155 ///
156 /// # 注意
157 ///
158 /// 支持内存缓存和 Redis 缓存(需要启用 `cache-redis` feature)。
159 ///
160 /// # 示例
161 ///
162 /// ```rust,no_run
163 /// use crates_docs::{AppConfig, CratesDocsServer};
164 ///
165 /// #[tokio::main]
166 /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
167 /// let config = AppConfig::default();
168 /// let server = CratesDocsServer::new_async(config).await?;
169 /// Ok(())
170 /// }
171 /// ```
172 #[allow(unused_variables)]
173 #[allow(clippy::unused_async)]
174 pub async fn new_async(config: AppConfig) -> Result<Self> {
175 // Decide which creation method to use based on cache type and feature
176 #[cfg(feature = "cache-redis")]
177 {
178 let cache_box: Box<dyn Cache> = crate::cache::create_cache_async(&config.cache).await?;
179 let cache: Arc<dyn Cache> = Arc::from(cache_box);
180 Self::from_parts(config, cache)
181 }
182
183 #[cfg(not(feature = "cache-redis"))]
184 {
185 // No cache-redis feature, fall back to synchronous creation
186 let cache_box: Box<dyn Cache> = crate::cache::create_cache(&config.cache)?;
187 let cache: Arc<dyn Cache> = Arc::from(cache_box);
188 Self::from_parts(config, cache)
189 }
190 }
191
192 /// 获取服务器配置
193 #[must_use]
194 pub fn config(&self) -> &AppConfig {
195 &self.config
196 }
197
198 /// 获取工具注册表
199 #[must_use]
200 pub fn tool_registry(&self) -> &Arc<ToolRegistry> {
201 &self.tool_registry
202 }
203
204 /// 获取缓存实例
205 #[must_use]
206 pub fn cache(&self) -> &Arc<dyn Cache> {
207 &self.cache
208 }
209
210 /// 获取服务器信息
211 ///
212 /// 返回 MCP 初始化结果,包含服务器元数据和能力信息
213 #[must_use]
214 pub fn server_info(&self) -> InitializeResult {
215 InitializeResult {
216 server_info: Implementation {
217 name: self.config.server.name.clone(),
218 version: self.config.server.version.clone(),
219 title: Some("Crates Docs MCP Server".to_string()),
220 description: self.config.server.description.clone(),
221 icons: self.config.server.icons.clone(),
222 website_url: self.config.server.website_url.clone(),
223 },
224 capabilities: ServerCapabilities {
225 tools: Some(ServerCapabilitiesTools { list_changed: None }),
226 resources: None,
227 prompts: None,
228 experimental: None,
229 completions: None,
230 logging: None,
231 tasks: None,
232 },
233 protocol_version: ProtocolVersion::V2025_11_25.into(),
234 instructions: Some(
235 "Use this server to query Rust crate documentation. Supports crate lookup, crate search, and health check."
236 .to_string(),
237 ),
238 meta: None,
239 }
240 }
241
242 /// 运行 Stdio 服务器
243 ///
244 /// # 错误
245 ///
246 /// 如果服务器启动失败,返回错误
247 pub async fn run_stdio(&self) -> Result<()> {
248 transport::run_stdio_server(self).await
249 }
250
251 /// 运行 HTTP 服务器
252 ///
253 /// # 错误
254 ///
255 /// 如果服务器启动失败,返回错误
256 pub async fn run_http(&self) -> Result<()> {
257 transport::run_http_server(self).await
258 }
259
260 /// 运行 SSE 服务器
261 ///
262 /// # 错误
263 ///
264 /// 如果服务器启动失败,返回错误
265 pub async fn run_sse(&self) -> Result<()> {
266 transport::run_sse_server(self).await
267 }
268}