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 invalid_params(detail: impl Into<String>) -> Self {
88 Self {
89 code: -32602,
90 message: "Invalid params".to_string(),
91 data: Some(Value::String(detail.into())),
92 }
93 }
94
95 pub fn internal_error(detail: impl Into<String>) -> Self {
97 Self {
98 code: -32603,
99 message: "Internal error".to_string(),
100 data: Some(Value::String(detail.into())),
101 }
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct JsonRpcResponse {
108 pub jsonrpc: String,
110 pub id: Value,
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub result: Option<Value>,
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub error: Option<JsonRpcError>,
118}
119
120impl JsonRpcResponse {
121 pub fn success(id: Value, result: Value) -> Self {
123 Self {
124 jsonrpc: "2.0".to_string(),
125 id,
126 result: Some(result),
127 error: None,
128 }
129 }
130
131 pub fn error(id: Value, error: JsonRpcError) -> Self {
133 Self {
134 jsonrpc: "2.0".to_string(),
135 id,
136 result: None,
137 error: Some(error),
138 }
139 }
140}
141
142#[allow(clippy::result_large_err)]
146pub fn parse_request(raw: &str) -> Result<JsonRpcRequest, JsonRpcResponse> {
147 let value: Value = serde_json::from_str(raw).map_err(|e| {
148 JsonRpcResponse::error(Value::Null, JsonRpcError::parse_error(e.to_string()))
149 })?;
150
151 let request: JsonRpcRequest = serde_json::from_value(value).map_err(|e| {
152 JsonRpcResponse::error(Value::Null, JsonRpcError::invalid_request(e.to_string()))
153 })?;
154
155 if request.jsonrpc != "2.0" {
156 return Err(JsonRpcResponse::error(
157 request.id.unwrap_or(Value::Null),
158 JsonRpcError::invalid_request("jsonrpc must be \"2.0\""),
159 ));
160 }
161
162 Ok(request)
163}