agentic_codebase/mcp/
protocol.rs1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct JsonRpcRequest {
12 pub jsonrpc: String,
14 pub id: Value,
16 pub method: String,
18 #[serde(default)]
20 pub params: Value,
21}
22
23impl JsonRpcRequest {
24 pub fn new(id: impl Into<Value>, method: impl Into<String>) -> Self {
26 Self {
27 jsonrpc: "2.0".to_string(),
28 id: id.into(),
29 method: method.into(),
30 params: Value::Null,
31 }
32 }
33
34 pub fn with_params(id: impl Into<Value>, method: impl Into<String>, params: Value) -> Self {
36 Self {
37 jsonrpc: "2.0".to_string(),
38 id: id.into(),
39 method: method.into(),
40 params,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct JsonRpcError {
48 pub code: i32,
50 pub message: String,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub data: Option<Value>,
55}
56
57impl JsonRpcError {
58 pub fn parse_error(detail: impl Into<String>) -> Self {
60 Self {
61 code: -32700,
62 message: "Parse error".to_string(),
63 data: Some(Value::String(detail.into())),
64 }
65 }
66
67 pub fn invalid_request(detail: impl Into<String>) -> Self {
69 Self {
70 code: -32600,
71 message: "Invalid Request".to_string(),
72 data: Some(Value::String(detail.into())),
73 }
74 }
75
76 pub fn method_not_found(method: impl Into<String>) -> Self {
78 Self {
79 code: -32601,
80 message: "Method not found".to_string(),
81 data: Some(Value::String(method.into())),
82 }
83 }
84
85 pub fn invalid_params(detail: impl Into<String>) -> Self {
87 Self {
88 code: -32602,
89 message: "Invalid params".to_string(),
90 data: Some(Value::String(detail.into())),
91 }
92 }
93
94 pub fn internal_error(detail: impl Into<String>) -> Self {
96 Self {
97 code: -32603,
98 message: "Internal error".to_string(),
99 data: Some(Value::String(detail.into())),
100 }
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct JsonRpcResponse {
107 pub jsonrpc: String,
109 pub id: Value,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub result: Option<Value>,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub error: Option<JsonRpcError>,
117}
118
119impl JsonRpcResponse {
120 pub fn success(id: Value, result: Value) -> Self {
122 Self {
123 jsonrpc: "2.0".to_string(),
124 id,
125 result: Some(result),
126 error: None,
127 }
128 }
129
130 pub fn error(id: Value, error: JsonRpcError) -> Self {
132 Self {
133 jsonrpc: "2.0".to_string(),
134 id,
135 result: None,
136 error: Some(error),
137 }
138 }
139}
140
141#[allow(clippy::result_large_err)]
145pub fn parse_request(raw: &str) -> Result<JsonRpcRequest, JsonRpcResponse> {
146 let value: Value = serde_json::from_str(raw).map_err(|e| {
147 JsonRpcResponse::error(Value::Null, JsonRpcError::parse_error(e.to_string()))
148 })?;
149
150 let request: JsonRpcRequest = serde_json::from_value(value).map_err(|e| {
151 JsonRpcResponse::error(Value::Null, JsonRpcError::invalid_request(e.to_string()))
152 })?;
153
154 if request.jsonrpc != "2.0" {
155 return Err(JsonRpcResponse::error(
156 request.id,
157 JsonRpcError::invalid_request("jsonrpc must be \"2.0\""),
158 ));
159 }
160
161 Ok(request)
162}