Skip to main content

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