1use collections::HashMap;
2use serde::de::DeserializeOwned;
3use serde::{Deserialize, Serialize};
4use url::Url;
5
6pub const LATEST_PROTOCOL_VERSION: &str = "2025-03-26";
7pub const VERSION_2024_11_05: &str = "2024-11-05";
8
9pub mod request {
10 use super::*;
11
12 macro_rules! request {
13 ($method:expr, $name:ident, $params:ty, $response:ty) => {
14 pub struct $name;
15
16 impl Request for $name {
17 type Params = $params;
18 type Response = $response;
19 const METHOD: &'static str = $method;
20 }
21 };
22 }
23
24 request!(
25 "initialize",
26 Initialize,
27 InitializeParams,
28 InitializeResponse
29 );
30 request!("tools/call", CallTool, CallToolParams, CallToolResponse);
31 request!(
32 "resources/unsubscribe",
33 ResourcesUnsubscribe,
34 ResourcesUnsubscribeParams,
35 ()
36 );
37 request!(
38 "resources/subscribe",
39 ResourcesSubscribe,
40 ResourcesSubscribeParams,
41 ()
42 );
43 request!(
44 "resources/read",
45 ResourcesRead,
46 ResourcesReadParams,
47 ResourcesReadResponse
48 );
49 request!("resources/list", ResourcesList, (), ResourcesListResponse);
50 request!(
51 "logging/setLevel",
52 LoggingSetLevel,
53 LoggingSetLevelParams,
54 ()
55 );
56 request!(
57 "prompts/get",
58 PromptsGet,
59 PromptsGetParams,
60 PromptsGetResponse
61 );
62 request!("prompts/list", PromptsList, (), PromptsListResponse);
63 request!(
64 "completion/complete",
65 CompletionComplete,
66 CompletionCompleteParams,
67 CompletionCompleteResponse
68 );
69 request!("ping", Ping, (), ());
70 request!("tools/list", ListTools, (), ListToolsResponse);
71 request!(
72 "resources/templates/list",
73 ListResourceTemplates,
74 (),
75 ListResourceTemplatesResponse
76 );
77 request!("roots/list", ListRoots, (), ListRootsResponse);
78}
79
80pub trait Request {
81 type Params: DeserializeOwned + Serialize + Send + Sync + 'static;
82 type Response: DeserializeOwned + Serialize + Send + Sync + 'static;
83 const METHOD: &'static str;
84}
85
86#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
87#[serde(transparent)]
88pub struct ProtocolVersion(pub String);
89
90#[derive(Debug, Serialize, Deserialize)]
91#[serde(rename_all = "camelCase")]
92pub struct InitializeParams {
93 pub protocol_version: ProtocolVersion,
94 pub capabilities: ClientCapabilities,
95 pub client_info: Implementation,
96 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
97 pub meta: Option<HashMap<String, serde_json::Value>>,
98}
99
100#[derive(Debug, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102pub struct CallToolParams {
103 pub name: String,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub arguments: Option<HashMap<String, serde_json::Value>>,
106 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
107 pub meta: Option<HashMap<String, serde_json::Value>>,
108}
109
110#[derive(Debug, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase")]
112pub struct ResourcesUnsubscribeParams {
113 pub uri: Url,
114 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
115 pub meta: Option<HashMap<String, serde_json::Value>>,
116}
117
118#[derive(Debug, Serialize, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct ResourcesSubscribeParams {
121 pub uri: Url,
122 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
123 pub meta: Option<HashMap<String, serde_json::Value>>,
124}
125
126#[derive(Debug, Serialize, Deserialize)]
127#[serde(rename_all = "camelCase")]
128pub struct ResourcesReadParams {
129 pub uri: Url,
130 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
131 pub meta: Option<HashMap<String, serde_json::Value>>,
132}
133
134#[derive(Debug, Serialize, Deserialize)]
135#[serde(rename_all = "camelCase")]
136pub struct LoggingSetLevelParams {
137 pub level: LoggingLevel,
138 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
139 pub meta: Option<HashMap<String, serde_json::Value>>,
140}
141
142#[derive(Debug, Serialize, Deserialize)]
143#[serde(rename_all = "camelCase")]
144pub struct PromptsGetParams {
145 pub name: String,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub arguments: Option<HashMap<String, String>>,
148 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
149 pub meta: Option<HashMap<String, serde_json::Value>>,
150}
151
152#[derive(Debug, Serialize, Deserialize)]
153#[serde(rename_all = "camelCase")]
154pub struct CompletionCompleteParams {
155 #[serde(rename = "ref")]
156 pub reference: CompletionReference,
157 pub argument: CompletionArgument,
158 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
159 pub meta: Option<HashMap<String, serde_json::Value>>,
160}
161
162#[derive(Debug, Serialize, Deserialize)]
163#[serde(untagged)]
164pub enum CompletionReference {
165 Prompt(PromptReference),
166 Resource(ResourceReference),
167}
168
169#[derive(Debug, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct PromptReference {
172 #[serde(rename = "type")]
173 pub ty: PromptReferenceType,
174 pub name: String,
175}
176
177#[derive(Debug, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct ResourceReference {
180 #[serde(rename = "type")]
181 pub ty: PromptReferenceType,
182 pub uri: Url,
183}
184
185#[derive(Debug, Serialize, Deserialize)]
186#[serde(rename_all = "snake_case")]
187pub enum PromptReferenceType {
188 #[serde(rename = "ref/prompt")]
189 Prompt,
190 #[serde(rename = "ref/resource")]
191 Resource,
192}
193
194#[derive(Debug, Serialize, Deserialize)]
195#[serde(rename_all = "camelCase")]
196pub struct CompletionArgument {
197 pub name: String,
198 pub value: String,
199}
200
201#[derive(Debug, Serialize, Deserialize)]
202#[serde(rename_all = "camelCase")]
203pub struct InitializeResponse {
204 pub protocol_version: ProtocolVersion,
205 pub capabilities: ServerCapabilities,
206 pub server_info: Implementation,
207 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
208 pub meta: Option<HashMap<String, serde_json::Value>>,
209}
210
211#[derive(Debug, Serialize, Deserialize)]
212#[serde(rename_all = "camelCase")]
213pub struct ResourcesReadResponse {
214 pub contents: Vec<ResourceContentsType>,
215 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
216 pub meta: Option<HashMap<String, serde_json::Value>>,
217}
218
219#[derive(Debug, Serialize, Deserialize)]
220#[serde(untagged)]
221pub enum ResourceContentsType {
222 Text(TextResourceContents),
223 Blob(BlobResourceContents),
224}
225
226#[derive(Debug, Serialize, Deserialize)]
227#[serde(rename_all = "camelCase")]
228pub struct ResourcesListResponse {
229 pub resources: Vec<Resource>,
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, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct SamplingMessage {
239 pub role: Role,
240 pub content: MessageContent,
241}
242
243#[derive(Debug, Serialize, Deserialize)]
244#[serde(rename_all = "camelCase")]
245pub struct CreateMessageRequest {
246 pub messages: Vec<SamplingMessage>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub model_preferences: Option<ModelPreferences>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub system_prompt: Option<String>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub include_context: Option<String>,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub temperature: Option<f64>,
255 pub max_tokens: u32,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub stop_sequences: Option<Vec<String>>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub metadata: Option<serde_json::Value>,
260}
261
262#[derive(Debug, Deserialize)]
263#[serde(rename_all = "camelCase")]
264pub struct CreateMessageResult {
265 pub role: Role,
266 pub content: MessageContent,
267 pub model: String,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub stop_reason: Option<String>,
270}
271
272#[derive(Debug, Serialize, Deserialize)]
273#[serde(rename_all = "camelCase")]
274pub struct PromptMessage {
275 pub role: Role,
276 pub content: MessageContent,
277}
278
279#[derive(Debug, Serialize, Deserialize)]
280#[serde(rename_all = "lowercase")]
281pub enum Role {
282 User,
283 Assistant,
284}
285
286#[derive(Debug, Serialize, Deserialize)]
287#[serde(tag = "type")]
288pub enum MessageContent {
289 #[serde(rename = "text")]
290 Text {
291 text: String,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 annotations: Option<MessageAnnotations>,
294 },
295 #[serde(rename = "image", rename_all = "camelCase")]
296 Image {
297 data: String,
298 mime_type: String,
299 #[serde(skip_serializing_if = "Option::is_none")]
300 annotations: Option<MessageAnnotations>,
301 },
302 #[serde(rename = "audio", rename_all = "camelCase")]
303 Audio {
304 data: String,
305 mime_type: String,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 annotations: Option<MessageAnnotations>,
308 },
309 #[serde(rename = "resource")]
310 Resource {
311 resource: ResourceContents,
312 #[serde(skip_serializing_if = "Option::is_none")]
313 annotations: Option<MessageAnnotations>,
314 },
315}
316
317#[derive(Debug, Serialize, Deserialize)]
318#[serde(rename_all = "camelCase")]
319pub struct MessageAnnotations {
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub audience: Option<Vec<Role>>,
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub priority: Option<f64>,
324}
325
326#[derive(Debug, Serialize, Deserialize)]
327#[serde(rename_all = "camelCase")]
328pub struct PromptsGetResponse {
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub description: Option<String>,
331 pub messages: Vec<PromptMessage>,
332 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
333 pub meta: Option<HashMap<String, serde_json::Value>>,
334}
335
336#[derive(Debug, Serialize, Deserialize)]
337#[serde(rename_all = "camelCase")]
338pub struct PromptsListResponse {
339 pub prompts: Vec<Prompt>,
340 #[serde(skip_serializing_if = "Option::is_none")]
341 pub next_cursor: Option<String>,
342 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
343 pub meta: Option<HashMap<String, serde_json::Value>>,
344}
345
346#[derive(Debug, Serialize, Deserialize)]
347#[serde(rename_all = "camelCase")]
348pub struct CompletionCompleteResponse {
349 pub completion: CompletionResult,
350 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
351 pub meta: Option<HashMap<String, serde_json::Value>>,
352}
353
354#[derive(Debug, Serialize, Deserialize)]
355#[serde(rename_all = "camelCase")]
356pub struct CompletionResult {
357 pub values: Vec<String>,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub total: Option<u32>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub has_more: Option<bool>,
362 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
363 pub meta: Option<HashMap<String, serde_json::Value>>,
364}
365
366#[derive(Debug, Serialize, Deserialize)]
367#[serde(rename_all = "camelCase")]
368pub struct Prompt {
369 pub name: String,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub description: Option<String>,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 pub arguments: Option<Vec<PromptArgument>>,
374}
375
376#[derive(Debug, Serialize, Deserialize)]
377#[serde(rename_all = "camelCase")]
378pub struct PromptArgument {
379 pub name: String,
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub description: Option<String>,
382 #[serde(skip_serializing_if = "Option::is_none")]
383 pub required: Option<bool>,
384}
385
386#[derive(Debug, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388pub struct ClientCapabilities {
389 #[serde(skip_serializing_if = "Option::is_none")]
390 pub experimental: Option<HashMap<String, serde_json::Value>>,
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub sampling: Option<serde_json::Value>,
393 #[serde(skip_serializing_if = "Option::is_none")]
394 pub roots: Option<RootsCapabilities>,
395}
396
397#[derive(Default, Debug, Serialize, Deserialize)]
398#[serde(rename_all = "camelCase")]
399pub struct ServerCapabilities {
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub experimental: Option<HashMap<String, serde_json::Value>>,
402 #[serde(skip_serializing_if = "Option::is_none")]
403 pub logging: Option<serde_json::Value>,
404 #[serde(skip_serializing_if = "Option::is_none")]
405 pub completions: Option<serde_json::Value>,
406 #[serde(skip_serializing_if = "Option::is_none")]
407 pub prompts: Option<PromptsCapabilities>,
408 #[serde(skip_serializing_if = "Option::is_none")]
409 pub resources: Option<ResourcesCapabilities>,
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub tools: Option<ToolsCapabilities>,
412}
413
414#[derive(Debug, Serialize, Deserialize)]
415#[serde(rename_all = "camelCase")]
416pub struct PromptsCapabilities {
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub list_changed: Option<bool>,
419}
420
421#[derive(Debug, Serialize, Deserialize)]
422#[serde(rename_all = "camelCase")]
423pub struct ResourcesCapabilities {
424 #[serde(skip_serializing_if = "Option::is_none")]
425 pub subscribe: Option<bool>,
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub list_changed: Option<bool>,
428}
429
430#[derive(Debug, Serialize, Deserialize)]
431#[serde(rename_all = "camelCase")]
432pub struct ToolsCapabilities {
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub list_changed: Option<bool>,
435}
436
437#[derive(Debug, Serialize, Deserialize)]
438#[serde(rename_all = "camelCase")]
439pub struct RootsCapabilities {
440 #[serde(skip_serializing_if = "Option::is_none")]
441 pub list_changed: Option<bool>,
442}
443
444#[derive(Debug, Serialize, Deserialize)]
445#[serde(rename_all = "camelCase")]
446pub struct Tool {
447 pub name: String,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub description: Option<String>,
450 pub input_schema: serde_json::Value,
451 #[serde(skip_serializing_if = "Option::is_none")]
452 pub annotations: Option<ToolAnnotations>,
453}
454
455#[derive(Debug, Serialize, Deserialize)]
456#[serde(rename_all = "camelCase")]
457pub struct ToolAnnotations {
458 /// A human-readable title for the tool.
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub title: Option<String>,
461 /// If true, the tool does not modify its environment.
462 #[serde(skip_serializing_if = "Option::is_none")]
463 pub read_only_hint: Option<bool>,
464 /// If true, the tool may perform destructive updates to its environment.
465 #[serde(skip_serializing_if = "Option::is_none")]
466 pub destructive_hint: Option<bool>,
467 /// If true, calling the tool repeatedly with the same arguments will have no additional effect on its environment.
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub idempotent_hint: Option<bool>,
470 /// If true, this tool may interact with an "open world" of external entities.
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub open_world_hint: Option<bool>,
473}
474
475#[derive(Debug, Serialize, Deserialize)]
476#[serde(rename_all = "camelCase")]
477pub struct Implementation {
478 pub name: String,
479 pub version: String,
480}
481
482#[derive(Debug, Serialize, Deserialize)]
483#[serde(rename_all = "camelCase")]
484pub struct Resource {
485 pub uri: Url,
486 pub name: String,
487 #[serde(skip_serializing_if = "Option::is_none")]
488 pub description: Option<String>,
489 #[serde(skip_serializing_if = "Option::is_none")]
490 pub mime_type: Option<String>,
491}
492
493#[derive(Debug, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct ResourceContents {
496 pub uri: Url,
497 #[serde(skip_serializing_if = "Option::is_none")]
498 pub mime_type: Option<String>,
499}
500
501#[derive(Debug, Serialize, Deserialize)]
502#[serde(rename_all = "camelCase")]
503pub struct TextResourceContents {
504 pub uri: Url,
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub mime_type: Option<String>,
507 pub text: String,
508}
509
510#[derive(Debug, Serialize, Deserialize)]
511#[serde(rename_all = "camelCase")]
512pub struct BlobResourceContents {
513 pub uri: Url,
514 #[serde(skip_serializing_if = "Option::is_none")]
515 pub mime_type: Option<String>,
516 pub blob: String,
517}
518
519#[derive(Debug, Serialize, Deserialize)]
520#[serde(rename_all = "camelCase")]
521pub struct ResourceTemplate {
522 pub uri_template: String,
523 pub name: String,
524 #[serde(skip_serializing_if = "Option::is_none")]
525 pub description: Option<String>,
526 #[serde(skip_serializing_if = "Option::is_none")]
527 pub mime_type: Option<String>,
528}
529
530#[derive(Debug, Serialize, Deserialize)]
531#[serde(rename_all = "lowercase")]
532pub enum LoggingLevel {
533 Debug,
534 Info,
535 Notice,
536 Warning,
537 Error,
538 Critical,
539 Alert,
540 Emergency,
541}
542
543#[derive(Debug, Serialize, Deserialize)]
544#[serde(rename_all = "camelCase")]
545pub struct ModelPreferences {
546 #[serde(skip_serializing_if = "Option::is_none")]
547 pub hints: Option<Vec<ModelHint>>,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 pub cost_priority: Option<f64>,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub speed_priority: Option<f64>,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 pub intelligence_priority: Option<f64>,
554}
555
556#[derive(Debug, Serialize, Deserialize)]
557#[serde(rename_all = "camelCase")]
558pub struct ModelHint {
559 #[serde(skip_serializing_if = "Option::is_none")]
560 pub name: Option<String>,
561}
562
563#[derive(Debug, Serialize, Deserialize)]
564#[serde(rename_all = "camelCase")]
565pub enum NotificationType {
566 Initialized,
567 Progress,
568 Message,
569 ResourcesUpdated,
570 ResourcesListChanged,
571 ToolsListChanged,
572 PromptsListChanged,
573 RootsListChanged,
574}
575
576impl NotificationType {
577 pub fn as_str(&self) -> &'static str {
578 match self {
579 NotificationType::Initialized => "notifications/initialized",
580 NotificationType::Progress => "notifications/progress",
581 NotificationType::Message => "notifications/message",
582 NotificationType::ResourcesUpdated => "notifications/resources/updated",
583 NotificationType::ResourcesListChanged => "notifications/resources/list_changed",
584 NotificationType::ToolsListChanged => "notifications/tools/list_changed",
585 NotificationType::PromptsListChanged => "notifications/prompts/list_changed",
586 NotificationType::RootsListChanged => "notifications/roots/list_changed",
587 }
588 }
589}
590
591#[derive(Debug, Serialize)]
592#[serde(untagged)]
593pub enum ClientNotification {
594 Initialized,
595 Progress(ProgressParams),
596 RootsListChanged,
597 Cancelled {
598 request_id: String,
599 #[serde(skip_serializing_if = "Option::is_none")]
600 reason: Option<String>,
601 },
602}
603
604#[derive(Debug, Serialize, Deserialize)]
605#[serde(untagged)]
606pub enum ProgressToken {
607 String(String),
608 Number(f64),
609}
610
611#[derive(Debug, Serialize)]
612#[serde(rename_all = "camelCase")]
613pub struct ProgressParams {
614 pub progress_token: ProgressToken,
615 pub progress: f64,
616 #[serde(skip_serializing_if = "Option::is_none")]
617 pub message: Option<String>,
618 #[serde(skip_serializing_if = "Option::is_none")]
619 pub total: Option<f64>,
620 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
621 pub meta: Option<HashMap<String, serde_json::Value>>,
622}
623
624pub enum CompletionTotal {
625 Exact(u32),
626 HasMore,
627 Unknown,
628}
629
630impl CompletionTotal {
631 pub fn from_options(has_more: Option<bool>, total: Option<u32>) -> Self {
632 match (has_more, total) {
633 (_, Some(count)) => CompletionTotal::Exact(count),
634 (Some(true), _) => CompletionTotal::HasMore,
635 _ => CompletionTotal::Unknown,
636 }
637 }
638}
639
640pub struct Completion {
641 pub values: Vec<String>,
642 pub total: CompletionTotal,
643}
644
645#[derive(Debug, Serialize, Deserialize)]
646#[serde(rename_all = "camelCase")]
647pub struct CallToolResponse {
648 pub content: Vec<ToolResponseContent>,
649 #[serde(skip_serializing_if = "Option::is_none")]
650 pub is_error: Option<bool>,
651 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
652 pub meta: Option<HashMap<String, serde_json::Value>>,
653}
654
655#[derive(Debug, Serialize, Deserialize)]
656#[serde(tag = "type")]
657pub enum ToolResponseContent {
658 #[serde(rename = "text")]
659 Text { text: String },
660 #[serde(rename = "image", rename_all = "camelCase")]
661 Image { data: String, mime_type: String },
662 #[serde(rename = "audio", rename_all = "camelCase")]
663 Audio { data: String, mime_type: String },
664 #[serde(rename = "resource")]
665 Resource { resource: ResourceContents },
666}
667
668#[derive(Debug, Serialize, Deserialize)]
669#[serde(rename_all = "camelCase")]
670pub struct ListToolsResponse {
671 pub tools: Vec<Tool>,
672 #[serde(skip_serializing_if = "Option::is_none")]
673 pub next_cursor: Option<String>,
674 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
675 pub meta: Option<HashMap<String, serde_json::Value>>,
676}
677
678#[derive(Debug, Serialize, Deserialize)]
679#[serde(rename_all = "camelCase")]
680pub struct ListResourceTemplatesResponse {
681 pub resource_templates: Vec<ResourceTemplate>,
682 #[serde(skip_serializing_if = "Option::is_none")]
683 pub next_cursor: Option<String>,
684 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
685 pub meta: Option<HashMap<String, serde_json::Value>>,
686}
687
688#[derive(Debug, Serialize, Deserialize)]
689#[serde(rename_all = "camelCase")]
690pub struct ListRootsResponse {
691 pub roots: Vec<Root>,
692 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
693 pub meta: Option<HashMap<String, serde_json::Value>>,
694}
695
696#[derive(Debug, Serialize, Deserialize)]
697#[serde(rename_all = "camelCase")]
698pub struct Root {
699 pub uri: Url,
700 #[serde(skip_serializing_if = "Option::is_none")]
701 pub name: Option<String>,
702}