spec_kit_mcp/mcp/
server.rs

1//! MCP Server Implementation
2//!
3//! The main server that handles MCP protocol communication.
4
5use anyhow::{Context, Result};
6use std::sync::Arc;
7
8use super::protocol::ProtocolHandler;
9use super::transport::StdioTransport;
10use super::types::{JsonRpcRequest, RequestId};
11use crate::tools::ToolRegistry;
12
13/// MCP Server
14pub struct McpServer {
15    transport: StdioTransport,
16    protocol: ProtocolHandler,
17    registry: Arc<ToolRegistry>,
18}
19
20impl McpServer {
21    /// Create a new MCP server
22    pub fn new(registry: ToolRegistry) -> Self {
23        Self {
24            transport: StdioTransport::new(),
25            protocol: ProtocolHandler::new(),
26            registry: Arc::new(registry),
27        }
28    }
29
30    /// Run the server (main event loop)
31    pub async fn run(&mut self) -> Result<()> {
32        tracing::info!("MCP server starting...");
33
34        loop {
35            // Read request
36            let request = match self.transport.read_request().await {
37                Ok(req) => req,
38                Err(e) => {
39                    if e.to_string().contains("EOF") {
40                        tracing::info!("Client disconnected");
41                        break;
42                    }
43                    tracing::error!(error = %e, "Failed to read request");
44                    continue;
45                }
46            };
47
48            // Handle request
49            let response = self.handle_request(request).await;
50
51            // Write response
52            if let Err(e) = self.transport.write_response(response).await {
53                tracing::error!(error = %e, "Failed to write response");
54            }
55        }
56
57        tracing::info!("MCP server stopped");
58        Ok(())
59    }
60
61    /// Handle a JSON-RPC request
62    async fn handle_request(&self, request: JsonRpcRequest) -> super::types::JsonRpcResponse {
63        // Validate request
64        if let Err(e) = self.protocol.validate_request(&request) {
65            return self.protocol.create_error_response(request.id, e);
66        }
67
68        // Route to appropriate handler
69        match request.method.as_str() {
70            "initialize" => self.protocol.handle_initialize(request.id),
71
72            "ping" => self.protocol.handle_ping(request.id),
73
74            "tools/list" => {
75                let tools = self.registry.list_tools();
76                self.protocol.create_tool_list_response(request.id, tools)
77            }
78
79            "tools/call" => {
80                match self
81                    .handle_tool_call(request.id.clone(), request.params)
82                    .await
83                {
84                    Ok(response) => response,
85                    Err(e) => self.protocol.create_error_response(request.id, e),
86                }
87            }
88
89            _ => {
90                let error = super::types::JsonRpcError::method_not_found(&request.method);
91                super::types::JsonRpcResponse::error(request.id, error)
92            }
93        }
94    }
95
96    /// Handle a tool call
97    async fn handle_tool_call(
98        &self,
99        id: RequestId,
100        params: Option<serde_json::Value>,
101    ) -> Result<super::types::JsonRpcResponse> {
102        // Parse tool call parameters
103        let tool_call = self.protocol.parse_tool_call(params)?;
104
105        tracing::info!(tool_name = %tool_call.name, "Executing tool");
106
107        // Get the tool
108        let tool = self
109            .registry
110            .get(&tool_call.name)
111            .ok_or_else(|| anyhow::anyhow!("Tool not found: {}", tool_call.name))?;
112
113        // Execute the tool
114        let result = tool
115            .execute(tool_call.arguments)
116            .await
117            .context("Tool execution failed")?;
118
119        // Create response
120        Ok(self.protocol.create_tool_result_response(id, result))
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127    use crate::speckit::SpecKitCli;
128    use crate::tools::create_registry;
129
130    #[test]
131    fn test_server_creation() {
132        let cli = SpecKitCli::new();
133        let registry = create_registry(cli);
134        let server = McpServer::new(registry);
135
136        // Just ensure server can be created
137        assert!(std::mem::size_of_val(&server) > 0);
138    }
139}