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<ResourceContentsType>,
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(untagged)]
177pub enum ResourceContentsType {
178 Text(TextResourceContents),
179 Blob(BlobResourceContents),
180}
181
182#[derive(Debug, Deserialize)]
183#[serde(rename_all = "camelCase")]
184pub struct ResourcesListResponse {
185 pub resources: Vec<Resource>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub next_cursor: Option<String>,
188 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
189 pub meta: Option<HashMap<String, serde_json::Value>>,
190}
191
192#[derive(Debug, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct SamplingMessage {
195 pub role: Role,
196 pub content: MessageContent,
197}
198
199#[derive(Debug, Serialize)]
200#[serde(rename_all = "camelCase")]
201pub struct CreateMessageRequest {
202 pub messages: Vec<SamplingMessage>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub model_preferences: Option<ModelPreferences>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub system_prompt: Option<String>,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub include_context: Option<String>,
209 #[serde(skip_serializing_if = "Option::is_none")]
210 pub temperature: Option<f64>,
211 pub max_tokens: u32,
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub stop_sequences: Option<Vec<String>>,
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub metadata: Option<serde_json::Value>,
216}
217
218#[derive(Debug, Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct CreateMessageResult {
221 pub role: Role,
222 pub content: MessageContent,
223 pub model: String,
224 #[serde(skip_serializing_if = "Option::is_none")]
225 pub stop_reason: Option<String>,
226}
227
228#[derive(Debug, Serialize, Deserialize)]
229#[serde(rename_all = "camelCase")]
230pub struct PromptMessage {
231 pub role: Role,
232 pub content: MessageContent,
233}
234
235#[derive(Debug, Serialize, Deserialize)]
236#[serde(rename_all = "lowercase")]
237pub enum Role {
238 User,
239 Assistant,
240}
241
242#[derive(Debug, Serialize, Deserialize)]
243#[serde(tag = "type")]
244pub enum MessageContent {
245 #[serde(rename = "text")]
246 Text {
247 text: String,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 annotations: Option<MessageAnnotations>,
250 },
251 #[serde(rename = "image")]
252 Image {
253 data: String,
254 mime_type: String,
255 #[serde(skip_serializing_if = "Option::is_none")]
256 annotations: Option<MessageAnnotations>,
257 },
258 #[serde(rename = "resource")]
259 Resource {
260 resource: ResourceContents,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 annotations: Option<MessageAnnotations>,
263 },
264}
265
266#[derive(Debug, Serialize, Deserialize)]
267#[serde(rename_all = "camelCase")]
268pub struct MessageAnnotations {
269 #[serde(skip_serializing_if = "Option::is_none")]
270 pub audience: Option<Vec<Role>>,
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub priority: Option<f64>,
273}
274
275#[derive(Debug, Deserialize)]
276#[serde(rename_all = "camelCase")]
277pub struct PromptsGetResponse {
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub description: Option<String>,
280 pub messages: Vec<PromptMessage>,
281 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
282 pub meta: Option<HashMap<String, serde_json::Value>>,
283}
284
285#[derive(Debug, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub struct PromptsListResponse {
288 pub prompts: Vec<Prompt>,
289 #[serde(skip_serializing_if = "Option::is_none")]
290 pub next_cursor: Option<String>,
291 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
292 pub meta: Option<HashMap<String, serde_json::Value>>,
293}
294
295#[derive(Debug, Deserialize)]
296#[serde(rename_all = "camelCase")]
297pub struct CompletionCompleteResponse {
298 pub completion: CompletionResult,
299 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
300 pub meta: Option<HashMap<String, serde_json::Value>>,
301}
302
303#[derive(Debug, Deserialize)]
304#[serde(rename_all = "camelCase")]
305pub struct CompletionResult {
306 pub values: Vec<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
308 pub total: Option<u32>,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub has_more: Option<bool>,
311 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
312 pub meta: Option<HashMap<String, serde_json::Value>>,
313}
314
315#[derive(Debug, Deserialize, Serialize)]
316#[serde(rename_all = "camelCase")]
317pub struct Prompt {
318 pub name: String,
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub description: Option<String>,
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub arguments: Option<Vec<PromptArgument>>,
323}
324
325#[derive(Debug, Deserialize, Serialize)]
326#[serde(rename_all = "camelCase")]
327pub struct PromptArgument {
328 pub name: String,
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub description: Option<String>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub required: Option<bool>,
333}
334
335#[derive(Debug, Serialize, Deserialize)]
336#[serde(rename_all = "camelCase")]
337pub struct ClientCapabilities {
338 #[serde(skip_serializing_if = "Option::is_none")]
339 pub experimental: Option<HashMap<String, serde_json::Value>>,
340 #[serde(skip_serializing_if = "Option::is_none")]
341 pub sampling: Option<serde_json::Value>,
342 #[serde(skip_serializing_if = "Option::is_none")]
343 pub roots: Option<RootsCapabilities>,
344}
345
346#[derive(Debug, Serialize, Deserialize)]
347#[serde(rename_all = "camelCase")]
348pub struct ServerCapabilities {
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub experimental: Option<HashMap<String, serde_json::Value>>,
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub logging: Option<serde_json::Value>,
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub prompts: Option<PromptsCapabilities>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 pub resources: Option<ResourcesCapabilities>,
357 #[serde(skip_serializing_if = "Option::is_none")]
358 pub tools: Option<ToolsCapabilities>,
359}
360
361#[derive(Debug, Serialize, Deserialize)]
362#[serde(rename_all = "camelCase")]
363pub struct PromptsCapabilities {
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub list_changed: Option<bool>,
366}
367
368#[derive(Debug, Serialize, Deserialize)]
369#[serde(rename_all = "camelCase")]
370pub struct ResourcesCapabilities {
371 #[serde(skip_serializing_if = "Option::is_none")]
372 pub subscribe: Option<bool>,
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub list_changed: Option<bool>,
375}
376
377#[derive(Debug, Serialize, Deserialize)]
378#[serde(rename_all = "camelCase")]
379pub struct ToolsCapabilities {
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub list_changed: Option<bool>,
382}
383
384#[derive(Debug, Serialize, Deserialize)]
385#[serde(rename_all = "camelCase")]
386pub struct RootsCapabilities {
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub list_changed: Option<bool>,
389}
390
391#[derive(Debug, Serialize, Deserialize)]
392#[serde(rename_all = "camelCase")]
393pub struct Tool {
394 pub name: String,
395 #[serde(skip_serializing_if = "Option::is_none")]
396 pub description: Option<String>,
397 pub input_schema: serde_json::Value,
398}
399
400#[derive(Debug, Serialize, Deserialize)]
401#[serde(rename_all = "camelCase")]
402pub struct Implementation {
403 pub name: String,
404 pub version: String,
405}
406
407#[derive(Debug, Serialize, Deserialize)]
408#[serde(rename_all = "camelCase")]
409pub struct Resource {
410 pub uri: Url,
411 pub name: String,
412 #[serde(skip_serializing_if = "Option::is_none")]
413 pub description: Option<String>,
414 #[serde(skip_serializing_if = "Option::is_none")]
415 pub mime_type: Option<String>,
416}
417
418#[derive(Debug, Serialize, Deserialize)]
419#[serde(rename_all = "camelCase")]
420pub struct ResourceContents {
421 pub uri: Url,
422 #[serde(skip_serializing_if = "Option::is_none")]
423 pub mime_type: Option<String>,
424}
425
426#[derive(Debug, Serialize, Deserialize)]
427#[serde(rename_all = "camelCase")]
428pub struct TextResourceContents {
429 pub uri: Url,
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub mime_type: Option<String>,
432 pub text: String,
433}
434
435#[derive(Debug, Serialize, Deserialize)]
436#[serde(rename_all = "camelCase")]
437pub struct BlobResourceContents {
438 pub uri: Url,
439 #[serde(skip_serializing_if = "Option::is_none")]
440 pub mime_type: Option<String>,
441 pub blob: String,
442}
443
444#[derive(Debug, Serialize, Deserialize)]
445#[serde(rename_all = "camelCase")]
446pub struct ResourceTemplate {
447 pub uri_template: String,
448 pub name: String,
449 #[serde(skip_serializing_if = "Option::is_none")]
450 pub description: Option<String>,
451 #[serde(skip_serializing_if = "Option::is_none")]
452 pub mime_type: Option<String>,
453}
454
455#[derive(Debug, Serialize, Deserialize)]
456#[serde(rename_all = "lowercase")]
457pub enum LoggingLevel {
458 Debug,
459 Info,
460 Notice,
461 Warning,
462 Error,
463 Critical,
464 Alert,
465 Emergency,
466}
467
468#[derive(Debug, Serialize, Deserialize)]
469#[serde(rename_all = "camelCase")]
470pub struct ModelPreferences {
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub hints: Option<Vec<ModelHint>>,
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub cost_priority: Option<f64>,
475 #[serde(skip_serializing_if = "Option::is_none")]
476 pub speed_priority: Option<f64>,
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub intelligence_priority: Option<f64>,
479}
480
481#[derive(Debug, Serialize, Deserialize)]
482#[serde(rename_all = "camelCase")]
483pub struct ModelHint {
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub name: Option<String>,
486}
487
488#[derive(Debug, Serialize)]
489#[serde(rename_all = "camelCase")]
490pub enum NotificationType {
491 Initialized,
492 Progress,
493 Message,
494 ResourcesUpdated,
495 ResourcesListChanged,
496 ToolsListChanged,
497 PromptsListChanged,
498 RootsListChanged,
499}
500
501impl NotificationType {
502 pub fn as_str(&self) -> &'static str {
503 match self {
504 NotificationType::Initialized => "notifications/initialized",
505 NotificationType::Progress => "notifications/progress",
506 NotificationType::Message => "notifications/message",
507 NotificationType::ResourcesUpdated => "notifications/resources/updated",
508 NotificationType::ResourcesListChanged => "notifications/resources/list_changed",
509 NotificationType::ToolsListChanged => "notifications/tools/list_changed",
510 NotificationType::PromptsListChanged => "notifications/prompts/list_changed",
511 NotificationType::RootsListChanged => "notifications/roots/list_changed",
512 }
513 }
514}
515
516#[derive(Debug, Serialize)]
517#[serde(untagged)]
518pub enum ClientNotification {
519 Initialized,
520 Progress(ProgressParams),
521 RootsListChanged,
522 Cancelled {
523 request_id: String,
524 #[serde(skip_serializing_if = "Option::is_none")]
525 reason: Option<String>,
526 },
527}
528
529#[derive(Debug, Serialize, Deserialize)]
530#[serde(untagged)]
531pub enum ProgressToken {
532 String(String),
533 Number(f64),
534}
535
536#[derive(Debug, Serialize)]
537#[serde(rename_all = "camelCase")]
538pub struct ProgressParams {
539 pub progress_token: ProgressToken,
540 pub progress: f64,
541 #[serde(skip_serializing_if = "Option::is_none")]
542 pub total: Option<f64>,
543 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
544 pub meta: Option<HashMap<String, serde_json::Value>>,
545}
546
547pub enum CompletionTotal {
548 Exact(u32),
549 HasMore,
550 Unknown,
551}
552
553impl CompletionTotal {
554 pub fn from_options(has_more: Option<bool>, total: Option<u32>) -> Self {
555 match (has_more, total) {
556 (_, Some(count)) => CompletionTotal::Exact(count),
557 (Some(true), _) => CompletionTotal::HasMore,
558 _ => CompletionTotal::Unknown,
559 }
560 }
561}
562
563pub struct Completion {
564 pub values: Vec<String>,
565 pub total: CompletionTotal,
566}
567
568#[derive(Debug, Deserialize)]
569#[serde(rename_all = "camelCase")]
570pub struct CallToolResponse {
571 pub content: Vec<ToolResponseContent>,
572 #[serde(skip_serializing_if = "Option::is_none")]
573 pub is_error: Option<bool>,
574 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
575 pub meta: Option<HashMap<String, serde_json::Value>>,
576}
577
578#[derive(Debug, Serialize, Deserialize)]
579#[serde(tag = "type")]
580pub enum ToolResponseContent {
581 #[serde(rename = "text")]
582 Text { text: String },
583 #[serde(rename = "image")]
584 Image { data: String, mime_type: String },
585 #[serde(rename = "resource")]
586 Resource { resource: ResourceContents },
587}
588
589#[derive(Debug, Deserialize)]
590#[serde(rename_all = "camelCase")]
591pub struct ListToolsResponse {
592 pub tools: Vec<Tool>,
593 #[serde(skip_serializing_if = "Option::is_none")]
594 pub next_cursor: Option<String>,
595 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
596 pub meta: Option<HashMap<String, serde_json::Value>>,
597}
598
599#[derive(Debug, Deserialize)]
600#[serde(rename_all = "camelCase")]
601pub struct ListResourceTemplatesResponse {
602 pub resource_templates: Vec<ResourceTemplate>,
603 #[serde(skip_serializing_if = "Option::is_none")]
604 pub next_cursor: Option<String>,
605 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
606 pub meta: Option<HashMap<String, serde_json::Value>>,
607}
608
609#[derive(Debug, Deserialize)]
610#[serde(rename_all = "camelCase")]
611pub struct ListRootsResponse {
612 pub roots: Vec<Root>,
613 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
614 pub meta: Option<HashMap<String, serde_json::Value>>,
615}
616
617#[derive(Debug, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct Root {
620 pub uri: Url,
621 #[serde(skip_serializing_if = "Option::is_none")]
622 pub name: Option<String>,
623}