1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4pub const LATEST_PROTOCOL_VERSION: &str = "2024-11-05";
5pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2024-11-05"];
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(untagged)]
9pub enum Id {
10 Number(i64),
11 String(String),
12 Null,
13}
14
15impl Id {
16 pub fn to_string_key(&self) -> String {
17 match self {
18 Id::Number(n) => n.to_string(),
19 Id::String(s) => s.clone(),
20 Id::Null => "null".to_string(),
21 }
22 }
23
24 pub fn to_value(&self) -> Value {
25 match self {
26 Id::Number(n) => Value::Number((*n).into()),
27 Id::String(s) => Value::String(s.clone()),
28 Id::Null => Value::Null,
29 }
30 }
31}
32
33impl std::fmt::Display for Id {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Id::Number(n) => write!(f, "{}", n),
37 Id::String(s) => write!(f, "{}", s),
38 Id::Null => write!(f, "null"),
39 }
40 }
41}
42
43impl From<Id> for Value {
44 fn from(id: Id) -> Self {
45 id.to_value()
46 }
47}
48
49impl From<&Id> for Value {
50 fn from(id: &Id) -> Self {
51 id.to_value()
52 }
53}
54
55impl From<i64> for Id {
56 fn from(n: i64) -> Self {
57 Id::Number(n)
58 }
59}
60
61impl From<i32> for Id {
62 fn from(n: i32) -> Self {
63 Id::Number(n as i64)
64 }
65}
66
67impl From<u64> for Id {
68 fn from(n: u64) -> Self {
69 Id::Number(n as i64)
70 }
71}
72
73impl From<String> for Id {
74 fn from(s: String) -> Self {
75 Id::String(s)
76 }
77}
78
79impl From<&str> for Id {
80 fn from(s: &str) -> Self {
81 Id::String(s.to_string())
82 }
83}
84
85impl From<Value> for Id {
86 fn from(v: Value) -> Self {
87 match v {
88 Value::Number(n) => {
89 if let Some(i) = n.as_i64() {
90 Id::Number(i)
91 } else if let Some(u) = n.as_u64() {
92 Id::Number(u as i64)
93 } else {
94 Id::String(n.to_string())
95 }
96 }
97 Value::String(s) => Id::String(s),
98 _ => Id::Null,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct JsonRpcRequest {
105 pub jsonrpc: String,
106 #[serde(default)]
107 pub id: Option<Id>,
108 pub method: String,
109 #[serde(default)]
110 pub params: Option<Value>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct JsonRpcResponse {
115 pub jsonrpc: String,
116 pub id: Value,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub result: Option<Value>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub error: Option<JsonRpcError>,
121}
122
123impl JsonRpcResponse {
124 pub fn success(id: impl Into<Value>, result: Value) -> Self {
125 Self {
126 jsonrpc: "2.0".to_string(),
127 id: id.into(),
128 result: Some(result),
129 error: None,
130 }
131 }
132
133 pub fn error(id: impl Into<Value>, code: i32, message: String, data: Option<Value>) -> Self {
134 Self {
135 jsonrpc: "2.0".to_string(),
136 id: id.into(),
137 result: None,
138 error: Some(JsonRpcError {
139 code,
140 message,
141 data,
142 }),
143 }
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct JsonRpcError {
149 pub code: i32,
150 pub message: String,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub data: Option<Value>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156#[serde(rename_all = "camelCase")]
157pub struct Implementation {
158 pub name: String,
159 pub version: String,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, Default)]
163#[serde(rename_all = "camelCase")]
164pub struct CapabilityInfo {
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub list_changed: Option<bool>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize, Default)]
170#[serde(rename_all = "camelCase")]
171pub struct ServerCapabilities {
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub tools: Option<CapabilityInfo>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub resources: Option<CapabilityInfo>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub prompts: Option<CapabilityInfo>,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181#[serde(rename_all = "camelCase")]
182pub struct InitializeResult {
183 pub protocol_version: String,
184 pub capabilities: ServerCapabilities,
185 pub server_info: Implementation,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct ToolDefinition {
193 pub name: String,
194 pub description: String,
195 pub input_schema: Value,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct ListToolsResult {
201 pub tools: Vec<ToolDefinition>,
202}
203
204#[derive(Debug, Clone, Serialize, Deserialize)]
205#[serde(tag = "type", rename_all = "camelCase")]
206pub enum ContentItem {
207 #[serde(rename = "text")]
208 Text { text: String },
209 #[serde(rename = "image")]
210 Image { data: String, mime_type: String },
211 #[serde(rename = "resource")]
212 Resource { resource: ResourceContent },
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(rename_all = "camelCase")]
217pub struct CallToolResult {
218 pub content: Vec<ContentItem>,
219 pub is_error: bool,
220}
221
222impl CallToolResult {
223 pub fn text(text: impl Into<String>) -> Self {
224 Self {
225 content: vec![ContentItem::Text { text: text.into() }],
226 is_error: false,
227 }
228 }
229
230 pub fn error(message: impl Into<String>) -> Self {
231 Self {
232 content: vec![ContentItem::Text {
233 text: message.into(),
234 }],
235 is_error: true,
236 }
237 }
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
243#[serde(rename_all = "camelCase")]
244pub struct ResourceDefinition {
245 pub uri: String,
246 pub name: String,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub description: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub mime_type: Option<String>,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254#[serde(rename_all = "camelCase")]
255pub struct ListResourcesResult {
256 pub resources: Vec<ResourceDefinition>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
260#[serde(rename_all = "camelCase")]
261pub struct ResourceContent {
262 pub uri: String,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub mime_type: Option<String>,
265 pub text: String,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269#[serde(rename_all = "camelCase")]
270pub struct ReadResourceResult {
271 pub contents: Vec<ResourceContent>,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct PromptArgument {
279 pub name: String,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub description: Option<String>,
282 pub required: bool,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub struct PromptDefinition {
288 pub name: String,
289 pub description: String,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub arguments: Option<Vec<PromptArgument>>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295#[serde(rename_all = "camelCase")]
296pub struct ListPromptsResult {
297 pub prompts: Vec<PromptDefinition>,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
301#[serde(rename_all = "camelCase")]
302pub struct PromptMessage {
303 pub role: String,
304 pub content: ContentItem,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308#[serde(rename_all = "camelCase")]
309pub struct GetPromptResult {
310 pub description: Option<String>,
311 pub messages: Vec<PromptMessage>,
312}