1use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct JsonRpcRequest {
11 pub jsonrpc: String,
13
14 pub id: RequestId,
16
17 pub method: String,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub params: Option<Value>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct JsonRpcResponse {
28 pub jsonrpc: String,
30
31 pub id: RequestId,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub result: Option<Value>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub error: Option<JsonRpcError>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
45#[serde(untagged)]
46pub enum RequestId {
47 String(String),
48 Number(i64),
49 Null,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct JsonRpcError {
55 pub code: i32,
57
58 pub message: String,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub data: Option<Value>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ToolDefinition {
69 pub name: String,
71
72 pub description: String,
74
75 #[serde(rename = "inputSchema")]
77 pub input_schema: Value,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct ToolCallParams {
83 pub name: String,
85
86 #[serde(default)]
88 pub arguments: Value,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct ToolResult {
94 pub content: Vec<ContentBlock>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub is_error: Option<bool>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
104#[serde(tag = "type")]
105pub enum ContentBlock {
106 #[serde(rename = "text")]
107 Text { text: String },
108
109 #[serde(rename = "image")]
110 Image { data: String, mime_type: String },
111
112 #[serde(rename = "resource")]
113 Resource {
114 uri: String,
115 mime_type: Option<String>,
116 text: Option<String>,
117 },
118}
119
120impl ContentBlock {
121 pub fn text(text: impl Into<String>) -> Self {
123 Self::Text { text: text.into() }
124 }
125}
126
127pub mod error_codes {
129 pub const PARSE_ERROR: i32 = -32700;
130 pub const INVALID_REQUEST: i32 = -32600;
131 pub const METHOD_NOT_FOUND: i32 = -32601;
132 pub const INVALID_PARAMS: i32 = -32602;
133 pub const INTERNAL_ERROR: i32 = -32603;
134}
135
136impl JsonRpcResponse {
137 pub fn success(id: RequestId, result: Value) -> Self {
139 Self {
140 jsonrpc: "2.0".to_string(),
141 id,
142 result: Some(result),
143 error: None,
144 }
145 }
146
147 pub fn error(id: RequestId, error: JsonRpcError) -> Self {
149 Self {
150 jsonrpc: "2.0".to_string(),
151 id,
152 result: None,
153 error: Some(error),
154 }
155 }
156}
157
158impl JsonRpcError {
159 pub fn new(code: i32, message: impl Into<String>) -> Self {
161 Self {
162 code,
163 message: message.into(),
164 data: None,
165 }
166 }
167
168 pub fn with_data(code: i32, message: impl Into<String>, data: Value) -> Self {
170 Self {
171 code,
172 message: message.into(),
173 data: Some(data),
174 }
175 }
176
177 pub fn parse_error(message: impl Into<String>) -> Self {
179 Self::new(error_codes::PARSE_ERROR, message)
180 }
181
182 pub fn invalid_request(message: impl Into<String>) -> Self {
184 Self::new(error_codes::INVALID_REQUEST, message)
185 }
186
187 pub fn method_not_found(method: &str) -> Self {
189 Self::new(
190 error_codes::METHOD_NOT_FOUND,
191 format!("Method not found: {}", method),
192 )
193 }
194
195 pub fn invalid_params(message: impl Into<String>) -> Self {
197 Self::new(error_codes::INVALID_PARAMS, message)
198 }
199
200 pub fn internal_error(message: impl Into<String>) -> Self {
202 Self::new(error_codes::INTERNAL_ERROR, message)
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use serde_json::json;
210
211 #[test]
212 fn test_parse_request() {
213 let json = r#"{
214 "jsonrpc": "2.0",
215 "id": 1,
216 "method": "tools/call",
217 "params": {
218 "name": "test_tool",
219 "arguments": {}
220 }
221 }"#;
222
223 let request: JsonRpcRequest = serde_json::from_str(json).unwrap();
224 assert_eq!(request.jsonrpc, "2.0");
225 assert_eq!(request.id, RequestId::Number(1));
226 assert_eq!(request.method, "tools/call");
227 assert!(request.params.is_some());
228 }
229
230 #[test]
231 fn test_success_response() {
232 let response = JsonRpcResponse::success(RequestId::Number(1), json!({"status": "ok"}));
233
234 assert_eq!(response.jsonrpc, "2.0");
235 assert_eq!(response.id, RequestId::Number(1));
236 assert!(response.result.is_some());
237 assert!(response.error.is_none());
238 }
239
240 #[test]
241 fn test_error_response() {
242 let error = JsonRpcError::method_not_found("test");
243 let response = JsonRpcResponse::error(RequestId::Number(1), error);
244
245 assert_eq!(response.jsonrpc, "2.0");
246 assert!(response.error.is_some());
247 assert!(response.result.is_none());
248 }
249
250 #[test]
251 fn test_content_block() {
252 let block = ContentBlock::text("Hello, world!");
253 let json = serde_json::to_value(&block).unwrap();
254
255 assert_eq!(json["type"], "text");
256 assert_eq!(json["text"], "Hello, world!");
257 }
258}