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
45impl TryFrom<&str> for RequestType {
46 type Error = ();
47
48 fn try_from(s: &str) -> Result<Self, Self::Error> {
49 match s {
50 "initialize" => Ok(RequestType::Initialize),
51 "tools/call" => Ok(RequestType::CallTool),
52 "resources/unsubscribe" => Ok(RequestType::ResourcesUnsubscribe),
53 "resources/subscribe" => Ok(RequestType::ResourcesSubscribe),
54 "resources/read" => Ok(RequestType::ResourcesRead),
55 "resources/list" => Ok(RequestType::ResourcesList),
56 "logging/setLevel" => Ok(RequestType::LoggingSetLevel),
57 "prompts/get" => Ok(RequestType::PromptsGet),
58 "prompts/list" => Ok(RequestType::PromptsList),
59 "completion/complete" => Ok(RequestType::CompletionComplete),
60 "ping" => Ok(RequestType::Ping),
61 "tools/list" => Ok(RequestType::ListTools),
62 "resources/templates/list" => Ok(RequestType::ListResourceTemplates),
63 "roots/list" => Ok(RequestType::ListRoots),
64 _ => Err(()),
65 }
66 }
67}
68
69#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(transparent)]
71pub struct ProtocolVersion(pub String);
72
73#[derive(Debug, Serialize)]
74#[serde(rename_all = "camelCase")]
75pub struct InitializeParams {
76 pub protocol_version: ProtocolVersion,
77 pub capabilities: ClientCapabilities,
78 pub client_info: Implementation,
79 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
80 pub meta: Option<HashMap<String, serde_json::Value>>,
81}
82
83#[derive(Debug, Serialize)]
84#[serde(rename_all = "camelCase")]
85pub struct CallToolParams {
86 pub name: String,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub arguments: Option<HashMap<String, serde_json::Value>>,
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 ResourcesUnsubscribeParams {
96 pub uri: Url,
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 ResourcesSubscribeParams {
104 pub uri: Url,
105 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
106 pub meta: Option<HashMap<String, serde_json::Value>>,
107}
108
109#[derive(Debug, Serialize)]
110#[serde(rename_all = "camelCase")]
111pub struct ResourcesReadParams {
112 pub uri: Url,
113 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
114 pub meta: Option<HashMap<String, serde_json::Value>>,
115}
116
117#[derive(Debug, Serialize)]
118#[serde(rename_all = "camelCase")]
119pub struct LoggingSetLevelParams {
120 pub level: LoggingLevel,
121 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
122 pub meta: Option<HashMap<String, serde_json::Value>>,
123}
124
125#[derive(Debug, Serialize)]
126#[serde(rename_all = "camelCase")]
127pub struct PromptsGetParams {
128 pub name: String,
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub arguments: Option<HashMap<String, String>>,
131 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
132 pub meta: Option<HashMap<String, serde_json::Value>>,
133}
134
135#[derive(Debug, Serialize)]
136#[serde(rename_all = "camelCase")]
137pub struct CompletionCompleteParams {
138 pub r#ref: CompletionReference,
139 pub argument: CompletionArgument,
140 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
141 pub meta: Option<HashMap<String, serde_json::Value>>,
142}
143
144#[derive(Debug, Serialize)]
145#[serde(untagged)]
146pub enum CompletionReference {
147 Prompt(PromptReference),
148 Resource(ResourceReference),
149}
150
151#[derive(Debug, Serialize)]
152#[serde(rename_all = "camelCase")]
153pub struct PromptReference {
154 pub r#type: PromptReferenceType,
155 pub name: String,
156}
157
158#[derive(Debug, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct ResourceReference {
161 pub r#type: PromptReferenceType,
162 pub uri: Url,
163}
164
165#[derive(Debug, Serialize)]
166#[serde(rename_all = "snake_case")]
167pub enum PromptReferenceType {
168 #[serde(rename = "ref/prompt")]
169 Prompt,
170 #[serde(rename = "ref/resource")]
171 Resource,
172}
173
174#[derive(Debug, Serialize)]
175#[serde(rename_all = "camelCase")]
176pub struct CompletionArgument {
177 pub name: String,
178 pub value: String,
179}
180
181#[derive(Debug, Serialize, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct InitializeResponse {
184 pub protocol_version: ProtocolVersion,
185 pub capabilities: ServerCapabilities,
186 pub server_info: Implementation,
187 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
188 pub meta: Option<HashMap<String, serde_json::Value>>,
189}
190
191#[derive(Debug, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct ResourcesReadResponse {
194 pub contents: Vec<ResourceContentsType>,
195 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
196 pub meta: Option<HashMap<String, serde_json::Value>>,
197}
198
199#[derive(Debug, Deserialize)]
200#[serde(untagged)]
201pub enum ResourceContentsType {
202 Text(TextResourceContents),
203 Blob(BlobResourceContents),
204}
205
206#[derive(Debug, Deserialize)]
207#[serde(rename_all = "camelCase")]
208pub struct ResourcesListResponse {
209 pub resources: Vec<Resource>,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub next_cursor: Option<String>,
212 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
213 pub meta: Option<HashMap<String, serde_json::Value>>,
214}
215
216#[derive(Debug, Serialize, Deserialize)]
217#[serde(rename_all = "camelCase")]
218pub struct SamplingMessage {
219 pub role: Role,
220 pub content: MessageContent,
221}
222
223#[derive(Debug, Serialize)]
224#[serde(rename_all = "camelCase")]
225pub struct CreateMessageRequest {
226 pub messages: Vec<SamplingMessage>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub model_preferences: Option<ModelPreferences>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub system_prompt: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub include_context: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub temperature: Option<f64>,
235 pub max_tokens: u32,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub stop_sequences: Option<Vec<String>>,
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub metadata: Option<serde_json::Value>,
240}
241
242#[derive(Debug, Deserialize)]
243#[serde(rename_all = "camelCase")]
244pub struct CreateMessageResult {
245 pub role: Role,
246 pub content: MessageContent,
247 pub model: String,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub stop_reason: Option<String>,
250}
251
252#[derive(Debug, Serialize, Deserialize)]
253#[serde(rename_all = "camelCase")]
254pub struct PromptMessage {
255 pub role: Role,
256 pub content: MessageContent,
257}
258
259#[derive(Debug, Serialize, Deserialize)]
260#[serde(rename_all = "lowercase")]
261pub enum Role {
262 User,
263 Assistant,
264}
265
266#[derive(Debug, Serialize, Deserialize)]
267#[serde(tag = "type")]
268pub enum MessageContent {
269 #[serde(rename = "text")]
270 Text {
271 text: String,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 annotations: Option<MessageAnnotations>,
274 },
275 #[serde(rename = "image")]
276 Image {
277 data: String,
278 mime_type: String,
279 #[serde(skip_serializing_if = "Option::is_none")]
280 annotations: Option<MessageAnnotations>,
281 },
282 #[serde(rename = "resource")]
283 Resource {
284 resource: ResourceContents,
285 #[serde(skip_serializing_if = "Option::is_none")]
286 annotations: Option<MessageAnnotations>,
287 },
288}
289
290#[derive(Debug, Serialize, Deserialize)]
291#[serde(rename_all = "camelCase")]
292pub struct MessageAnnotations {
293 #[serde(skip_serializing_if = "Option::is_none")]
294 pub audience: Option<Vec<Role>>,
295 #[serde(skip_serializing_if = "Option::is_none")]
296 pub priority: Option<f64>,
297}
298
299#[derive(Debug, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct PromptsGetResponse {
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub description: Option<String>,
304 pub messages: Vec<PromptMessage>,
305 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
306 pub meta: Option<HashMap<String, serde_json::Value>>,
307}
308
309#[derive(Debug, Deserialize)]
310#[serde(rename_all = "camelCase")]
311pub struct PromptsListResponse {
312 pub prompts: Vec<Prompt>,
313 #[serde(skip_serializing_if = "Option::is_none")]
314 pub next_cursor: Option<String>,
315 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
316 pub meta: Option<HashMap<String, serde_json::Value>>,
317}
318
319#[derive(Debug, Deserialize)]
320#[serde(rename_all = "camelCase")]
321pub struct CompletionCompleteResponse {
322 pub completion: CompletionResult,
323 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
324 pub meta: Option<HashMap<String, serde_json::Value>>,
325}
326
327#[derive(Debug, Deserialize)]
328#[serde(rename_all = "camelCase")]
329pub struct CompletionResult {
330 pub values: Vec<String>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub total: Option<u32>,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub has_more: Option<bool>,
335 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
336 pub meta: Option<HashMap<String, serde_json::Value>>,
337}
338
339#[derive(Debug, Deserialize, Serialize)]
340#[serde(rename_all = "camelCase")]
341pub struct Prompt {
342 pub name: String,
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub description: Option<String>,
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub arguments: Option<Vec<PromptArgument>>,
347}
348
349#[derive(Debug, Deserialize, Serialize)]
350#[serde(rename_all = "camelCase")]
351pub struct PromptArgument {
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 required: Option<bool>,
357}
358
359#[derive(Debug, Serialize, Deserialize)]
360#[serde(rename_all = "camelCase")]
361pub struct ClientCapabilities {
362 #[serde(skip_serializing_if = "Option::is_none")]
363 pub experimental: Option<HashMap<String, serde_json::Value>>,
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub sampling: Option<serde_json::Value>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub roots: Option<RootsCapabilities>,
368}
369
370#[derive(Default, Debug, Serialize, Deserialize)]
371#[serde(rename_all = "camelCase")]
372pub struct ServerCapabilities {
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub experimental: Option<HashMap<String, serde_json::Value>>,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub logging: Option<serde_json::Value>,
377 #[serde(skip_serializing_if = "Option::is_none")]
378 pub prompts: Option<PromptsCapabilities>,
379 #[serde(skip_serializing_if = "Option::is_none")]
380 pub resources: Option<ResourcesCapabilities>,
381 #[serde(skip_serializing_if = "Option::is_none")]
382 pub tools: Option<ToolsCapabilities>,
383}
384
385#[derive(Debug, Serialize, Deserialize)]
386#[serde(rename_all = "camelCase")]
387pub struct PromptsCapabilities {
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub list_changed: Option<bool>,
390}
391
392#[derive(Debug, Serialize, Deserialize)]
393#[serde(rename_all = "camelCase")]
394pub struct ResourcesCapabilities {
395 #[serde(skip_serializing_if = "Option::is_none")]
396 pub subscribe: Option<bool>,
397 #[serde(skip_serializing_if = "Option::is_none")]
398 pub list_changed: Option<bool>,
399}
400
401#[derive(Debug, Serialize, Deserialize)]
402#[serde(rename_all = "camelCase")]
403pub struct ToolsCapabilities {
404 #[serde(skip_serializing_if = "Option::is_none")]
405 pub list_changed: Option<bool>,
406}
407
408#[derive(Debug, Serialize, Deserialize)]
409#[serde(rename_all = "camelCase")]
410pub struct RootsCapabilities {
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub list_changed: Option<bool>,
413}
414
415#[derive(Debug, Serialize, Deserialize)]
416#[serde(rename_all = "camelCase")]
417pub struct Tool {
418 pub name: String,
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub description: Option<String>,
421 pub input_schema: serde_json::Value,
422}
423
424#[derive(Debug, Serialize, Deserialize)]
425#[serde(rename_all = "camelCase")]
426pub struct Implementation {
427 pub name: String,
428 pub version: String,
429}
430
431#[derive(Debug, Serialize, Deserialize)]
432#[serde(rename_all = "camelCase")]
433pub struct Resource {
434 pub uri: Url,
435 pub name: String,
436 #[serde(skip_serializing_if = "Option::is_none")]
437 pub description: Option<String>,
438 #[serde(skip_serializing_if = "Option::is_none")]
439 pub mime_type: Option<String>,
440}
441
442#[derive(Debug, Serialize, Deserialize)]
443#[serde(rename_all = "camelCase")]
444pub struct ResourceContents {
445 pub uri: Url,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 pub mime_type: Option<String>,
448}
449
450#[derive(Debug, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct TextResourceContents {
453 pub uri: Url,
454 #[serde(skip_serializing_if = "Option::is_none")]
455 pub mime_type: Option<String>,
456 pub text: String,
457}
458
459#[derive(Debug, Serialize, Deserialize)]
460#[serde(rename_all = "camelCase")]
461pub struct BlobResourceContents {
462 pub uri: Url,
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub mime_type: Option<String>,
465 pub blob: String,
466}
467
468#[derive(Debug, Serialize, Deserialize)]
469#[serde(rename_all = "camelCase")]
470pub struct ResourceTemplate {
471 pub uri_template: String,
472 pub name: String,
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub description: Option<String>,
475 #[serde(skip_serializing_if = "Option::is_none")]
476 pub mime_type: Option<String>,
477}
478
479#[derive(Debug, Serialize, Deserialize)]
480#[serde(rename_all = "lowercase")]
481pub enum LoggingLevel {
482 Debug,
483 Info,
484 Notice,
485 Warning,
486 Error,
487 Critical,
488 Alert,
489 Emergency,
490}
491
492#[derive(Debug, Serialize, Deserialize)]
493#[serde(rename_all = "camelCase")]
494pub struct ModelPreferences {
495 #[serde(skip_serializing_if = "Option::is_none")]
496 pub hints: Option<Vec<ModelHint>>,
497 #[serde(skip_serializing_if = "Option::is_none")]
498 pub cost_priority: Option<f64>,
499 #[serde(skip_serializing_if = "Option::is_none")]
500 pub speed_priority: Option<f64>,
501 #[serde(skip_serializing_if = "Option::is_none")]
502 pub intelligence_priority: Option<f64>,
503}
504
505#[derive(Debug, Serialize, Deserialize)]
506#[serde(rename_all = "camelCase")]
507pub struct ModelHint {
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub name: Option<String>,
510}
511
512#[derive(Debug, Serialize)]
513#[serde(rename_all = "camelCase")]
514pub enum NotificationType {
515 Initialized,
516 Progress,
517 Message,
518 ResourcesUpdated,
519 ResourcesListChanged,
520 ToolsListChanged,
521 PromptsListChanged,
522 RootsListChanged,
523}
524
525impl NotificationType {
526 pub fn as_str(&self) -> &'static str {
527 match self {
528 NotificationType::Initialized => "notifications/initialized",
529 NotificationType::Progress => "notifications/progress",
530 NotificationType::Message => "notifications/message",
531 NotificationType::ResourcesUpdated => "notifications/resources/updated",
532 NotificationType::ResourcesListChanged => "notifications/resources/list_changed",
533 NotificationType::ToolsListChanged => "notifications/tools/list_changed",
534 NotificationType::PromptsListChanged => "notifications/prompts/list_changed",
535 NotificationType::RootsListChanged => "notifications/roots/list_changed",
536 }
537 }
538}
539
540#[derive(Debug, Serialize)]
541#[serde(untagged)]
542pub enum ClientNotification {
543 Initialized,
544 Progress(ProgressParams),
545 RootsListChanged,
546 Cancelled {
547 request_id: String,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 reason: Option<String>,
550 },
551}
552
553#[derive(Debug, Serialize, Deserialize)]
554#[serde(untagged)]
555pub enum ProgressToken {
556 String(String),
557 Number(f64),
558}
559
560#[derive(Debug, Serialize)]
561#[serde(rename_all = "camelCase")]
562pub struct ProgressParams {
563 pub progress_token: ProgressToken,
564 pub progress: f64,
565 #[serde(skip_serializing_if = "Option::is_none")]
566 pub total: Option<f64>,
567 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
568 pub meta: Option<HashMap<String, serde_json::Value>>,
569}
570
571pub enum CompletionTotal {
572 Exact(u32),
573 HasMore,
574 Unknown,
575}
576
577impl CompletionTotal {
578 pub fn from_options(has_more: Option<bool>, total: Option<u32>) -> Self {
579 match (has_more, total) {
580 (_, Some(count)) => CompletionTotal::Exact(count),
581 (Some(true), _) => CompletionTotal::HasMore,
582 _ => CompletionTotal::Unknown,
583 }
584 }
585}
586
587pub struct Completion {
588 pub values: Vec<String>,
589 pub total: CompletionTotal,
590}
591
592#[derive(Debug, Deserialize)]
593#[serde(rename_all = "camelCase")]
594pub struct CallToolResponse {
595 pub content: Vec<ToolResponseContent>,
596 #[serde(skip_serializing_if = "Option::is_none")]
597 pub is_error: Option<bool>,
598 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
599 pub meta: Option<HashMap<String, serde_json::Value>>,
600}
601
602#[derive(Debug, Serialize, Deserialize)]
603#[serde(tag = "type")]
604pub enum ToolResponseContent {
605 #[serde(rename = "text")]
606 Text { text: String },
607 #[serde(rename = "image", rename_all = "camelCase")]
608 Image { data: String, mime_type: String },
609 #[serde(rename = "resource")]
610 Resource { resource: ResourceContents },
611}
612
613#[derive(Debug, Serialize, Deserialize)]
614#[serde(rename_all = "camelCase")]
615pub struct ListToolsResponse {
616 pub tools: Vec<Tool>,
617 #[serde(skip_serializing_if = "Option::is_none")]
618 pub next_cursor: Option<String>,
619 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
620 pub meta: Option<HashMap<String, serde_json::Value>>,
621}
622
623#[derive(Debug, Deserialize)]
624#[serde(rename_all = "camelCase")]
625pub struct ListResourceTemplatesResponse {
626 pub resource_templates: Vec<ResourceTemplate>,
627 #[serde(skip_serializing_if = "Option::is_none")]
628 pub next_cursor: Option<String>,
629 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
630 pub meta: Option<HashMap<String, serde_json::Value>>,
631}
632
633#[derive(Debug, Deserialize)]
634#[serde(rename_all = "camelCase")]
635pub struct ListRootsResponse {
636 pub roots: Vec<Root>,
637 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
638 pub meta: Option<HashMap<String, serde_json::Value>>,
639}
640
641#[derive(Debug, Serialize, Deserialize)]
642#[serde(rename_all = "camelCase")]
643pub struct Root {
644 pub uri: Url,
645 #[serde(skip_serializing_if = "Option::is_none")]
646 pub name: Option<String>,
647}