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