Skip to main content

crates_docs/server/
handler.rs

1//! MCP handler implementation
2
3use crate::server::CratesDocsServer;
4use crate::tools::ToolRegistry;
5use async_trait::async_trait;
6use rust_mcp_sdk::{
7    mcp_server::{ServerHandler, ServerHandlerCore},
8    schema::{
9        CallToolError, CallToolRequestParams, CallToolResult, GetPromptRequestParams,
10        GetPromptResult, ListPromptsResult, ListResourcesResult, ListToolsResult,
11        NotificationFromClient, PaginatedRequestParams, ReadResourceRequestParams,
12        ReadResourceResult, RequestFromClient, ResultFromServer, RpcError,
13    },
14    McpServer,
15};
16use std::sync::Arc;
17
18/// MCP server handler
19pub struct CratesDocsHandler {
20    server: Arc<CratesDocsServer>,
21}
22
23impl CratesDocsHandler {
24    /// Create a new handler
25    #[must_use]
26    pub fn new(server: Arc<CratesDocsServer>) -> Self {
27        Self { server }
28    }
29
30    /// Get the tool registry
31    fn tool_registry(&self) -> &ToolRegistry {
32        self.server.tool_registry()
33    }
34}
35
36#[async_trait]
37impl ServerHandler for CratesDocsHandler {
38    /// Handle list tools request
39    async fn handle_list_tools_request(
40        &self,
41        _request: Option<PaginatedRequestParams>,
42        _runtime: std::sync::Arc<dyn McpServer>,
43    ) -> std::result::Result<ListToolsResult, RpcError> {
44        let tools = self.tool_registry().get_tools();
45
46        Ok(ListToolsResult {
47            tools,
48            meta: None,
49            next_cursor: None,
50        })
51    }
52
53    /// Handle call tool request
54    async fn handle_call_tool_request(
55        &self,
56        params: CallToolRequestParams,
57        _runtime: std::sync::Arc<dyn McpServer>,
58    ) -> std::result::Result<CallToolResult, CallToolError> {
59        self.tool_registry()
60            .execute_tool(
61                &params.name,
62                params
63                    .arguments
64                    .map_or_else(|| serde_json::Value::Null, serde_json::Value::Object),
65            )
66            .await
67    }
68
69    /// Handle list resources request
70    async fn handle_list_resources_request(
71        &self,
72        _request: Option<PaginatedRequestParams>,
73        _runtime: std::sync::Arc<dyn McpServer>,
74    ) -> std::result::Result<ListResourcesResult, RpcError> {
75        // Resources are not currently provided
76        Ok(ListResourcesResult {
77            resources: vec![],
78            meta: None,
79            next_cursor: None,
80        })
81    }
82
83    /// Handle read resource request
84    async fn handle_read_resource_request(
85        &self,
86        _params: ReadResourceRequestParams,
87        _runtime: std::sync::Arc<dyn McpServer>,
88    ) -> std::result::Result<ReadResourceResult, RpcError> {
89        // Resources are not currently provided
90        Err(RpcError::invalid_request().with_message("Resource not found".to_string()))
91    }
92
93    /// Handle list prompts request
94    async fn handle_list_prompts_request(
95        &self,
96        _request: Option<PaginatedRequestParams>,
97        _runtime: std::sync::Arc<dyn McpServer>,
98    ) -> std::result::Result<ListPromptsResult, RpcError> {
99        // Prompts are not currently provided
100        Ok(ListPromptsResult {
101            prompts: vec![],
102            meta: None,
103            next_cursor: None,
104        })
105    }
106
107    /// Handle get prompt request
108    async fn handle_get_prompt_request(
109        &self,
110        _params: GetPromptRequestParams,
111        _runtime: std::sync::Arc<dyn McpServer>,
112    ) -> std::result::Result<GetPromptResult, RpcError> {
113        // Prompts are not currently provided
114        Err(RpcError::invalid_request().with_message("Prompt not found".to_string()))
115    }
116}
117
118/// Core handler implementation (provides more control)
119pub struct CratesDocsHandlerCore {
120    server: Arc<CratesDocsServer>,
121}
122
123impl CratesDocsHandlerCore {
124    /// Create a new core handler
125    #[must_use]
126    pub fn new(server: Arc<CratesDocsServer>) -> Self {
127        Self { server }
128    }
129}
130
131#[async_trait]
132impl ServerHandlerCore for CratesDocsHandlerCore {
133    /// Handle request
134    async fn handle_request(
135        &self,
136        request: RequestFromClient,
137        _runtime: std::sync::Arc<dyn McpServer>,
138    ) -> std::result::Result<ResultFromServer, RpcError> {
139        match request {
140            RequestFromClient::ListToolsRequest(_params) => {
141                let tools = self.server.tool_registry().get_tools();
142                Ok(ListToolsResult {
143                    tools,
144                    meta: None,
145                    next_cursor: None,
146                }
147                .into())
148            }
149            RequestFromClient::CallToolRequest(params) => {
150                let result = self
151                    .server
152                    .tool_registry()
153                    .execute_tool(
154                        &params.name,
155                        params
156                            .arguments
157                            .map_or_else(|| serde_json::Value::Null, serde_json::Value::Object),
158                    )
159                    .await
160                    .map_err(|_e| CallToolError::unknown_tool(params.name.clone()))?;
161                Ok(result.into())
162            }
163            RequestFromClient::ListResourcesRequest(_params) => Ok(ListResourcesResult {
164                resources: vec![],
165                meta: None,
166                next_cursor: None,
167            }
168            .into()),
169            RequestFromClient::ReadResourceRequest(_params) => {
170                Err(RpcError::invalid_request().with_message("Resource not found".to_string()))
171            }
172            RequestFromClient::ListPromptsRequest(_params) => Ok(ListPromptsResult {
173                prompts: vec![],
174                meta: None,
175                next_cursor: None,
176            }
177            .into()),
178            RequestFromClient::GetPromptRequest(_params) => {
179                Err(RpcError::invalid_request().with_message("Prompt not found".to_string()))
180            }
181            RequestFromClient::InitializeRequest(_params) => {
182                // Use default initialization handling
183                Err(RpcError::method_not_found()
184                    .with_message("Initialize request should be handled by runtime".to_string()))
185            }
186            _ => {
187                // Other requests use default handling
188                Err(RpcError::method_not_found()
189                    .with_message("Unimplemented request type".to_string()))
190            }
191        }
192    }
193
194    /// Handle notification
195    async fn handle_notification(
196        &self,
197        _notification: NotificationFromClient,
198        _runtime: std::sync::Arc<dyn McpServer>,
199    ) -> std::result::Result<(), RpcError> {
200        // Notifications are not currently handled
201        Ok(())
202    }
203
204    /// Handle error
205    async fn handle_error(
206        &self,
207        _error: &RpcError,
208        _runtime: std::sync::Arc<dyn McpServer>,
209    ) -> std::result::Result<(), RpcError> {
210        // Log error but don't interrupt
211        tracing::error!("MCP error: {:?}", _error);
212        Ok(())
213    }
214}