embacle_server/mcp/
protocol.rs1use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10pub const PROTOCOL_VERSION: &str = "2024-11-05";
12
13pub const SERVER_NAME: &str = "embacle-server";
15
16pub const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
18
19pub const PARSE_ERROR: i32 = -32_700;
25
26pub const INVALID_REQUEST: i32 = -32_600;
28
29pub const METHOD_NOT_FOUND: i32 = -32_601;
31
32pub const INVALID_PARAMS: i32 = -32_602;
34
35pub const INTERNAL_ERROR: i32 = -32_603;
37
38#[derive(Debug, Deserialize)]
44pub struct JsonRpcRequest {
45 pub jsonrpc: String,
47 pub id: Option<Value>,
49 pub method: String,
51 #[serde(default)]
53 pub params: Option<Value>,
54}
55
56#[derive(Debug, Serialize)]
58pub struct JsonRpcResponse {
59 pub jsonrpc: String,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub id: Option<Value>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub result: Option<Value>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub error: Option<JsonRpcError>,
70}
71
72#[derive(Debug, Serialize)]
74pub struct JsonRpcError {
75 pub code: i32,
77 pub message: String,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub data: Option<Value>,
82}
83
84impl JsonRpcResponse {
85 pub fn success(id: Option<Value>, result: Value) -> Self {
87 Self {
88 jsonrpc: "2.0".to_owned(),
89 id,
90 result: Some(result),
91 error: None,
92 }
93 }
94
95 pub fn error(id: Option<Value>, code: i32, message: String) -> Self {
97 Self {
98 jsonrpc: "2.0".to_owned(),
99 id,
100 result: None,
101 error: Some(JsonRpcError {
102 code,
103 message,
104 data: None,
105 }),
106 }
107 }
108}
109
110#[derive(Debug, Deserialize)]
116pub struct InitializeParams {
117 #[serde(rename = "protocolVersion")]
119 pub protocol_version: String,
120 #[serde(default)]
122 pub capabilities: Value,
123 #[serde(rename = "clientInfo")]
125 pub client_info: ClientInfo,
126}
127
128#[derive(Debug, Deserialize)]
130pub struct ClientInfo {
131 pub name: String,
133 #[serde(default)]
135 pub version: Option<String>,
136}
137
138#[derive(Debug, Serialize)]
140pub struct InitializeResult {
141 #[serde(rename = "protocolVersion")]
143 pub protocol_version: String,
144 pub capabilities: ServerCapabilities,
146 #[serde(rename = "serverInfo")]
148 pub server_info: ServerInfo,
149}
150
151#[derive(Debug, Serialize)]
153pub struct ServerInfo {
154 pub name: String,
156 pub version: String,
158}
159
160#[derive(Debug, Serialize)]
162pub struct ServerCapabilities {
163 #[serde(skip_serializing_if = "Option::is_none")]
165 pub tools: Option<ToolsCapability>,
166}
167
168#[derive(Debug, Serialize)]
170pub struct ToolsCapability {}
171
172#[derive(Debug, Clone, Serialize)]
178pub struct ToolDefinition {
179 pub name: String,
181 pub description: String,
183 #[serde(rename = "inputSchema")]
185 pub input_schema: Value,
186}
187
188#[derive(Debug, Serialize)]
190pub struct ToolsListResult {
191 pub tools: Vec<ToolDefinition>,
193}
194
195#[derive(Debug, Deserialize)]
197pub struct CallToolParams {
198 pub name: String,
200 #[serde(default)]
202 pub arguments: Option<Value>,
203}
204
205#[derive(Debug, Serialize)]
207pub struct CallToolResult {
208 pub content: Vec<ContentPart>,
210 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
212 pub is_error: Option<bool>,
213}
214
215#[derive(Debug, Serialize)]
217pub struct ContentPart {
218 #[serde(rename = "type")]
220 pub content_type: String,
221 pub text: String,
223}
224
225impl CallToolResult {
226 pub fn text(content: String) -> Self {
228 Self {
229 content: vec![ContentPart {
230 content_type: "text".to_owned(),
231 text: content,
232 }],
233 is_error: None,
234 }
235 }
236
237 pub fn error(message: String) -> Self {
239 Self {
240 content: vec![ContentPart {
241 content_type: "text".to_owned(),
242 text: message,
243 }],
244 is_error: Some(true),
245 }
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn serialize_success_response() {
255 let resp = JsonRpcResponse::success(Some(Value::from(1)), serde_json::json!({"ok": true}));
256 let json = serde_json::to_string(&resp).expect("serialize");
257 assert!(json.contains("\"result\""));
258 assert!(!json.contains("\"error\""));
259 }
260
261 #[test]
262 fn serialize_error_response() {
263 let resp = JsonRpcResponse::error(Some(Value::from(1)), PARSE_ERROR, "bad json".to_owned());
264 let json = serde_json::to_string(&resp).expect("serialize");
265 assert!(json.contains("\"error\""));
266 assert!(json.contains("-32700"));
267 assert!(!json.contains("\"result\""));
268 }
269
270 #[test]
271 fn deserialize_request() {
272 let raw = r#"{"jsonrpc":"2.0","id":1,"method":"tools/list"}"#;
273 let req: JsonRpcRequest = serde_json::from_str(raw).expect("deserialize");
274 assert_eq!(req.method, "tools/list");
275 assert!(req.params.is_none());
276 }
277
278 #[test]
279 fn call_tool_result_text() {
280 let result = CallToolResult::text("hello".to_owned());
281 assert!(result.is_error.is_none());
282 assert_eq!(result.content.len(), 1);
283 assert_eq!(result.content[0].text, "hello");
284 }
285
286 #[test]
287 fn call_tool_result_error() {
288 let result = CallToolResult::error("oops".to_owned());
289 assert_eq!(result.is_error, Some(true));
290 assert_eq!(result.content[0].text, "oops");
291 }
292}