use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct JsonRpcRequest {
#[allow(dead_code)] pub jsonrpc: String,
pub id: Option<serde_json::Value>,
pub method: String,
#[serde(default)]
pub params: serde_json::Value,
}
#[derive(Debug, Serialize)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub id: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
#[derive(Debug, Serialize)]
pub struct JsonRpcError {
pub code: i32,
pub message: String,
}
#[derive(Debug, Serialize)]
pub struct ToolDefinition {
pub name: String,
pub description: String,
#[serde(rename = "inputSchema")]
pub input_schema: serde_json::Value,
}
impl JsonRpcResponse {
pub fn success(id: serde_json::Value, result: serde_json::Value) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id,
result: Some(result),
error: None,
}
}
pub fn error(id: serde_json::Value, code: i32, message: String) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id,
result: None,
error: Some(JsonRpcError { code, message }),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn request_round_trip() {
let json = r#"{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}"#;
let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.method, "tools/list");
assert_eq!(req.id, Some(serde_json::json!(1)));
}
#[test]
fn notification_has_no_id() {
let json = r#"{"jsonrpc":"2.0","method":"notifications/initialized"}"#;
let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
assert!(req.id.is_none());
}
#[test]
fn success_response_omits_error() {
let resp = JsonRpcResponse::success(serde_json::json!(1), serde_json::json!({"ok": true}));
let serialized = serde_json::to_string(&resp).unwrap();
assert!(!serialized.contains("error"));
assert!(serialized.contains("result"));
}
#[test]
fn error_response_omits_result() {
let resp =
JsonRpcResponse::error(serde_json::json!(1), -32601, "method not found".to_string());
let serialized = serde_json::to_string(&resp).unwrap();
assert!(!serialized.contains("result"));
assert!(serialized.contains("error"));
}
}