mcp_runner/transport/
json_rpc.rs1use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::fmt;
13
14pub const JSON_RPC_VERSION: &str = "2.0";
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(untagged)]
20pub enum JsonRpcMessage {
21 Request(JsonRpcRequest),
23 Response(JsonRpcResponse),
25 Notification(JsonRpcNotification),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct JsonRpcRequest {
32 pub jsonrpc: String,
34 pub id: Value,
36 pub method: String,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub params: Option<Value>,
41}
42
43impl JsonRpcRequest {
44 pub fn new(id: impl Into<Value>, method: impl Into<String>, params: Option<Value>) -> Self {
46 Self {
47 jsonrpc: JSON_RPC_VERSION.to_string(),
48 id: id.into(),
49 method: method.into(),
50 params,
51 }
52 }
53
54 pub fn list_tools(id: impl Into<Value>) -> Self {
56 Self::new(id, "tools/list", None)
57 }
58
59 pub fn call_tool(id: impl Into<Value>, name: impl Into<String>, args: Value) -> Self {
61 let params = serde_json::json!({
62 "name": name.into(),
63 "arguments": args
64 });
65 Self::new(id, "tools/call", Some(params))
66 }
67
68 pub fn list_resources(id: impl Into<Value>) -> Self {
70 Self::new(id, "resources/list", None)
71 }
72
73 pub fn get_resource(id: impl Into<Value>, uri: impl Into<String>) -> Self {
75 let params = serde_json::json!({
76 "uri": uri.into()
77 });
78 Self::new(id, "resources/get", Some(params))
79 }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct JsonRpcNotification {
85 pub jsonrpc: String,
87 pub method: String,
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub params: Option<Value>,
92}
93
94impl JsonRpcNotification {
95 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
97 Self {
98 jsonrpc: JSON_RPC_VERSION.to_string(),
99 method: method.into(),
100 params,
101 }
102 }
103
104 pub fn initialized() -> Self {
106 Self::new("notifications/initialized", None)
107 }
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct JsonRpcError {
113 pub code: i32,
115 pub message: String,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub data: Option<Value>,
120}
121
122impl fmt::Display for JsonRpcError {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "JSON-RPC error {}: {}", self.code, self.message)
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct JsonRpcResponse {
131 pub jsonrpc: String,
133 pub id: Value,
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub result: Option<Value>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub error: Option<JsonRpcError>,
141}
142
143impl JsonRpcResponse {
144 pub fn success(id: impl Into<Value>, result: Value) -> Self {
146 Self {
147 jsonrpc: JSON_RPC_VERSION.to_string(),
148 id: id.into(),
149 result: Some(result),
150 error: None,
151 }
152 }
153
154 pub fn error(
156 id: impl Into<Value>,
157 code: i32,
158 message: impl Into<String>,
159 data: Option<Value>,
160 ) -> Self {
161 Self {
162 jsonrpc: JSON_RPC_VERSION.to_string(),
163 id: id.into(),
164 result: None,
165 error: Some(JsonRpcError {
166 code,
167 message: message.into(),
168 data,
169 }),
170 }
171 }
172
173 pub fn is_success(&self) -> bool {
175 self.error.is_none() && self.result.is_some()
176 }
177}