1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10pub const LATEST_PROTOCOL_VERSION: &str = "2025-06-18";
16pub const JSONRPC_VERSION: &str = "2.0";
17
18pub const PROTOCOL_VERSION: &str = LATEST_PROTOCOL_VERSION;
20
21pub type ProgressToken = serde_json::Value; pub type Cursor = String;
30
31pub type RequestId = serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36#[serde(untagged)]
37pub enum JsonRpcId {
38 String(String),
39 Number(i64),
40 Null,
41}
42
43impl From<i64> for JsonRpcId {
44 fn from(value: i64) -> Self {
45 JsonRpcId::Number(value)
46 }
47}
48
49impl From<String> for JsonRpcId {
50 fn from(value: String) -> Self {
51 JsonRpcId::String(value)
52 }
53}
54
55impl From<&str> for JsonRpcId {
56 fn from(value: &str) -> Self {
57 JsonRpcId::String(value.to_string())
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
67pub struct BaseMetadata {
68 pub name: String,
70 #[serde(skip_serializing_if = "Option::is_none")]
76 pub title: Option<String>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
85pub struct Implementation {
86 pub name: String,
88 pub version: String,
90 #[serde(skip_serializing_if = "Option::is_none")]
93 pub title: Option<String>,
94}
95
96impl Implementation {
97 pub fn new<S: Into<String>>(name: S, version: S) -> Self {
99 Self {
100 name: name.into(),
101 version: version.into(),
102 title: None,
103 }
104 }
105
106 pub fn with_title<S: Into<String>>(name: S, version: S, title: S) -> Self {
108 Self {
109 name: name.into(),
110 version: version.into(),
111 title: Some(title.into()),
112 }
113 }
114}
115
116pub type ServerInfo = Implementation;
118pub type ClientInfo = Implementation;
119
120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
126pub struct ServerCapabilities {
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub prompts: Option<PromptsCapability>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub resources: Option<ResourcesCapability>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub tools: Option<ToolsCapability>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub sampling: Option<SamplingCapability>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub logging: Option<LoggingCapability>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub completions: Option<CompletionsCapability>,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub experimental: Option<HashMap<String, serde_json::Value>>,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
152pub struct ClientCapabilities {
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub sampling: Option<SamplingCapability>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub roots: Option<RootsCapability>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub elicitation: Option<ElicitationCapability>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub experimental: Option<HashMap<String, serde_json::Value>>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
169pub struct PromptsCapability {
170 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
172 pub list_changed: Option<bool>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
177pub struct ResourcesCapability {
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub subscribe: Option<bool>,
181 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
183 pub list_changed: Option<bool>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
188pub struct ToolsCapability {
189 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
191 pub list_changed: Option<bool>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
196pub struct SamplingCapability {
197 #[serde(flatten)]
199 pub additional_properties: HashMap<String, serde_json::Value>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
204pub struct LoggingCapability {
205 #[serde(flatten)]
207 pub additional_properties: HashMap<String, serde_json::Value>,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
212pub struct CompletionsCapability {
213 #[serde(flatten)]
215 pub additional_properties: HashMap<String, serde_json::Value>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
220pub struct RootsCapability {
221 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
223 pub list_changed: Option<bool>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
228pub struct ElicitationCapability {
229 #[serde(flatten)]
231 pub additional_properties: HashMap<String, serde_json::Value>,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
240pub struct Annotations {
241 #[serde(skip_serializing_if = "Option::is_none")]
245 pub audience: Option<Vec<Role>>,
246 #[serde(skip_serializing_if = "Option::is_none")]
252 pub priority: Option<f64>,
253 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
260 pub last_modified: Option<String>,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub danger: Option<DangerLevel>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub destructive: Option<bool>,
267 #[serde(skip_serializing_if = "Option::is_none")]
269 pub read_only: Option<bool>,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
278pub struct TextContent {
279 #[serde(rename = "type")]
281 pub content_type: String, pub text: String,
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub annotations: Option<Annotations>,
287 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
289 pub meta: Option<HashMap<String, serde_json::Value>>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
294pub struct ImageContent {
295 #[serde(rename = "type")]
297 pub content_type: String, pub data: String,
300 #[serde(rename = "mimeType")]
302 pub mime_type: String,
303 #[serde(skip_serializing_if = "Option::is_none")]
305 pub annotations: Option<Annotations>,
306 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
308 pub meta: Option<HashMap<String, serde_json::Value>>,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
313pub struct AudioContent {
314 #[serde(rename = "type")]
316 pub content_type: String, pub data: String,
319 #[serde(rename = "mimeType")]
321 pub mime_type: String,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub annotations: Option<Annotations>,
325 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
327 pub meta: Option<HashMap<String, serde_json::Value>>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
332pub struct ResourceLink {
333 #[serde(rename = "type")]
335 pub content_type: String, pub uri: String,
338 pub name: String,
340 #[serde(skip_serializing_if = "Option::is_none")]
342 pub description: Option<String>,
343 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
345 pub mime_type: Option<String>,
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub size: Option<u64>,
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub title: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub annotations: Option<Annotations>,
355 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
357 pub meta: Option<HashMap<String, serde_json::Value>>,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
362pub struct EmbeddedResource {
363 #[serde(rename = "type")]
365 pub content_type: String, pub resource: ResourceContents,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub annotations: Option<Annotations>,
371 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
373 pub meta: Option<HashMap<String, serde_json::Value>>,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
378#[serde(tag = "type")]
379pub enum ContentBlock {
380 #[serde(rename = "text")]
382 Text {
383 text: String,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 annotations: Option<Annotations>,
388 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
390 meta: Option<HashMap<String, serde_json::Value>>,
391 },
392 #[serde(rename = "image")]
394 Image {
395 data: String,
397 #[serde(rename = "mimeType")]
399 mime_type: String,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 annotations: Option<Annotations>,
403 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
405 meta: Option<HashMap<String, serde_json::Value>>,
406 },
407 #[serde(rename = "audio")]
409 Audio {
410 data: String,
412 #[serde(rename = "mimeType")]
414 mime_type: String,
415 #[serde(skip_serializing_if = "Option::is_none")]
417 annotations: Option<Annotations>,
418 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
420 meta: Option<HashMap<String, serde_json::Value>>,
421 },
422 #[serde(rename = "resource_link")]
424 ResourceLink {
425 uri: String,
427 name: String,
429 #[serde(skip_serializing_if = "Option::is_none")]
431 description: Option<String>,
432 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
434 mime_type: Option<String>,
435 #[serde(skip_serializing_if = "Option::is_none")]
437 size: Option<u64>,
438 #[serde(skip_serializing_if = "Option::is_none")]
440 title: Option<String>,
441 #[serde(skip_serializing_if = "Option::is_none")]
443 annotations: Option<Annotations>,
444 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
446 meta: Option<HashMap<String, serde_json::Value>>,
447 },
448 #[serde(rename = "resource")]
450 Resource {
451 resource: ResourceContents,
453 #[serde(skip_serializing_if = "Option::is_none")]
455 annotations: Option<Annotations>,
456 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
458 meta: Option<HashMap<String, serde_json::Value>>,
459 },
460}
461
462pub type Content = ContentBlock;
464
465#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
478pub struct ToolAnnotations {
479 #[serde(skip_serializing_if = "Option::is_none")]
481 pub title: Option<String>,
482
483 #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
486 pub read_only_hint: Option<bool>,
487
488 #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
493 pub destructive_hint: Option<bool>,
494
495 #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
500 pub idempotent_hint: Option<bool>,
501
502 #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
508 pub open_world_hint: Option<bool>,
509}
510
511impl ToolAnnotations {
512 pub fn new() -> Self {
514 Self::default()
515 }
516
517 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
519 self.title = Some(title.into());
520 self
521 }
522
523 pub fn read_only(mut self) -> Self {
525 self.read_only_hint = Some(true);
526 self
527 }
528
529 pub fn destructive(mut self) -> Self {
531 self.destructive_hint = Some(true);
532 self
533 }
534
535 pub fn idempotent(mut self) -> Self {
537 self.idempotent_hint = Some(true);
538 self
539 }
540
541 pub fn open_world(mut self) -> Self {
543 self.open_world_hint = Some(true);
544 self
545 }
546
547 pub fn closed_world(mut self) -> Self {
549 self.open_world_hint = Some(false);
550 self
551 }
552}
553
554impl From<&crate::core::tool_metadata::ToolBehaviorHints> for ToolAnnotations {
559 fn from(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
560 Self {
561 title: None, read_only_hint: hints.read_only,
563 destructive_hint: hints.destructive,
564 idempotent_hint: hints.idempotent,
565 open_world_hint: if hints.requires_auth.unwrap_or(false)
567 || hints.resource_intensive.unwrap_or(false)
568 {
569 Some(true)
570 } else {
571 None
572 },
573 }
574 }
575}
576
577impl From<&crate::core::tool_metadata::EnhancedToolMetadata> for ToolAnnotations {
578 fn from(metadata: &crate::core::tool_metadata::EnhancedToolMetadata) -> Self {
579 ToolAnnotations::from(&metadata.behavior_hints)
580 }
581}
582
583impl ToolAnnotations {
584 pub fn from_enhanced_metadata(
586 metadata: &crate::core::tool_metadata::EnhancedToolMetadata,
587 title_override: Option<String>,
588 ) -> Self {
589 let mut annotations = Self::from(metadata);
590 if let Some(title) = title_override {
591 annotations.title = Some(title);
592 }
593 annotations
594 }
595
596 pub fn from_behavior_hints(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
598 Self::from(hints)
599 }
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
604pub struct Tool {
605 pub name: String,
607 #[serde(skip_serializing_if = "Option::is_none")]
609 pub description: Option<String>,
610 #[serde(rename = "inputSchema")]
612 pub input_schema: ToolInputSchema,
613 #[serde(skip_serializing_if = "Option::is_none")]
615 pub annotations: Option<ToolAnnotations>,
616 #[serde(skip_serializing_if = "Option::is_none")]
618 pub title: Option<String>,
619 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
621 pub meta: Option<HashMap<String, serde_json::Value>>,
622}
623
624#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
626pub struct ToolInputSchema {
627 #[serde(rename = "type")]
629 pub schema_type: String,
630 #[serde(skip_serializing_if = "Option::is_none")]
632 pub properties: Option<HashMap<String, serde_json::Value>>,
633 #[serde(skip_serializing_if = "Option::is_none")]
635 pub required: Option<Vec<String>>,
636 #[serde(flatten)]
638 pub additional_properties: HashMap<String, serde_json::Value>,
639}
640
641#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
643pub struct CallToolResult {
644 pub content: Vec<ContentBlock>,
646 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
648 pub is_error: Option<bool>,
649 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
651 pub structured_content: Option<serde_json::Value>,
652 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
654 pub meta: Option<HashMap<String, serde_json::Value>>,
655}
656
657pub type ToolInfo = Tool;
659pub type ToolResult = CallToolResult;
660
661#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
667pub struct Resource {
668 pub uri: String,
670 pub name: String,
672 #[serde(skip_serializing_if = "Option::is_none")]
674 pub description: Option<String>,
675 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
677 pub mime_type: Option<String>,
678 #[serde(skip_serializing_if = "Option::is_none")]
680 pub annotations: Option<Annotations>,
681 #[serde(skip_serializing_if = "Option::is_none")]
683 pub size: Option<u64>,
684 #[serde(skip_serializing_if = "Option::is_none")]
686 pub title: Option<String>,
687 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
689 pub meta: Option<HashMap<String, serde_json::Value>>,
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
694pub struct ResourceTemplate {
695 #[serde(rename = "uriTemplate")]
697 pub uri_template: String,
698 pub name: String,
700 #[serde(skip_serializing_if = "Option::is_none")]
702 pub description: Option<String>,
703 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
705 pub mime_type: Option<String>,
706 #[serde(skip_serializing_if = "Option::is_none")]
708 pub annotations: Option<Annotations>,
709 #[serde(skip_serializing_if = "Option::is_none")]
711 pub title: Option<String>,
712 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
714 pub meta: Option<HashMap<String, serde_json::Value>>,
715}
716
717#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
719#[serde(untagged)]
720pub enum ResourceContents {
721 Text {
723 uri: String,
725 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
727 mime_type: Option<String>,
728 text: String,
730 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
732 meta: Option<HashMap<String, serde_json::Value>>,
733 },
734 Blob {
736 uri: String,
738 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
740 mime_type: Option<String>,
741 blob: String,
743 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
745 meta: Option<HashMap<String, serde_json::Value>>,
746 },
747}
748
749impl ResourceContents {
750 pub fn uri(&self) -> &str {
752 match self {
753 ResourceContents::Text { uri, .. } => uri,
754 ResourceContents::Blob { uri, .. } => uri,
755 }
756 }
757}
758
759pub type ResourceInfo = Resource;
761
762#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
768pub struct Prompt {
769 pub name: String,
771 #[serde(skip_serializing_if = "Option::is_none")]
773 pub description: Option<String>,
774 #[serde(skip_serializing_if = "Option::is_none")]
776 pub arguments: Option<Vec<PromptArgument>>,
777 #[serde(skip_serializing_if = "Option::is_none")]
779 pub title: Option<String>,
780 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
782 pub meta: Option<HashMap<String, serde_json::Value>>,
783}
784
785#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
787pub struct PromptArgument {
788 pub name: String,
790 #[serde(skip_serializing_if = "Option::is_none")]
792 pub description: Option<String>,
793 #[serde(skip_serializing_if = "Option::is_none")]
795 pub required: Option<bool>,
796 #[serde(skip_serializing_if = "Option::is_none")]
798 pub title: Option<String>,
799}
800
801#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
803#[serde(rename_all = "lowercase")]
804pub enum Role {
805 User,
806 Assistant,
807}
808
809#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
811pub struct PromptMessage {
812 pub role: Role,
814 pub content: ContentBlock,
816}
817
818#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
820pub struct GetPromptResult {
821 #[serde(skip_serializing_if = "Option::is_none")]
823 pub description: Option<String>,
824 pub messages: Vec<PromptMessage>,
826 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
828 pub meta: Option<HashMap<String, serde_json::Value>>,
829}
830
831pub type PromptInfo = Prompt;
833pub type PromptResult = GetPromptResult;
834
835#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
841pub struct SamplingMessage {
842 pub role: Role,
844 pub content: SamplingContent,
846}
847
848#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
850#[serde(tag = "type")]
851pub enum SamplingContent {
852 #[serde(rename = "text")]
854 Text {
855 text: String,
857 #[serde(skip_serializing_if = "Option::is_none")]
859 annotations: Option<Annotations>,
860 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
862 meta: Option<HashMap<String, serde_json::Value>>,
863 },
864 #[serde(rename = "image")]
866 Image {
867 data: String,
869 #[serde(rename = "mimeType")]
871 mime_type: String,
872 #[serde(skip_serializing_if = "Option::is_none")]
874 annotations: Option<Annotations>,
875 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
877 meta: Option<HashMap<String, serde_json::Value>>,
878 },
879 #[serde(rename = "audio")]
881 Audio {
882 data: String,
884 #[serde(rename = "mimeType")]
886 mime_type: String,
887 #[serde(skip_serializing_if = "Option::is_none")]
889 annotations: Option<Annotations>,
890 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
892 meta: Option<HashMap<String, serde_json::Value>>,
893 },
894}
895
896#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
898pub struct ModelHint {
899 #[serde(skip_serializing_if = "Option::is_none")]
906 pub name: Option<String>,
907}
908
909#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
911pub struct ModelPreferences {
912 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
914 pub cost_priority: Option<f64>,
915 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
917 pub speed_priority: Option<f64>,
918 #[serde(
920 rename = "intelligencePriority",
921 skip_serializing_if = "Option::is_none"
922 )]
923 pub intelligence_priority: Option<f64>,
924 #[serde(skip_serializing_if = "Option::is_none")]
926 pub hints: Option<Vec<ModelHint>>,
927}
928
929#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
931pub struct CreateMessageResult {
932 pub role: Role,
934 pub content: SamplingContent,
936 pub model: String,
938 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
940 pub stop_reason: Option<StopReason>,
941 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
943 pub meta: Option<HashMap<String, serde_json::Value>>,
944}
945
946#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
948#[serde(rename_all = "camelCase")]
949pub enum StopReason {
950 EndTurn,
951 StopSequence,
952 MaxTokens,
953 #[serde(untagged)]
954 Other(String),
955}
956
957#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
963#[serde(tag = "type")]
964pub enum PrimitiveSchemaDefinition {
965 #[serde(rename = "string")]
966 String {
967 #[serde(skip_serializing_if = "Option::is_none")]
968 title: Option<String>,
969 #[serde(skip_serializing_if = "Option::is_none")]
970 description: Option<String>,
971 #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
972 min_length: Option<u32>,
973 #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
974 max_length: Option<u32>,
975 #[serde(skip_serializing_if = "Option::is_none")]
976 format: Option<String>,
977 #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
978 enum_values: Option<Vec<String>>,
979 #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
980 enum_names: Option<Vec<String>>,
981 },
982 #[serde(rename = "number")]
983 Number {
984 #[serde(skip_serializing_if = "Option::is_none")]
985 title: Option<String>,
986 #[serde(skip_serializing_if = "Option::is_none")]
987 description: Option<String>,
988 #[serde(skip_serializing_if = "Option::is_none")]
989 minimum: Option<i32>,
990 #[serde(skip_serializing_if = "Option::is_none")]
991 maximum: Option<i32>,
992 },
993 #[serde(rename = "integer")]
994 Integer {
995 #[serde(skip_serializing_if = "Option::is_none")]
996 title: Option<String>,
997 #[serde(skip_serializing_if = "Option::is_none")]
998 description: Option<String>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 minimum: Option<i32>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 maximum: Option<i32>,
1003 },
1004 #[serde(rename = "boolean")]
1005 Boolean {
1006 #[serde(skip_serializing_if = "Option::is_none")]
1007 title: Option<String>,
1008 #[serde(skip_serializing_if = "Option::is_none")]
1009 description: Option<String>,
1010 #[serde(skip_serializing_if = "Option::is_none")]
1011 default: Option<bool>,
1012 },
1013}
1014
1015#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1017pub struct ElicitationSchema {
1018 #[serde(rename = "type")]
1020 pub schema_type: String,
1021 pub properties: HashMap<String, PrimitiveSchemaDefinition>,
1023 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub required: Option<Vec<String>>,
1026}
1027
1028#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1030#[serde(rename_all = "lowercase")]
1031pub enum ElicitationAction {
1032 Accept,
1034 Decline,
1036 Cancel,
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1046#[serde(rename_all = "lowercase")]
1047pub enum LoggingLevel {
1048 Debug,
1049 Info,
1050 Notice,
1051 Warning,
1052 Error,
1053 Critical,
1054 Alert,
1055 Emergency,
1056}
1057
1058#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1064pub struct JsonRpcRequest {
1065 pub jsonrpc: String,
1067 pub id: RequestId,
1069 pub method: String,
1071 #[serde(skip_serializing_if = "Option::is_none")]
1073 pub params: Option<serde_json::Value>,
1074}
1075
1076#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1078pub struct JsonRpcResponse {
1079 pub jsonrpc: String,
1081 pub id: RequestId,
1083 #[serde(skip_serializing_if = "Option::is_none")]
1085 pub result: Option<serde_json::Value>,
1086}
1087
1088#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1090pub struct JsonRpcError {
1091 pub jsonrpc: String,
1093 pub id: RequestId,
1095 pub error: ErrorObject,
1097}
1098
1099#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1101pub struct ErrorObject {
1102 pub code: i32,
1104 pub message: String,
1106 #[serde(skip_serializing_if = "Option::is_none")]
1108 pub data: Option<serde_json::Value>,
1109}
1110
1111#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1113pub struct JsonRpcNotification {
1114 pub jsonrpc: String,
1116 pub method: String,
1118 #[serde(skip_serializing_if = "Option::is_none")]
1120 pub params: Option<serde_json::Value>,
1121}
1122
1123#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1125#[serde(untagged)]
1126pub enum JsonRpcMessage {
1127 Request(JsonRpcRequest),
1128 Response(JsonRpcResponse),
1129 Error(JsonRpcError),
1130 Notification(JsonRpcNotification),
1131}
1132
1133#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1139pub struct Request {
1140 pub method: String,
1142 #[serde(skip_serializing_if = "Option::is_none")]
1144 pub params: Option<RequestParams>,
1145}
1146
1147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1149pub struct RequestParams {
1150 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1152 pub meta: Option<RequestMeta>,
1153 #[serde(flatten)]
1155 pub params: HashMap<String, serde_json::Value>,
1156}
1157
1158#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1160pub struct RequestMeta {
1161 #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
1163 pub progress_token: Option<ProgressToken>,
1164}
1165
1166#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1168pub struct Notification {
1169 pub method: String,
1171 #[serde(skip_serializing_if = "Option::is_none")]
1173 pub params: Option<NotificationParams>,
1174}
1175
1176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1178pub struct NotificationParams {
1179 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1181 pub meta: Option<HashMap<String, serde_json::Value>>,
1182 #[serde(flatten)]
1184 pub params: HashMap<String, serde_json::Value>,
1185}
1186
1187#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1193pub struct PaginatedRequest {
1194 #[serde(skip_serializing_if = "Option::is_none")]
1196 pub cursor: Option<Cursor>,
1197}
1198
1199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1201pub struct PaginatedResult {
1202 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1204 pub next_cursor: Option<Cursor>,
1205}
1206
1207impl ContentBlock {
1212 pub fn text<S: Into<String>>(text: S) -> Self {
1214 Self::Text {
1215 text: text.into(),
1216 annotations: None,
1217 meta: None,
1218 }
1219 }
1220
1221 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1223 Self::Image {
1224 data: data.into(),
1225 mime_type: mime_type.into(),
1226 annotations: None,
1227 meta: None,
1228 }
1229 }
1230
1231 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1233 Self::Audio {
1234 data: data.into(),
1235 mime_type: mime_type.into(),
1236 annotations: None,
1237 meta: None,
1238 }
1239 }
1240
1241 pub fn resource_link<S: Into<String>>(uri: S, name: S) -> Self {
1243 Self::ResourceLink {
1244 uri: uri.into(),
1245 name: name.into(),
1246 description: None,
1247 mime_type: None,
1248 size: None,
1249 title: None,
1250 annotations: None,
1251 meta: None,
1252 }
1253 }
1254
1255 pub fn embedded_resource(resource: ResourceContents) -> Self {
1257 Self::Resource {
1258 resource,
1259 annotations: None,
1260 meta: None,
1261 }
1262 }
1263
1264 pub fn resource<S: Into<String>>(uri: S) -> Self {
1266 let uri_str = uri.into();
1267 Self::resource_link(uri_str.clone(), uri_str)
1268 }
1269}
1270
1271impl SamplingContent {
1272 pub fn text<S: Into<String>>(text: S) -> Self {
1274 Self::Text {
1275 text: text.into(),
1276 annotations: None,
1277 meta: None,
1278 }
1279 }
1280
1281 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1283 Self::Image {
1284 data: data.into(),
1285 mime_type: mime_type.into(),
1286 annotations: None,
1287 meta: None,
1288 }
1289 }
1290
1291 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1293 Self::Audio {
1294 data: data.into(),
1295 mime_type: mime_type.into(),
1296 annotations: None,
1297 meta: None,
1298 }
1299 }
1300}
1301
1302impl Annotations {
1303 pub fn new() -> Self {
1305 Self {
1306 audience: None,
1307 priority: None,
1308 last_modified: None,
1309 danger: None,
1310 destructive: None,
1311 read_only: None,
1312 }
1313 }
1314
1315 pub fn with_priority(mut self, priority: f64) -> Self {
1317 self.priority = Some(priority.clamp(0.0, 1.0));
1318 self
1319 }
1320
1321 pub fn for_audience(mut self, audience: Vec<Role>) -> Self {
1323 self.audience = Some(audience);
1324 self
1325 }
1326
1327 pub fn with_last_modified<S: Into<String>>(mut self, timestamp: S) -> Self {
1329 self.last_modified = Some(timestamp.into());
1330 self
1331 }
1332
1333 pub fn for_audience_legacy(self, _audience: Vec<AnnotationAudience>) -> Self {
1335 self
1337 }
1338
1339 pub fn with_danger_level(self, _level: DangerLevel) -> Self {
1341 self
1343 }
1344
1345 pub fn danger(&self) -> Option<DangerLevel> {
1347 None
1348 }
1349
1350 pub fn audience(&self) -> Option<Vec<AnnotationAudience>> {
1352 None
1353 }
1354
1355 pub fn read_only(mut self) -> Self {
1357 self.read_only = Some(true);
1358 self
1359 }
1360
1361 pub fn destructive(mut self, level: DangerLevel) -> Self {
1363 self.destructive = Some(true);
1364 self.danger = Some(level);
1365 self
1366 }
1367}
1368
1369impl Tool {
1370 pub fn new<S: Into<String>>(name: S, description: S) -> Self {
1372 Self {
1373 name: name.into(),
1374 description: Some(description.into()),
1375 input_schema: ToolInputSchema {
1376 schema_type: "object".to_string(),
1377 properties: None,
1378 required: None,
1379 additional_properties: HashMap::new(),
1380 },
1381 annotations: None,
1382 title: None,
1383 meta: None,
1384 }
1385 }
1386
1387 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1389 self.title = Some(title.into());
1390 self
1391 }
1392
1393 pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
1395 self.annotations = Some(annotations);
1396 self
1397 }
1398}
1399
1400impl Resource {
1401 pub fn new<S: Into<String>>(uri: S, name: S) -> Self {
1403 Self {
1404 uri: uri.into(),
1405 name: name.into(),
1406 description: None,
1407 mime_type: None,
1408 annotations: None,
1409 size: None,
1410 title: None,
1411 meta: None,
1412 }
1413 }
1414
1415 pub fn from_legacy<S: Into<String>>(uri: S, name: Option<S>) -> Self {
1417 Self {
1418 uri: uri.into(),
1419 name: name
1420 .map(|n| n.into())
1421 .unwrap_or_else(|| "Unnamed Resource".to_string()),
1422 description: None,
1423 mime_type: None,
1424 annotations: None,
1425 size: None,
1426 title: None,
1427 meta: None,
1428 }
1429 }
1430
1431 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1433 self.title = Some(title.into());
1434 self
1435 }
1436
1437 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1439 self.description = Some(description.into());
1440 self
1441 }
1442}
1443
1444impl ResourceTemplate {
1445 pub fn new<S: Into<String>>(uri_template: S, name: S) -> Self {
1447 Self {
1448 uri_template: uri_template.into(),
1449 name: name.into(),
1450 description: None,
1451 mime_type: None,
1452 annotations: None,
1453 title: None,
1454 meta: None,
1455 }
1456 }
1457
1458 pub fn from_legacy<S: Into<String>>(uri_template: S, name: Option<S>) -> Self {
1460 Self {
1461 uri_template: uri_template.into(),
1462 name: name
1463 .map(|n| n.into())
1464 .unwrap_or_else(|| "Unnamed Template".to_string()),
1465 description: None,
1466 mime_type: None,
1467 annotations: None,
1468 title: None,
1469 meta: None,
1470 }
1471 }
1472
1473 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1475 self.title = Some(title.into());
1476 self
1477 }
1478}
1479
1480impl Prompt {
1481 pub fn new<S: Into<String>>(name: S) -> Self {
1483 Self {
1484 name: name.into(),
1485 description: None,
1486 arguments: None,
1487 title: None,
1488 meta: None,
1489 }
1490 }
1491
1492 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1494 self.title = Some(title.into());
1495 self
1496 }
1497
1498 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1500 self.description = Some(description.into());
1501 self
1502 }
1503}
1504
1505impl PromptArgument {
1506 pub fn new<S: Into<String>>(name: S) -> Self {
1508 Self {
1509 name: name.into(),
1510 description: None,
1511 required: None,
1512 title: None,
1513 }
1514 }
1515
1516 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1518 self.title = Some(title.into());
1519 self
1520 }
1521
1522 pub fn required(mut self, required: bool) -> Self {
1524 self.required = Some(required);
1525 self
1526 }
1527}
1528
1529impl JsonRpcRequest {
1530 pub fn new<T: Serialize>(
1532 id: RequestId,
1533 method: String,
1534 params: Option<T>,
1535 ) -> std::result::Result<Self, serde_json::Error> {
1536 let params = match params {
1537 Some(p) => Some(serde_json::to_value(p)?),
1538 None => None,
1539 };
1540
1541 Ok(Self {
1542 jsonrpc: JSONRPC_VERSION.to_string(),
1543 id,
1544 method,
1545 params,
1546 })
1547 }
1548}
1549
1550impl JsonRpcResponse {
1551 pub fn success<T: Serialize>(
1553 id: RequestId,
1554 result: T,
1555 ) -> std::result::Result<Self, serde_json::Error> {
1556 Ok(Self {
1557 jsonrpc: JSONRPC_VERSION.to_string(),
1558 id,
1559 result: Some(serde_json::to_value(result)?),
1560 })
1561 }
1562}
1563
1564impl JsonRpcError {
1565 pub fn error(
1567 id: RequestId,
1568 code: i32,
1569 message: String,
1570 data: Option<serde_json::Value>,
1571 ) -> Self {
1572 Self {
1573 jsonrpc: JSONRPC_VERSION.to_string(),
1574 id,
1575 error: ErrorObject {
1576 code,
1577 message,
1578 data,
1579 },
1580 }
1581 }
1582}
1583
1584impl JsonRpcNotification {
1585 pub fn new<T: Serialize>(
1587 method: String,
1588 params: Option<T>,
1589 ) -> std::result::Result<Self, serde_json::Error> {
1590 let params = match params {
1591 Some(p) => Some(serde_json::to_value(p)?),
1592 None => None,
1593 };
1594
1595 Ok(Self {
1596 jsonrpc: JSONRPC_VERSION.to_string(),
1597 method,
1598 params,
1599 })
1600 }
1601}
1602
1603impl SamplingMessage {
1604 pub fn user_text<S: Into<String>>(text: S) -> Self {
1606 Self {
1607 role: Role::User,
1608 content: SamplingContent::text(text),
1609 }
1610 }
1611
1612 pub fn assistant_text<S: Into<String>>(text: S) -> Self {
1614 Self {
1615 role: Role::Assistant,
1616 content: SamplingContent::text(text),
1617 }
1618 }
1619
1620 pub fn user_image<S: Into<String>>(data: S, mime_type: S) -> Self {
1622 Self {
1623 role: Role::User,
1624 content: SamplingContent::image(data, mime_type),
1625 }
1626 }
1627
1628 pub fn user_audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1630 Self {
1631 role: Role::User,
1632 content: SamplingContent::audio(data, mime_type),
1633 }
1634 }
1635}
1636
1637pub mod error_codes {
1643 pub const PARSE_ERROR: i32 = -32700;
1645 pub const INVALID_REQUEST: i32 = -32600;
1647 pub const METHOD_NOT_FOUND: i32 = -32601;
1649 pub const INVALID_PARAMS: i32 = -32602;
1651 pub const INTERNAL_ERROR: i32 = -32603;
1653
1654 pub const TOOL_NOT_FOUND: i32 = -32000;
1656 pub const RESOURCE_NOT_FOUND: i32 = -32001;
1657 pub const PROMPT_NOT_FOUND: i32 = -32002;
1658}
1659
1660#[cfg(test)]
1661mod tests {
1662 use super::*;
1663 use serde_json::json;
1664
1665 #[test]
1666 fn test_protocol_version() {
1667 assert_eq!(LATEST_PROTOCOL_VERSION, "2025-06-18");
1668 assert_eq!(JSONRPC_VERSION, "2.0");
1669 }
1670
1671 #[test]
1672 fn test_content_block_types() {
1673 let text = ContentBlock::text("Hello, world!");
1675 let json = serde_json::to_value(&text).unwrap();
1676 assert_eq!(json["type"], "text");
1677 assert_eq!(json["text"], "Hello, world!");
1678
1679 let audio = ContentBlock::audio("base64data", "audio/wav");
1681 let json = serde_json::to_value(&audio).unwrap();
1682 assert_eq!(json["type"], "audio");
1683 assert_eq!(json["data"], "base64data");
1684 assert_eq!(json["mimeType"], "audio/wav");
1685
1686 let resource_link = ContentBlock::resource_link("file:///test.txt", "test file");
1688 let json = serde_json::to_value(&resource_link).unwrap();
1689 assert_eq!(json["type"], "resource_link");
1690 assert_eq!(json["uri"], "file:///test.txt");
1691 assert_eq!(json["name"], "test file");
1692 }
1693
1694 #[test]
1695 fn test_annotations() {
1696 let annotations = Annotations::new()
1697 .with_priority(0.8)
1698 .for_audience(vec![Role::User, Role::Assistant])
1699 .with_last_modified("2025-01-12T15:00:58Z");
1700
1701 assert_eq!(annotations.priority, Some(0.8));
1702 assert_eq!(
1703 annotations.audience,
1704 Some(vec![Role::User, Role::Assistant])
1705 );
1706 assert_eq!(
1707 annotations.last_modified,
1708 Some("2025-01-12T15:00:58Z".to_string())
1709 );
1710 }
1711
1712 #[test]
1713 fn test_tool_with_title() {
1714 let tool = Tool::new("file_reader", "Read files safely")
1715 .with_title("File Reader Tool")
1716 .with_annotations(ToolAnnotations::new().with_title("File Reader"));
1717
1718 assert_eq!(tool.name, "file_reader");
1719 assert_eq!(tool.title, Some("File Reader Tool".to_string()));
1720 assert!(tool.annotations.is_some());
1721 assert_eq!(
1722 tool.annotations.unwrap().title,
1723 Some("File Reader".to_string())
1724 );
1725 }
1726
1727 #[test]
1728 fn test_server_capabilities_2025_06_18() {
1729 let caps = ServerCapabilities {
1730 tools: Some(ToolsCapability {
1731 list_changed: Some(true),
1732 }),
1733 completions: Some(CompletionsCapability::default()),
1734 logging: Some(LoggingCapability::default()),
1735 experimental: Some(HashMap::new()),
1736 ..Default::default()
1737 };
1738
1739 let json = serde_json::to_value(&caps).unwrap();
1740 assert!(json["tools"]["listChanged"].as_bool().unwrap());
1741 assert!(json["completions"].is_object());
1742 assert!(json["logging"].is_object());
1743 assert!(json["experimental"].is_object());
1744 }
1745
1746 #[test]
1747 fn test_client_capabilities_with_elicitation() {
1748 let caps = ClientCapabilities {
1749 elicitation: Some(ElicitationCapability::default()),
1750 roots: Some(RootsCapability {
1751 list_changed: Some(true),
1752 }),
1753 ..Default::default()
1754 };
1755
1756 let json = serde_json::to_value(&caps).unwrap();
1757 assert!(json["elicitation"].is_object());
1758 assert!(json["roots"]["listChanged"].as_bool().unwrap());
1759 }
1760
1761 #[test]
1762 fn test_implementation_with_title() {
1763 let impl_info = Implementation::with_title("my-server", "1.0.0", "My Awesome Server");
1764
1765 assert_eq!(impl_info.name, "my-server");
1766 assert_eq!(impl_info.version, "1.0.0");
1767 assert_eq!(impl_info.title, Some("My Awesome Server".to_string()));
1768 }
1769
1770 #[test]
1771 fn test_model_preferences_enhanced() {
1772 let prefs = ModelPreferences {
1773 cost_priority: Some(0.3),
1774 speed_priority: Some(0.7),
1775 intelligence_priority: Some(0.9),
1776 hints: Some(vec![ModelHint {
1777 name: Some("claude".to_string()),
1778 }]),
1779 };
1780
1781 let json = serde_json::to_value(&prefs).unwrap();
1782 assert_eq!(json["costPriority"], 0.3);
1783 assert_eq!(json["speedPriority"], 0.7);
1784 assert_eq!(json["intelligencePriority"], 0.9);
1785 assert!(json["hints"].is_array());
1786 }
1787
1788 #[test]
1789 fn test_call_tool_result_with_structured_content() {
1790 let result = CallToolResult {
1791 content: vec![ContentBlock::text("Operation completed")],
1792 is_error: Some(false),
1793 structured_content: Some(json!({"status": "success", "count": 42})),
1794 meta: None,
1795 };
1796
1797 let json = serde_json::to_value(&result).unwrap();
1798 assert!(json["content"].is_array());
1799 assert_eq!(json["isError"], false);
1800 assert_eq!(json["structuredContent"]["status"], "success");
1801 assert_eq!(json["structuredContent"]["count"], 42);
1802 }
1803
1804 #[test]
1805 fn test_sampling_content_types() {
1806 let text = SamplingContent::text("Hello");
1808 let image = SamplingContent::image("data", "image/png");
1809 let audio = SamplingContent::audio("data", "audio/wav");
1810
1811 let text_json = serde_json::to_value(&text).unwrap();
1812 let image_json = serde_json::to_value(&image).unwrap();
1813 let audio_json = serde_json::to_value(&audio).unwrap();
1814
1815 assert_eq!(text_json["type"], "text");
1816 assert_eq!(image_json["type"], "image");
1817 assert_eq!(audio_json["type"], "audio");
1818 }
1819}
1820
1821pub type JsonRpcBatchRequest = Vec<JsonRpcRequest>;
1827
1828pub type JsonRpcBatchResponse = Vec<JsonRpcResponse>;
1830
1831#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1833#[serde(untagged)]
1834pub enum JsonRpcRequestOrNotification {
1835 Request(JsonRpcRequest),
1836 Notification(JsonRpcNotification),
1837}
1838
1839#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1841#[serde(untagged)]
1842pub enum JsonRpcResponseOrError {
1843 Response(JsonRpcResponse),
1844 Error(JsonRpcError),
1845}
1846
1847#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1849pub enum AnnotationAudience {
1850 User,
1851 Developer,
1852 System,
1853}
1854
1855#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1857pub enum DangerLevel {
1858 Safe,
1859 Low,
1860 Medium,
1861 High,
1862}