embacle_server/mcp/
server.rs1use serde_json::Value;
8use tracing::debug;
9
10use super::protocol::{
11 CallToolParams, InitializeParams, InitializeResult, JsonRpcRequest, JsonRpcResponse,
12 ServerCapabilities, ServerInfo, ToolsCapability, ToolsListResult, INTERNAL_ERROR,
13 INVALID_PARAMS, INVALID_REQUEST, METHOD_NOT_FOUND, PROTOCOL_VERSION, SERVER_NAME,
14 SERVER_VERSION,
15};
16use super::tools::ToolRegistry;
17use crate::state::SharedState;
18
19pub struct McpServer {
24 state: SharedState,
25 tools: ToolRegistry,
26}
27
28impl McpServer {
29 pub const fn new(state: SharedState, tools: ToolRegistry) -> Self {
31 Self { state, tools }
32 }
33
34 pub async fn handle_request(&self, request: JsonRpcRequest) -> Option<JsonRpcResponse> {
38 if request.jsonrpc != "2.0" {
39 return Some(JsonRpcResponse::error(
40 request.id,
41 INVALID_REQUEST,
42 format!("Unsupported JSON-RPC version: {}", request.jsonrpc),
43 ));
44 }
45
46 if request.id.is_none() {
48 debug!(method = %request.method, "Received notification, no response");
49 return None;
50 }
51
52 let response = match request.method.as_str() {
53 "initialize" => Self::handle_initialize(request.id, request.params),
54 "tools/list" => self.handle_tools_list(request.id),
55 "tools/call" => self.handle_tools_call(request.id, request.params).await,
56 "ping" => JsonRpcResponse::success(request.id, Value::Object(serde_json::Map::new())),
57 method => {
58 debug!(method, "Unknown MCP method");
59 JsonRpcResponse::error(
60 request.id,
61 METHOD_NOT_FOUND,
62 format!("Method not found: {method}"),
63 )
64 }
65 };
66
67 Some(response)
68 }
69
70 fn handle_initialize(id: Option<Value>, params: Option<Value>) -> JsonRpcResponse {
72 if let Some(params) = params {
73 if let Ok(init) = serde_json::from_value::<InitializeParams>(params) {
74 debug!(
75 client = %init.client_info.name,
76 version = ?init.client_info.version,
77 protocol = %init.protocol_version,
78 "MCP client connected"
79 );
80 }
81 }
82
83 let result = InitializeResult {
84 protocol_version: PROTOCOL_VERSION.to_owned(),
85 capabilities: ServerCapabilities {
86 tools: Some(ToolsCapability {}),
87 },
88 server_info: ServerInfo {
89 name: SERVER_NAME.to_owned(),
90 version: SERVER_VERSION.to_owned(),
91 },
92 };
93
94 match serde_json::to_value(result) {
95 Ok(val) => JsonRpcResponse::success(id, val),
96 Err(e) => {
97 JsonRpcResponse::error(id, INTERNAL_ERROR, format!("Serialization error: {e}"))
98 }
99 }
100 }
101
102 fn handle_tools_list(&self, id: Option<Value>) -> JsonRpcResponse {
104 let result = ToolsListResult {
105 tools: self.tools.list_definitions(),
106 };
107
108 match serde_json::to_value(result) {
109 Ok(val) => JsonRpcResponse::success(id, val),
110 Err(e) => {
111 JsonRpcResponse::error(id, INTERNAL_ERROR, format!("Serialization error: {e}"))
112 }
113 }
114 }
115
116 async fn handle_tools_call(&self, id: Option<Value>, params: Option<Value>) -> JsonRpcResponse {
118 let call_params: CallToolParams = match params {
119 Some(p) => match serde_json::from_value(p) {
120 Ok(cp) => cp,
121 Err(e) => {
122 return JsonRpcResponse::error(
123 id,
124 INVALID_PARAMS,
125 format!("Invalid params: {e}"),
126 );
127 }
128 },
129 None => {
130 return JsonRpcResponse::error(
131 id,
132 INVALID_PARAMS,
133 "Missing params for tools/call".to_owned(),
134 );
135 }
136 };
137
138 let arguments = call_params
139 .arguments
140 .unwrap_or_else(|| Value::Object(serde_json::Map::new()));
141
142 let result = self
143 .tools
144 .execute(&call_params.name, &self.state, arguments)
145 .await;
146
147 match serde_json::to_value(result) {
148 Ok(val) => JsonRpcResponse::success(id, val),
149 Err(e) => JsonRpcResponse::error(
150 id,
151 INTERNAL_ERROR,
152 format!("Result serialization error: {e}"),
153 ),
154 }
155 }
156}