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 #[serde(default)]
16 pub id: Option<Value>,
17 pub method: String,
19 #[serde(default)]
21 pub params: Value,
22}
23
24impl JsonRpcRequest {
25 pub fn new(id: impl Into<Value>, method: impl Into<String>) -> Self {
27 Self {
28 jsonrpc: "2.0".to_string(),
29 id: Some(id.into()),
30 method: method.into(),
31 params: Value::Null,
32 }
33 }
34
35 pub fn with_params(id: impl Into<Value>, method: impl Into<String>, params: Value) -> Self {
37 Self {
38 jsonrpc: "2.0".to_string(),
39 id: Some(id.into()),
40 method: method.into(),
41 params,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct JsonRpcError {
49 pub code: i32,
51 pub message: String,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub data: Option<Value>,
56}
57
58impl JsonRpcError {
59 pub fn parse_error(detail: impl Into<String>) -> Self {
61 Self {
62 code: -32700,
63 message: "Parse error".to_string(),
64 data: Some(Value::String(detail.into())),
65 }
66 }
67
68 pub fn invalid_request(detail: impl Into<String>) -> Self {
70 Self {
71 code: -32600,
72 message: "Invalid Request".to_string(),
73 data: Some(Value::String(detail.into())),
74 }
75 }
76
77 pub fn method_not_found(method: impl Into<String>) -> Self {
79 Self {
80 code: -32601,
81 message: "Method not found".to_string(),
82 data: Some(Value::String(method.into())),
83 }
84 }
85
86 pub fn tool_not_found(tool: impl Into<String>) -> Self {
88 Self {
89 code: -32803,
90 message: "Tool not found".to_string(),
91 data: Some(Value::String(tool.into())),
92 }
93 }
94
95 pub fn invalid_params(detail: impl Into<String>) -> Self {
97 Self {
98 code: -32602,
99 message: "Invalid params".to_string(),
100 data: Some(Value::String(detail.into())),
101 }
102 }
103
104 pub fn internal_error(detail: impl Into<String>) -> Self {
106 Self {
107 code: -32603,
108 message: "Internal error".to_string(),
109 data: Some(Value::String(detail.into())),
110 }
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct JsonRpcResponse {
117 pub jsonrpc: String,
119 pub id: Value,
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub result: Option<Value>,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub error: Option<JsonRpcError>,
127}
128
129impl JsonRpcResponse {
130 pub fn success(id: Value, result: Value) -> Self {
132 Self {
133 jsonrpc: "2.0".to_string(),
134 id,
135 result: Some(result),
136 error: None,
137 }
138 }
139
140 pub fn error(id: Value, error: JsonRpcError) -> Self {
142 Self {
143 jsonrpc: "2.0".to_string(),
144 id,
145 result: None,
146 error: Some(error),
147 }
148 }
149
150 pub fn tool_error(id: Value, message: impl Into<String>) -> Self {
153 Self::success(
154 id,
155 serde_json::json!({
156 "content": [{"type": "text", "text": message.into()}],
157 "isError": true
158 }),
159 )
160 }
161
162 pub fn into_tool_error_if_needed(self) -> Self {
165 if let Some(ref err) = self.error {
166 match err.code {
170 -32700 | -32600 | -32601 | -32803 => self, _ => {
172 let msg = if let Some(ref data) = err.data {
174 format!("{}: {}", err.message, data)
175 } else {
176 err.message.clone()
177 };
178 Self::tool_error(self.id.clone(), msg)
179 }
180 }
181 } else {
182 self
183 }
184 }
185}
186
187#[allow(clippy::result_large_err)]
191pub fn parse_request(raw: &str) -> Result<JsonRpcRequest, JsonRpcResponse> {
192 let value: Value = serde_json::from_str(raw).map_err(|e| {
193 JsonRpcResponse::error(Value::Null, JsonRpcError::parse_error(e.to_string()))
194 })?;
195
196 let request: JsonRpcRequest = serde_json::from_value(value).map_err(|e| {
197 JsonRpcResponse::error(Value::Null, JsonRpcError::invalid_request(e.to_string()))
198 })?;
199
200 if request.jsonrpc != "2.0" {
201 return Err(JsonRpcResponse::error(
202 request.id.unwrap_or(Value::Null),
203 JsonRpcError::invalid_request("jsonrpc must be \"2.0\""),
204 ));
205 }
206
207 Ok(request)
208}