1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct JsonRpcRequest {
15 pub jsonrpc: String,
16 pub id: Option<serde_json::Value>,
17 pub method: String,
18 #[serde(default)]
19 pub params: serde_json::Value,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct JsonRpcResponse {
25 pub jsonrpc: String,
26 pub id: Option<serde_json::Value>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub result: Option<serde_json::Value>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub error: Option<JsonRpcError>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct JsonRpcError {
36 pub code: i64,
37 pub message: String,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub data: Option<serde_json::Value>,
40}
41
42impl JsonRpcResponse {
43 pub fn success(id: Option<serde_json::Value>, result: serde_json::Value) -> Self {
44 Self { jsonrpc: "2.0".to_string(), id, result: Some(result), error: None }
45 }
46
47 pub fn error(id: Option<serde_json::Value>, code: i64, message: impl Into<String>) -> Self {
48 Self {
49 jsonrpc: "2.0".to_string(),
50 id,
51 result: None,
52 error: Some(JsonRpcError { code, message: message.into(), data: None }),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct ServerCapabilities {
64 pub tools: ToolsCapability,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct ToolsCapability {
70 #[serde(rename = "listChanged")]
71 pub list_changed: bool,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct ToolDefinition {
77 pub name: String,
78 pub description: String,
79 #[serde(rename = "inputSchema")]
80 pub input_schema: InputSchema,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct InputSchema {
86 #[serde(rename = "type")]
87 pub schema_type: String,
88 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
89 pub properties: HashMap<String, PropertySchema>,
90 #[serde(default, skip_serializing_if = "Vec::is_empty")]
91 pub required: Vec<String>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct PropertySchema {
97 #[serde(rename = "type")]
98 pub prop_type: String,
99 pub description: String,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub r#enum: Option<Vec<String>>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct ToolCallResult {
107 pub content: Vec<ContentBlock>,
108 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
109 pub is_error: Option<bool>,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct ContentBlock {
115 #[serde(rename = "type")]
116 pub content_type: String,
117 pub text: String,
118}
119
120impl ContentBlock {
121 pub fn text(content: impl Into<String>) -> Self {
122 Self { content_type: "text".to_string(), text: content.into() }
123 }
124}
125
126impl ToolCallResult {
127 pub fn success(text: impl Into<String>) -> Self {
128 Self { content: vec![ContentBlock::text(text)], is_error: None }
129 }
130
131 pub fn error(text: impl Into<String>) -> Self {
132 Self { content: vec![ContentBlock::text(text)], is_error: Some(true) }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_json_rpc_response_success() {
142 let resp = JsonRpcResponse::success(Some(serde_json::json!(1)), serde_json::json!("ok"));
143 assert!(resp.result.is_some());
144 assert!(resp.error.is_none());
145 assert_eq!(resp.jsonrpc, "2.0");
146 }
147
148 #[test]
149 fn test_json_rpc_response_error() {
150 let resp = JsonRpcResponse::error(Some(serde_json::json!(1)), -32600, "Invalid Request");
151 assert!(resp.result.is_none());
152 assert!(resp.error.is_some());
153 assert_eq!(resp.error.as_ref().map(|e| e.code), Some(-32600));
154 }
155
156 #[test]
157 fn test_tool_call_result_success() {
158 let result = ToolCallResult::success("hello");
159 assert_eq!(result.content.len(), 1);
160 assert_eq!(result.content[0].text, "hello");
161 assert!(result.is_error.is_none());
162 }
163
164 #[test]
165 fn test_tool_call_result_error() {
166 let result = ToolCallResult::error("fail");
167 assert!(result.is_error == Some(true));
168 }
169
170 #[test]
171 fn test_content_block_text() {
172 let block = ContentBlock::text("test");
173 assert_eq!(block.content_type, "text");
174 assert_eq!(block.text, "test");
175 }
176
177 #[test]
178 fn test_json_rpc_request_deserialize() {
179 let json = r#"{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}"#;
180 let req: JsonRpcRequest = serde_json::from_str(json).expect("json deserialize failed");
181 assert_eq!(req.method, "tools/list");
182 assert_eq!(req.jsonrpc, "2.0");
183 }
184
185 #[test]
186 fn test_input_schema_serialization() {
187 let schema = InputSchema {
188 schema_type: "object".to_string(),
189 properties: HashMap::new(),
190 required: vec![],
191 };
192 let json = serde_json::to_string(&schema).expect("json serialize failed");
193 assert!(json.contains("\"type\":\"object\""));
194 }
195}