spec_kit_mcp/mcp/
server.rs1use 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
13pub struct McpServer {
15 transport: StdioTransport,
16 protocol: ProtocolHandler,
17 registry: Arc<ToolRegistry>,
18}
19
20impl McpServer {
21 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 pub async fn run(&mut self) -> Result<()> {
32 tracing::info!("MCP server starting...");
33
34 loop {
35 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 let response = self.handle_request(request).await;
50
51 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 async fn handle_request(&self, request: JsonRpcRequest) -> super::types::JsonRpcResponse {
63 if let Err(e) = self.protocol.validate_request(&request) {
65 return self.protocol.create_error_response(request.id, e);
66 }
67
68 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 async fn handle_tool_call(
98 &self,
99 id: RequestId,
100 params: Option<serde_json::Value>,
101 ) -> Result<super::types::JsonRpcResponse> {
102 let tool_call = self.protocol.parse_tool_call(params)?;
104
105 tracing::info!(tool_name = %tool_call.name, "Executing tool");
106
107 let tool = self
109 .registry
110 .get(&tool_call.name)
111 .ok_or_else(|| anyhow::anyhow!("Tool not found: {}", tool_call.name))?;
112
113 let result = tool
115 .execute(tool_call.arguments)
116 .await
117 .context("Tool execution failed")?;
118
119 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 assert!(std::mem::size_of_val(&server) > 0);
138 }
139}