crates_docs/server/
mod.rs1pub mod auth;
6pub mod handler;
7pub mod transport;
8
9use crate::cache::Cache;
10use crate::config::AppConfig;
11use crate::error::Result;
12use crate::tools::ToolRegistry;
13use rust_mcp_sdk::schema::{
14 Implementation, InitializeResult, ProtocolVersion, ServerCapabilities, ServerCapabilitiesTools,
15};
16use std::sync::Arc;
17
18pub use crate::config::ServerConfig;
20
21#[derive(Clone)]
23pub struct CratesDocsServer {
24 config: AppConfig,
25 tool_registry: Arc<ToolRegistry>,
26 cache: Arc<dyn Cache>,
27}
28
29impl CratesDocsServer {
30 fn from_parts(config: AppConfig, cache: Arc<dyn Cache>) -> crate::error::Result<Self> {
32 let doc_service = Arc::new(crate::tools::docs::DocService::with_config(
34 cache.clone(),
35 &config.cache,
36 )?);
37
38 let tool_registry = Arc::new(crate::tools::create_default_registry(&doc_service));
40
41 Ok(Self {
42 config,
43 tool_registry,
44 cache,
45 })
46 }
47
48 pub fn new(config: AppConfig) -> Result<Self> {
52 let cache_box: Box<dyn Cache> = crate::cache::create_cache(&config.cache)?;
53 let cache: Arc<dyn Cache> = Arc::from(cache_box);
54 Self::from_parts(config, cache)
55 }
56
57 #[allow(unused_variables)]
61 #[allow(clippy::unused_async)]
62 pub async fn new_async(config: AppConfig) -> Result<Self> {
63 #[cfg(feature = "cache-redis")]
65 {
66 let cache_box: Box<dyn Cache> = crate::cache::create_cache_async(&config.cache).await?;
67 let cache: Arc<dyn Cache> = Arc::from(cache_box);
68 Self::from_parts(config, cache)
69 }
70
71 #[cfg(not(feature = "cache-redis"))]
72 {
73 let cache_box: Box<dyn Cache> = crate::cache::create_cache(&config.cache)?;
75 let cache: Arc<dyn Cache> = Arc::from(cache_box);
76 Self::from_parts(config, cache)
77 }
78 }
79
80 #[must_use]
82 pub fn config(&self) -> &AppConfig {
83 &self.config
84 }
85
86 #[must_use]
88 pub fn tool_registry(&self) -> &Arc<ToolRegistry> {
89 &self.tool_registry
90 }
91
92 #[must_use]
94 pub fn cache(&self) -> &Arc<dyn Cache> {
95 &self.cache
96 }
97
98 #[must_use]
100 pub fn server_info(&self) -> InitializeResult {
101 InitializeResult {
102 server_info: Implementation {
103 name: self.config.server.name.clone(),
104 version: self.config.server.version.clone(),
105 title: Some("Crates Docs MCP Server".to_string()),
106 description: self.config.server.description.clone(),
107 icons: self.config.server.icons.clone(),
108 website_url: self.config.server.website_url.clone(),
109 },
110 capabilities: ServerCapabilities {
111 tools: Some(ServerCapabilitiesTools { list_changed: None }),
112 resources: None,
113 prompts: None,
114 experimental: None,
115 completions: None,
116 logging: None,
117 tasks: None,
118 },
119 protocol_version: ProtocolVersion::V2025_11_25.into(),
120 instructions: Some(
121 "Use this server to query Rust crate documentation. Supports crate lookup, crate search, and health check."
122 .to_string(),
123 ),
124 meta: None,
125 }
126 }
127
128 pub async fn run_stdio(&self) -> Result<()> {
130 transport::run_stdio_server(self).await
131 }
132
133 pub async fn run_http(&self) -> Result<()> {
135 transport::run_http_server(self).await
136 }
137
138 pub async fn run_sse(&self) -> Result<()> {
140 transport::run_sse_server(self).await
141 }
142}