types.rs

  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}