1use collections::HashMap;
2use serde::{Deserialize, Serialize};
3use url::Url;
4
5pub const LATEST_PROTOCOL_VERSION: &str = "2024-11-05";
6
7pub enum RequestType {
8 Initialize,
9 CallTool,
10 ResourcesUnsubscribe,
11 ResourcesSubscribe,
12 ResourcesRead,
13 ResourcesList,
14 LoggingSetLevel,
15 PromptsGet,
16 PromptsList,
17 CompletionComplete,
18 Ping,
19 ListTools,
20 ListResourceTemplates,
21 ListRoots,
22}
23
24impl RequestType {
25 pub fn as_str(&self) -> &'static str {
26 match self {
27 RequestType::Initialize => "initialize",
28 RequestType::CallTool => "tools/call",
29 RequestType::ResourcesUnsubscribe => "resources/unsubscribe",
30 RequestType::ResourcesSubscribe => "resources/subscribe",
31 RequestType::ResourcesRead => "resources/read",
32 RequestType::ResourcesList => "resources/list",
33 RequestType::LoggingSetLevel => "logging/setLevel",
34 RequestType::PromptsGet => "prompts/get",
35 RequestType::PromptsList => "prompts/list",
36 RequestType::CompletionComplete => "completion/complete",
37 RequestType::Ping => "ping",
38 RequestType::ListTools => "tools/list",
39 RequestType::ListResourceTemplates => "resources/templates/list",
40 RequestType::ListRoots => "roots/list",
41 }
42 }
43}
44
45#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(transparent)]
47pub struct ProtocolVersion(pub String);
48
49#[derive(Debug, Serialize)]
50#[serde(rename_all = "camelCase")]
51pub struct InitializeParams {
52 pub protocol_version: ProtocolVersion,
53 pub capabilities: ClientCapabilities,
54 pub client_info: Implementation,
55 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
56 pub meta: Option<HashMap<String, serde_json::Value>>,
57}
58
59#[derive(Debug, Serialize)]
60#[serde(rename_all = "camelCase")]
61pub struct CallToolParams {
62 pub name: String,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub arguments: Option<HashMap<String, serde_json::Value>>,
65 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
66 pub meta: Option<HashMap<String, serde_json::Value>>,
67}
68
69#[derive(Debug, Serialize)]
70#[serde(rename_all = "camelCase")]
71pub struct ResourcesUnsubscribeParams {
72 pub uri: Url,
73 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
74 pub meta: Option<HashMap<String, serde_json::Value>>,
75}
76
77#[derive(Debug, Serialize)]
78#[serde(rename_all = "camelCase")]
79pub struct ResourcesSubscribeParams {
80 pub uri: Url,
81 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
82 pub meta: Option<HashMap<String, serde_json::Value>>,
83}
84
85#[derive(Debug, Serialize)]
86#[serde(rename_all = "camelCase")]
87pub struct ResourcesReadParams {
88 pub uri: Url,
89 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
90 pub meta: Option<HashMap<String, serde_json::Value>>,
91}
92
93#[derive(Debug, Serialize)]
94#[serde(rename_all = "camelCase")]
95pub struct LoggingSetLevelParams {
96 pub level: LoggingLevel,
97 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
98 pub meta: Option<HashMap<String, serde_json::Value>>,
99}
100
101#[derive(Debug, Serialize)]
102#[serde(rename_all = "camelCase")]
103pub struct PromptsGetParams {
104 pub name: String,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub arguments: Option<HashMap<String, String>>,
107 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
108 pub meta: Option<HashMap<String, serde_json::Value>>,
109}
110
111#[derive(Debug, Serialize)]
112#[serde(rename_all = "camelCase")]
113pub struct CompletionCompleteParams {
114 pub r#ref: CompletionReference,
115 pub argument: CompletionArgument,
116 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
117 pub meta: Option<HashMap<String, serde_json::Value>>,
118}
119
120#[derive(Debug, Serialize)]
121#[serde(untagged)]
122pub enum CompletionReference {
123 Prompt(PromptReference),
124 Resource(ResourceReference),
125}
126
127#[derive(Debug, Serialize)]
128#[serde(rename_all = "camelCase")]
129pub struct PromptReference {
130 pub r#type: PromptReferenceType,
131 pub name: String,
132}
133
134#[derive(Debug, Serialize)]
135#[serde(rename_all = "camelCase")]
136pub struct ResourceReference {
137 pub r#type: PromptReferenceType,
138 pub uri: Url,
139}
140
141#[derive(Debug, Serialize)]
142#[serde(rename_all = "snake_case")]
143pub enum PromptReferenceType {
144 #[serde(rename = "ref/prompt")]
145 Prompt,
146 #[serde(rename = "ref/resource")]
147 Resource,
148}
149
150#[derive(Debug, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct CompletionArgument {
153 pub name: String,
154 pub value: String,
155}
156
157#[derive(Debug, Deserialize)]
158#[serde(rename_all = "camelCase")]
159pub struct InitializeResponse {
160 pub protocol_version: ProtocolVersion,
161 pub capabilities: ServerCapabilities,
162 pub server_info: Implementation,
163 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
164 pub meta: Option<HashMap<String, serde_json::Value>>,
165}
166
167#[derive(Debug, Deserialize)]
168#[serde(rename_all = "camelCase")]
169pub struct ResourcesReadResponse {
170 pub contents: Vec<ResourceContents>,
171 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
172 pub meta: Option<HashMap<String, serde_json::Value>>,
173}
174
175#[derive(Debug, Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub struct ResourcesListResponse {
178 pub resources: Vec<Resource>,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub next_cursor: Option<String>,
181 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
182 pub meta: Option<HashMap<String, serde_json::Value>>,
183}
184#[derive(Debug, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct SamplingMessage {
187 pub role: Role,
188 pub content: MessageContent,
189}
190
191#[derive(Debug, Serialize, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct PromptMessage {
194 pub role: Role,
195 pub content: MessageContent,
196}
197
198#[derive(Debug, Serialize, Deserialize)]
199#[serde(rename_all = "lowercase")]
200pub enum Role {
201 User,
202 Assistant,
203}
204
205#[derive(Debug, Serialize, Deserialize)]
206#[serde(tag = "type")]
207pub enum MessageContent {
208 #[serde(rename = "text")]
209 Text { text: String },
210 #[serde(rename = "image")]
211 Image { data: String, mime_type: String },
212 #[serde(rename = "resource")]
213 Resource { resource: ResourceContents },
214}
215
216#[derive(Debug, Deserialize)]
217#[serde(rename_all = "camelCase")]
218pub struct PromptsGetResponse {
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub description: Option<String>,
221 pub messages: Vec<PromptMessage>,
222 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
223 pub meta: Option<HashMap<String, serde_json::Value>>,
224}
225
226#[derive(Debug, Deserialize)]
227#[serde(rename_all = "camelCase")]
228pub struct PromptsListResponse {
229 pub prompts: Vec<Prompt>,
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub next_cursor: Option<String>,
232 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
233 pub meta: Option<HashMap<String, serde_json::Value>>,
234}
235
236#[derive(Debug, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct CompletionCompleteResponse {
239 pub completion: CompletionResult,
240 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
241 pub meta: Option<HashMap<String, serde_json::Value>>,
242}
243
244#[derive(Debug, Deserialize)]
245#[serde(rename_all = "camelCase")]
246pub struct CompletionResult {
247 pub values: Vec<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub total: Option<u32>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub has_more: Option<bool>,
252 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
253 pub meta: Option<HashMap<String, serde_json::Value>>,
254}
255
256#[derive(Debug, Deserialize, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub struct Prompt {
259 pub name: String,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub description: Option<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub arguments: Option<Vec<PromptArgument>>,
264}
265
266#[derive(Debug, Deserialize, Serialize)]
267#[serde(rename_all = "camelCase")]
268pub struct PromptArgument {
269 pub name: String,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub description: Option<String>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub required: Option<bool>,
274}
275
276#[derive(Debug, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct ClientCapabilities {
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub experimental: Option<HashMap<String, serde_json::Value>>,
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub sampling: Option<serde_json::Value>,
283 #[serde(skip_serializing_if = "Option::is_none")]
284 pub roots: Option<RootsCapabilities>,
285}
286
287#[derive(Debug, Serialize, Deserialize)]
288#[serde(rename_all = "camelCase")]
289pub struct ServerCapabilities {
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub experimental: Option<HashMap<String, serde_json::Value>>,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub logging: Option<serde_json::Value>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub prompts: Option<PromptsCapabilities>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub resources: Option<ResourcesCapabilities>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub tools: Option<ToolsCapabilities>,
300}
301
302#[derive(Debug, Serialize, Deserialize)]
303#[serde(rename_all = "camelCase")]
304pub struct PromptsCapabilities {
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub list_changed: Option<bool>,
307}
308
309#[derive(Debug, Serialize, Deserialize)]
310#[serde(rename_all = "camelCase")]
311pub struct ResourcesCapabilities {
312 #[serde(skip_serializing_if = "Option::is_none")]
313 pub subscribe: Option<bool>,
314 #[serde(skip_serializing_if = "Option::is_none")]
315 pub list_changed: Option<bool>,
316}
317
318#[derive(Debug, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320pub struct ToolsCapabilities {
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub list_changed: Option<bool>,
323}
324
325#[derive(Debug, Serialize, Deserialize)]
326#[serde(rename_all = "camelCase")]
327pub struct RootsCapabilities {
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub list_changed: Option<bool>,
330}
331
332#[derive(Debug, Serialize, Deserialize)]
333#[serde(rename_all = "camelCase")]
334pub struct Tool {
335 pub name: String,
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub description: Option<String>,
338 pub input_schema: serde_json::Value,
339}
340
341#[derive(Debug, Serialize, Deserialize)]
342#[serde(rename_all = "camelCase")]
343pub struct Implementation {
344 pub name: String,
345 pub version: String,
346}
347
348#[derive(Debug, Serialize, Deserialize)]
349#[serde(rename_all = "camelCase")]
350pub struct Resource {
351 pub uri: Url,
352 pub name: String,
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub description: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 pub mime_type: Option<String>,
357}
358
359#[derive(Debug, Serialize, Deserialize)]
360#[serde(rename_all = "camelCase")]
361pub struct ResourceContents {
362 pub uri: Url,
363 #[serde(skip_serializing_if = "Option::is_none")]
364 pub mime_type: Option<String>,
365}
366
367#[derive(Debug, Serialize, Deserialize)]
368#[serde(rename_all = "camelCase")]
369pub struct TextResourceContents {
370 pub uri: Url,
371 #[serde(skip_serializing_if = "Option::is_none")]
372 pub mime_type: Option<String>,
373 pub text: String,
374}
375
376#[derive(Debug, Serialize, Deserialize)]
377#[serde(rename_all = "camelCase")]
378pub struct BlobResourceContents {
379 pub uri: Url,
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub mime_type: Option<String>,
382 pub blob: String,
383}
384
385#[derive(Debug, Serialize, Deserialize)]
386#[serde(rename_all = "camelCase")]
387pub struct ResourceTemplate {
388 pub uri_template: String,
389 pub name: String,
390 #[serde(skip_serializing_if = "Option::is_none")]
391 pub description: Option<String>,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub mime_type: Option<String>,
394}
395
396#[derive(Debug, Serialize, Deserialize)]
397#[serde(rename_all = "lowercase")]
398pub enum LoggingLevel {
399 Debug,
400 Info,
401 Notice,
402 Warning,
403 Error,
404 Critical,
405 Alert,
406 Emergency,
407}
408
409#[derive(Debug, Serialize, Deserialize)]
410#[serde(rename_all = "camelCase")]
411pub struct ModelPreferences {
412 #[serde(skip_serializing_if = "Option::is_none")]
413 pub hints: Option<Vec<ModelHint>>,
414 #[serde(skip_serializing_if = "Option::is_none")]
415 pub cost_priority: Option<f64>,
416 #[serde(skip_serializing_if = "Option::is_none")]
417 pub speed_priority: Option<f64>,
418 #[serde(skip_serializing_if = "Option::is_none")]
419 pub intelligence_priority: Option<f64>,
420}
421
422#[derive(Debug, Serialize, Deserialize)]
423#[serde(rename_all = "camelCase")]
424pub struct ModelHint {
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub name: Option<String>,
427}
428
429#[derive(Debug, Serialize)]
430#[serde(rename_all = "camelCase")]
431pub enum NotificationType {
432 Initialized,
433 Progress,
434 Message,
435 ResourcesUpdated,
436 ResourcesListChanged,
437 ToolsListChanged,
438 PromptsListChanged,
439 RootsListChanged,
440}
441
442impl NotificationType {
443 pub fn as_str(&self) -> &'static str {
444 match self {
445 NotificationType::Initialized => "notifications/initialized",
446 NotificationType::Progress => "notifications/progress",
447 NotificationType::Message => "notifications/message",
448 NotificationType::ResourcesUpdated => "notifications/resources/updated",
449 NotificationType::ResourcesListChanged => "notifications/resources/list_changed",
450 NotificationType::ToolsListChanged => "notifications/tools/list_changed",
451 NotificationType::PromptsListChanged => "notifications/prompts/list_changed",
452 NotificationType::RootsListChanged => "notifications/roots/list_changed",
453 }
454 }
455}
456
457#[derive(Debug, Serialize)]
458#[serde(untagged)]
459pub enum ClientNotification {
460 Initialized,
461 Progress(ProgressParams),
462 RootsListChanged,
463}
464
465#[derive(Debug, Serialize, Deserialize)]
466#[serde(untagged)]
467pub enum ProgressToken {
468 String(String),
469 Number(f64),
470}
471
472#[derive(Debug, Serialize)]
473#[serde(rename_all = "camelCase")]
474pub struct ProgressParams {
475 pub progress_token: ProgressToken,
476 pub progress: f64,
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub total: Option<f64>,
479 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
480 pub meta: Option<HashMap<String, serde_json::Value>>,
481}
482
483pub enum CompletionTotal {
484 Exact(u32),
485 HasMore,
486 Unknown,
487}
488
489impl CompletionTotal {
490 pub fn from_options(has_more: Option<bool>, total: Option<u32>) -> Self {
491 match (has_more, total) {
492 (_, Some(count)) => CompletionTotal::Exact(count),
493 (Some(true), _) => CompletionTotal::HasMore,
494 _ => CompletionTotal::Unknown,
495 }
496 }
497}
498
499pub struct Completion {
500 pub values: Vec<String>,
501 pub total: CompletionTotal,
502}
503
504#[derive(Debug, Deserialize)]
505#[serde(rename_all = "camelCase")]
506pub struct CallToolResponse {
507 pub content: Vec<ToolResponseContent>,
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub is_error: Option<bool>,
510 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
511 pub meta: Option<HashMap<String, serde_json::Value>>,
512}
513
514#[derive(Debug, Serialize, Deserialize)]
515#[serde(tag = "type")]
516pub enum ToolResponseContent {
517 #[serde(rename = "text")]
518 Text { text: String },
519 #[serde(rename = "image")]
520 Image { data: String, mime_type: String },
521 #[serde(rename = "resource")]
522 Resource { resource: ResourceContents },
523}
524
525#[derive(Debug, Deserialize)]
526#[serde(rename_all = "camelCase")]
527pub struct ListToolsResponse {
528 pub tools: Vec<Tool>,
529 #[serde(skip_serializing_if = "Option::is_none")]
530 pub next_cursor: Option<String>,
531 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
532 pub meta: Option<HashMap<String, serde_json::Value>>,
533}
534
535#[derive(Debug, Deserialize)]
536#[serde(rename_all = "camelCase")]
537pub struct ListRootsResponse {
538 pub roots: Vec<Root>,
539 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
540 pub meta: Option<HashMap<String, serde_json::Value>>,
541}
542
543#[derive(Debug, Serialize, Deserialize)]
544#[serde(rename_all = "camelCase")]
545pub struct Root {
546 pub uri: Url,
547 #[serde(skip_serializing_if = "Option::is_none")]
548 pub name: Option<String>,
549}