1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use crate::error::JsonRpcError;
10
11pub const JSONRPC_VERSION: &str = "2.0";
13
14pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
16
17pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct JsonRpcRequest {
23 pub jsonrpc: String,
25 pub id: RequestId,
27 pub method: String,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub params: Option<Value>,
32}
33
34impl JsonRpcRequest {
35 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
37 Self {
38 jsonrpc: JSONRPC_VERSION.to_string(),
39 id: id.into(),
40 method: method.into(),
41 params: None,
42 }
43 }
44
45 pub fn with_params(mut self, params: Value) -> Self {
47 self.params = Some(params);
48 self
49 }
50
51 pub fn validate(&self) -> Result<(), JsonRpcError> {
54 if self.jsonrpc != JSONRPC_VERSION {
55 return Err(JsonRpcError::invalid_request(format!(
56 "Invalid JSON-RPC version: expected '{}', got '{}'",
57 JSONRPC_VERSION, self.jsonrpc
58 )));
59 }
60 Ok(())
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct JsonRpcResultResponse {
67 pub jsonrpc: String,
69 pub id: RequestId,
71 pub result: Value,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct JsonRpcErrorResponse {
78 pub jsonrpc: String,
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub id: Option<RequestId>,
83 pub error: JsonRpcError,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(untagged)]
90pub enum JsonRpcResponse {
91 Result(JsonRpcResultResponse),
93 Error(JsonRpcErrorResponse),
95}
96
97impl JsonRpcResponse {
98 pub fn result(id: RequestId, result: Value) -> Self {
100 Self::Result(JsonRpcResultResponse {
101 jsonrpc: JSONRPC_VERSION.to_string(),
102 id,
103 result,
104 })
105 }
106
107 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
109 Self::Error(JsonRpcErrorResponse {
110 jsonrpc: JSONRPC_VERSION.to_string(),
111 id,
112 error,
113 })
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(untagged)]
120pub enum JsonRpcMessage {
121 Single(JsonRpcRequest),
123 Batch(Vec<JsonRpcRequest>),
125}
126
127impl JsonRpcMessage {
128 pub fn is_batch(&self) -> bool {
130 matches!(self, JsonRpcMessage::Batch(_))
131 }
132
133 pub fn len(&self) -> usize {
135 match self {
136 JsonRpcMessage::Single(_) => 1,
137 JsonRpcMessage::Batch(batch) => batch.len(),
138 }
139 }
140
141 pub fn is_empty(&self) -> bool {
143 self.len() == 0
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(untagged)]
150pub enum JsonRpcResponseMessage {
151 Single(JsonRpcResponse),
153 Batch(Vec<JsonRpcResponse>),
155}
156
157impl JsonRpcResponseMessage {
158 pub fn is_batch(&self) -> bool {
160 matches!(self, JsonRpcResponseMessage::Batch(_))
161 }
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct JsonRpcNotification {
167 pub jsonrpc: String,
168 pub method: String,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
170 pub params: Option<Value>,
171}
172
173impl JsonRpcNotification {
174 pub fn new(method: impl Into<String>) -> Self {
175 Self {
176 jsonrpc: JSONRPC_VERSION.to_string(),
177 method: method.into(),
178 params: None,
179 }
180 }
181
182 pub fn with_params(mut self, params: Value) -> Self {
183 self.params = Some(params);
184 self
185 }
186}
187
188pub mod notifications {
190 pub const INITIALIZED: &str = "notifications/initialized";
192 pub const CANCELLED: &str = "notifications/cancelled";
194 pub const PROGRESS: &str = "notifications/progress";
196 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
198 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
200 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
202 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
204 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
206 pub const MESSAGE: &str = "notifications/message";
208 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status_changed";
210 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
212}
213
214#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
218#[serde(rename_all = "lowercase")]
219pub enum LogLevel {
220 Emergency,
222 Alert,
224 Critical,
226 Error,
228 Warning,
230 Notice,
232 #[default]
234 Info,
235 Debug,
237}
238
239impl std::fmt::Display for LogLevel {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 match self {
242 LogLevel::Emergency => write!(f, "emergency"),
243 LogLevel::Alert => write!(f, "alert"),
244 LogLevel::Critical => write!(f, "critical"),
245 LogLevel::Error => write!(f, "error"),
246 LogLevel::Warning => write!(f, "warning"),
247 LogLevel::Notice => write!(f, "notice"),
248 LogLevel::Info => write!(f, "info"),
249 LogLevel::Debug => write!(f, "debug"),
250 }
251 }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct LoggingMessageParams {
257 pub level: LogLevel,
259 #[serde(skip_serializing_if = "Option::is_none")]
261 pub logger: Option<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
264 pub data: Option<Value>,
265}
266
267impl LoggingMessageParams {
268 pub fn new(level: LogLevel) -> Self {
270 Self {
271 level,
272 logger: None,
273 data: None,
274 }
275 }
276
277 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
279 self.logger = Some(logger.into());
280 self
281 }
282
283 pub fn with_data(mut self, data: Value) -> Self {
285 self.data = Some(data);
286 self
287 }
288}
289
290#[derive(Debug, Clone, Deserialize)]
292pub struct SetLogLevelParams {
293 pub level: LogLevel,
295}
296
297#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
299#[serde(untagged)]
300pub enum RequestId {
301 String(String),
302 Number(i64),
303}
304
305impl From<String> for RequestId {
306 fn from(s: String) -> Self {
307 RequestId::String(s)
308 }
309}
310
311impl From<&str> for RequestId {
312 fn from(s: &str) -> Self {
313 RequestId::String(s.to_string())
314 }
315}
316
317impl From<i64> for RequestId {
318 fn from(n: i64) -> Self {
319 RequestId::Number(n)
320 }
321}
322
323impl From<i32> for RequestId {
324 fn from(n: i32) -> Self {
325 RequestId::Number(n as i64)
326 }
327}
328
329#[derive(Debug, Clone)]
335pub enum McpRequest {
336 Initialize(InitializeParams),
338 ListTools(ListToolsParams),
340 CallTool(CallToolParams),
342 ListResources(ListResourcesParams),
344 ListResourceTemplates(ListResourceTemplatesParams),
346 ReadResource(ReadResourceParams),
348 SubscribeResource(SubscribeResourceParams),
350 UnsubscribeResource(UnsubscribeResourceParams),
352 ListPrompts(ListPromptsParams),
354 GetPrompt(GetPromptParams),
356 EnqueueTask(EnqueueTaskParams),
358 ListTasks(ListTasksParams),
360 GetTaskInfo(GetTaskInfoParams),
362 GetTaskResult(GetTaskResultParams),
364 CancelTask(CancelTaskParams),
366 Ping,
368 SetLoggingLevel(SetLogLevelParams),
370 Complete(CompleteParams),
372 Unknown {
374 method: String,
375 params: Option<Value>,
376 },
377}
378
379impl McpRequest {
380 pub fn method_name(&self) -> &str {
382 match self {
383 McpRequest::Initialize(_) => "initialize",
384 McpRequest::ListTools(_) => "tools/list",
385 McpRequest::CallTool(_) => "tools/call",
386 McpRequest::ListResources(_) => "resources/list",
387 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
388 McpRequest::ReadResource(_) => "resources/read",
389 McpRequest::SubscribeResource(_) => "resources/subscribe",
390 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
391 McpRequest::ListPrompts(_) => "prompts/list",
392 McpRequest::GetPrompt(_) => "prompts/get",
393 McpRequest::EnqueueTask(_) => "tasks/enqueue",
394 McpRequest::ListTasks(_) => "tasks/list",
395 McpRequest::GetTaskInfo(_) => "tasks/get",
396 McpRequest::GetTaskResult(_) => "tasks/result",
397 McpRequest::CancelTask(_) => "tasks/cancel",
398 McpRequest::Ping => "ping",
399 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
400 McpRequest::Complete(_) => "completion/complete",
401 McpRequest::Unknown { method, .. } => method,
402 }
403 }
404}
405
406#[derive(Debug, Clone)]
408pub enum McpNotification {
409 Initialized,
411 Cancelled(CancelledParams),
413 Progress(ProgressParams),
415 RootsListChanged,
417 Unknown {
419 method: String,
420 params: Option<Value>,
421 },
422}
423
424#[derive(Debug, Clone, Serialize, Deserialize)]
426#[serde(rename_all = "camelCase")]
427pub struct CancelledParams {
428 pub request_id: RequestId,
430 #[serde(skip_serializing_if = "Option::is_none")]
432 pub reason: Option<String>,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct ProgressParams {
439 pub progress_token: ProgressToken,
441 pub progress: f64,
443 #[serde(skip_serializing_if = "Option::is_none")]
445 pub total: Option<f64>,
446 #[serde(skip_serializing_if = "Option::is_none")]
448 pub message: Option<String>,
449}
450
451#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
453#[serde(untagged)]
454pub enum ProgressToken {
455 String(String),
456 Number(i64),
457}
458
459#[derive(Debug, Clone, Default, Serialize, Deserialize)]
461#[serde(rename_all = "camelCase")]
462pub struct RequestMeta {
463 #[serde(skip_serializing_if = "Option::is_none")]
465 pub progress_token: Option<ProgressToken>,
466}
467
468#[derive(Debug, Clone, Serialize)]
470#[serde(untagged)]
471pub enum McpResponse {
472 Initialize(InitializeResult),
473 ListTools(ListToolsResult),
474 CallTool(CallToolResult),
475 ListResources(ListResourcesResult),
476 ListResourceTemplates(ListResourceTemplatesResult),
477 ReadResource(ReadResourceResult),
478 SubscribeResource(EmptyResult),
479 UnsubscribeResource(EmptyResult),
480 ListPrompts(ListPromptsResult),
481 GetPrompt(GetPromptResult),
482 EnqueueTask(EnqueueTaskResult),
483 ListTasks(ListTasksResult),
484 GetTaskInfo(TaskInfo),
485 GetTaskResult(GetTaskResultResult),
486 CancelTask(CancelTaskResult),
487 SetLoggingLevel(EmptyResult),
488 Complete(CompleteResult),
489 Pong(EmptyResult),
490 Empty(EmptyResult),
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize)]
498#[serde(rename_all = "camelCase")]
499pub struct InitializeParams {
500 pub protocol_version: String,
501 pub capabilities: ClientCapabilities,
502 pub client_info: Implementation,
503}
504
505#[derive(Debug, Clone, Default, Deserialize, Serialize)]
506pub struct ClientCapabilities {
507 #[serde(default, skip_serializing_if = "Option::is_none")]
508 pub roots: Option<RootsCapability>,
509 #[serde(default, skip_serializing_if = "Option::is_none")]
510 pub sampling: Option<SamplingCapability>,
511 #[serde(default, skip_serializing_if = "Option::is_none")]
512 pub elicitation: Option<ElicitationCapability>,
513}
514
515#[derive(Debug, Clone, Default, Deserialize, Serialize)]
517pub struct ElicitationCapability {
518 #[serde(default, skip_serializing_if = "Option::is_none")]
520 pub form: Option<ElicitationFormCapability>,
521 #[serde(default, skip_serializing_if = "Option::is_none")]
523 pub url: Option<ElicitationUrlCapability>,
524}
525
526#[derive(Debug, Clone, Default, Deserialize, Serialize)]
528pub struct ElicitationFormCapability {}
529
530#[derive(Debug, Clone, Default, Deserialize, Serialize)]
532pub struct ElicitationUrlCapability {}
533
534#[derive(Debug, Clone, Default, Deserialize, Serialize)]
536#[serde(rename_all = "camelCase")]
537pub struct RootsCapability {
538 #[serde(default)]
540 pub list_changed: bool,
541}
542
543#[derive(Debug, Clone, Deserialize, Serialize)]
550pub struct Root {
551 pub uri: String,
553 #[serde(default, skip_serializing_if = "Option::is_none")]
555 pub name: Option<String>,
556}
557
558impl Root {
559 pub fn new(uri: impl Into<String>) -> Self {
561 Self {
562 uri: uri.into(),
563 name: None,
564 }
565 }
566
567 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
569 Self {
570 uri: uri.into(),
571 name: Some(name.into()),
572 }
573 }
574}
575
576#[derive(Debug, Clone, Default, Deserialize, Serialize)]
578pub struct ListRootsParams {
579 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
581 pub meta: Option<RequestMeta>,
582}
583
584#[derive(Debug, Clone, Deserialize, Serialize)]
586pub struct ListRootsResult {
587 pub roots: Vec<Root>,
589}
590
591#[derive(Debug, Clone, Default, Deserialize, Serialize)]
592pub struct SamplingCapability {}
593
594#[derive(Debug, Clone, Default, Deserialize, Serialize)]
596pub struct CompletionsCapability {}
597
598#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct PromptReference {
605 #[serde(rename = "type")]
607 pub ref_type: String,
608 pub name: String,
610}
611
612impl PromptReference {
613 pub fn new(name: impl Into<String>) -> Self {
615 Self {
616 ref_type: "ref/prompt".to_string(),
617 name: name.into(),
618 }
619 }
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize)]
624pub struct ResourceReference {
625 #[serde(rename = "type")]
627 pub ref_type: String,
628 pub uri: String,
630}
631
632impl ResourceReference {
633 pub fn new(uri: impl Into<String>) -> Self {
635 Self {
636 ref_type: "ref/resource".to_string(),
637 uri: uri.into(),
638 }
639 }
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize)]
644#[serde(tag = "type")]
645pub enum CompletionReference {
646 #[serde(rename = "ref/prompt")]
648 Prompt {
649 name: String,
651 },
652 #[serde(rename = "ref/resource")]
654 Resource {
655 uri: String,
657 },
658}
659
660impl CompletionReference {
661 pub fn prompt(name: impl Into<String>) -> Self {
663 Self::Prompt { name: name.into() }
664 }
665
666 pub fn resource(uri: impl Into<String>) -> Self {
668 Self::Resource { uri: uri.into() }
669 }
670}
671
672#[derive(Debug, Clone, Serialize, Deserialize)]
674pub struct CompletionArgument {
675 pub name: String,
677 pub value: String,
679}
680
681impl CompletionArgument {
682 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
684 Self {
685 name: name.into(),
686 value: value.into(),
687 }
688 }
689}
690
691#[derive(Debug, Clone, Serialize, Deserialize)]
693#[serde(rename_all = "camelCase")]
694pub struct CompleteParams {
695 #[serde(rename = "ref")]
697 pub reference: CompletionReference,
698 pub argument: CompletionArgument,
700}
701
702#[derive(Debug, Clone, Serialize, Deserialize)]
704#[serde(rename_all = "camelCase")]
705pub struct Completion {
706 pub values: Vec<String>,
708 #[serde(default, skip_serializing_if = "Option::is_none")]
710 pub total: Option<u32>,
711 #[serde(default, skip_serializing_if = "Option::is_none")]
713 pub has_more: Option<bool>,
714}
715
716impl Completion {
717 pub fn new(values: Vec<String>) -> Self {
719 Self {
720 values,
721 total: None,
722 has_more: None,
723 }
724 }
725
726 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
728 Self {
729 values,
730 total: Some(total),
731 has_more: Some(has_more),
732 }
733 }
734}
735
736#[derive(Debug, Clone, Serialize, Deserialize)]
738pub struct CompleteResult {
739 pub completion: Completion,
741}
742
743impl CompleteResult {
744 pub fn new(values: Vec<String>) -> Self {
746 Self {
747 completion: Completion::new(values),
748 }
749 }
750
751 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
753 Self {
754 completion: Completion::with_pagination(values, total, has_more),
755 }
756 }
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
765pub struct ModelHint {
766 pub name: String,
768}
769
770impl ModelHint {
771 pub fn new(name: impl Into<String>) -> Self {
773 Self { name: name.into() }
774 }
775}
776
777#[derive(Debug, Clone, Default, Serialize, Deserialize)]
779#[serde(rename_all = "camelCase")]
780pub struct ModelPreferences {
781 #[serde(default, skip_serializing_if = "Option::is_none")]
783 pub speed_priority: Option<f64>,
784 #[serde(default, skip_serializing_if = "Option::is_none")]
786 pub intelligence_priority: Option<f64>,
787 #[serde(default, skip_serializing_if = "Option::is_none")]
789 pub cost_priority: Option<f64>,
790 #[serde(default, skip_serializing_if = "Vec::is_empty")]
792 pub hints: Vec<ModelHint>,
793}
794
795impl ModelPreferences {
796 pub fn new() -> Self {
798 Self::default()
799 }
800
801 pub fn speed(mut self, priority: f64) -> Self {
803 self.speed_priority = Some(priority.clamp(0.0, 1.0));
804 self
805 }
806
807 pub fn intelligence(mut self, priority: f64) -> Self {
809 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
810 self
811 }
812
813 pub fn cost(mut self, priority: f64) -> Self {
815 self.cost_priority = Some(priority.clamp(0.0, 1.0));
816 self
817 }
818
819 pub fn hint(mut self, name: impl Into<String>) -> Self {
821 self.hints.push(ModelHint::new(name));
822 self
823 }
824}
825
826#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
828#[serde(rename_all = "camelCase")]
829pub enum IncludeContext {
830 AllServers,
832 ThisServer,
834 #[default]
836 None,
837}
838
839#[derive(Debug, Clone, Serialize, Deserialize)]
841pub struct SamplingMessage {
842 pub role: ContentRole,
844 pub content: SamplingContent,
846}
847
848impl SamplingMessage {
849 pub fn user(text: impl Into<String>) -> Self {
851 Self {
852 role: ContentRole::User,
853 content: SamplingContent::Text { text: text.into() },
854 }
855 }
856
857 pub fn assistant(text: impl Into<String>) -> Self {
859 Self {
860 role: ContentRole::Assistant,
861 content: SamplingContent::Text { text: text.into() },
862 }
863 }
864}
865
866#[derive(Debug, Clone, Serialize, Deserialize)]
870#[serde(rename_all = "camelCase")]
871pub struct SamplingTool {
872 pub name: String,
874 #[serde(skip_serializing_if = "Option::is_none")]
876 pub description: Option<String>,
877 pub input_schema: Value,
879}
880
881#[derive(Debug, Clone, Serialize, Deserialize)]
885#[serde(rename_all = "camelCase")]
886pub struct ToolChoice {
887 #[serde(rename = "type")]
892 pub mode: String,
893}
894
895impl ToolChoice {
896 pub fn auto() -> Self {
898 Self {
899 mode: "auto".to_string(),
900 }
901 }
902
903 pub fn required() -> Self {
905 Self {
906 mode: "required".to_string(),
907 }
908 }
909
910 pub fn none() -> Self {
912 Self {
913 mode: "none".to_string(),
914 }
915 }
916}
917
918#[derive(Debug, Clone, Serialize, Deserialize)]
920#[serde(tag = "type", rename_all = "lowercase")]
921pub enum SamplingContent {
922 Text {
924 text: String,
926 },
927 Image {
929 data: String,
931 #[serde(rename = "mimeType")]
933 mime_type: String,
934 },
935 Audio {
937 data: String,
939 #[serde(rename = "mimeType")]
941 mime_type: String,
942 },
943 #[serde(rename = "tool_use")]
945 ToolUse {
946 id: String,
948 name: String,
950 input: Value,
952 },
953 #[serde(rename = "tool_result")]
955 ToolResult {
956 tool_use_id: String,
958 content: Vec<SamplingContent>,
960 #[serde(default, skip_serializing_if = "Option::is_none")]
962 is_error: Option<bool>,
963 },
964}
965
966#[derive(Debug, Clone, Serialize, Deserialize)]
971#[serde(untagged)]
972pub enum SamplingContentOrArray {
973 Single(SamplingContent),
975 Array(Vec<SamplingContent>),
977}
978
979impl SamplingContentOrArray {
980 pub fn items(&self) -> Vec<&SamplingContent> {
982 match self {
983 Self::Single(c) => vec![c],
984 Self::Array(arr) => arr.iter().collect(),
985 }
986 }
987
988 pub fn into_items(self) -> Vec<SamplingContent> {
990 match self {
991 Self::Single(c) => vec![c],
992 Self::Array(arr) => arr,
993 }
994 }
995}
996
997#[derive(Debug, Clone, Serialize, Deserialize)]
999#[serde(rename_all = "camelCase")]
1000pub struct CreateMessageParams {
1001 pub messages: Vec<SamplingMessage>,
1003 pub max_tokens: u32,
1005 #[serde(default, skip_serializing_if = "Option::is_none")]
1007 pub system_prompt: Option<String>,
1008 #[serde(default, skip_serializing_if = "Option::is_none")]
1010 pub temperature: Option<f64>,
1011 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1013 pub stop_sequences: Vec<String>,
1014 #[serde(default, skip_serializing_if = "Option::is_none")]
1016 pub model_preferences: Option<ModelPreferences>,
1017 #[serde(default, skip_serializing_if = "Option::is_none")]
1019 pub include_context: Option<IncludeContext>,
1020 #[serde(default, skip_serializing_if = "Option::is_none")]
1022 pub metadata: Option<serde_json::Map<String, Value>>,
1023 #[serde(default, skip_serializing_if = "Option::is_none")]
1025 pub tools: Option<Vec<SamplingTool>>,
1026 #[serde(default, skip_serializing_if = "Option::is_none")]
1028 pub tool_choice: Option<ToolChoice>,
1029}
1030
1031impl CreateMessageParams {
1032 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1034 Self {
1035 messages,
1036 max_tokens,
1037 system_prompt: None,
1038 temperature: None,
1039 stop_sequences: Vec::new(),
1040 model_preferences: None,
1041 include_context: None,
1042 metadata: None,
1043 tools: None,
1044 tool_choice: None,
1045 }
1046 }
1047
1048 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1050 self.system_prompt = Some(prompt.into());
1051 self
1052 }
1053
1054 pub fn temperature(mut self, temp: f64) -> Self {
1056 self.temperature = Some(temp.clamp(0.0, 1.0));
1057 self
1058 }
1059
1060 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1062 self.stop_sequences.push(seq.into());
1063 self
1064 }
1065
1066 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1068 self.model_preferences = Some(prefs);
1069 self
1070 }
1071
1072 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1074 self.include_context = Some(mode);
1075 self
1076 }
1077
1078 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1080 self.tools = Some(tools);
1081 self
1082 }
1083
1084 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1086 self.tool_choice = Some(choice);
1087 self
1088 }
1089}
1090
1091#[derive(Debug, Clone, Serialize, Deserialize)]
1093#[serde(rename_all = "camelCase")]
1094pub struct CreateMessageResult {
1095 pub content: SamplingContentOrArray,
1097 pub model: String,
1099 pub role: ContentRole,
1101 #[serde(default, skip_serializing_if = "Option::is_none")]
1103 pub stop_reason: Option<String>,
1104}
1105
1106impl CreateMessageResult {
1107 pub fn content_items(&self) -> Vec<&SamplingContent> {
1109 self.content.items()
1110 }
1111}
1112
1113#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1115#[serde(rename_all = "camelCase")]
1116pub struct Implementation {
1117 pub name: String,
1119 pub version: String,
1121 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub title: Option<String>,
1124 #[serde(skip_serializing_if = "Option::is_none")]
1126 pub description: Option<String>,
1127 #[serde(skip_serializing_if = "Option::is_none")]
1129 pub icons: Option<Vec<ToolIcon>>,
1130 #[serde(skip_serializing_if = "Option::is_none")]
1132 pub website_url: Option<String>,
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize)]
1136#[serde(rename_all = "camelCase")]
1137pub struct InitializeResult {
1138 pub protocol_version: String,
1139 pub capabilities: ServerCapabilities,
1140 pub server_info: Implementation,
1141 #[serde(skip_serializing_if = "Option::is_none")]
1144 pub instructions: Option<String>,
1145}
1146
1147#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1148#[serde(rename_all = "camelCase")]
1149pub struct ServerCapabilities {
1150 #[serde(default, skip_serializing_if = "Option::is_none")]
1151 pub tools: Option<ToolsCapability>,
1152 #[serde(default, skip_serializing_if = "Option::is_none")]
1153 pub resources: Option<ResourcesCapability>,
1154 #[serde(default, skip_serializing_if = "Option::is_none")]
1155 pub prompts: Option<PromptsCapability>,
1156 #[serde(default, skip_serializing_if = "Option::is_none")]
1158 pub logging: Option<LoggingCapability>,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1160 pub tasks: Option<TasksCapability>,
1161 #[serde(default, skip_serializing_if = "Option::is_none")]
1163 pub completions: Option<CompletionsCapability>,
1164}
1165
1166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1168pub struct LoggingCapability {}
1169
1170#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1172#[serde(rename_all = "camelCase")]
1173pub struct TasksCapability {
1174 #[serde(default, skip_serializing_if = "Option::is_none")]
1176 pub default_poll_interval: Option<u64>,
1177}
1178
1179#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1180#[serde(rename_all = "camelCase")]
1181pub struct ToolsCapability {
1182 #[serde(default)]
1183 pub list_changed: bool,
1184}
1185
1186#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1187#[serde(rename_all = "camelCase")]
1188pub struct ResourcesCapability {
1189 #[serde(default)]
1190 pub subscribe: bool,
1191 #[serde(default)]
1192 pub list_changed: bool,
1193}
1194
1195#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1196#[serde(rename_all = "camelCase")]
1197pub struct PromptsCapability {
1198 #[serde(default)]
1199 pub list_changed: bool,
1200}
1201
1202#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1207pub struct ListToolsParams {
1208 #[serde(default)]
1209 pub cursor: Option<String>,
1210}
1211
1212#[derive(Debug, Clone, Serialize, Deserialize)]
1213#[serde(rename_all = "camelCase")]
1214pub struct ListToolsResult {
1215 pub tools: Vec<ToolDefinition>,
1216 #[serde(default, skip_serializing_if = "Option::is_none")]
1217 pub next_cursor: Option<String>,
1218}
1219
1220#[derive(Debug, Clone, Serialize, Deserialize)]
1222#[serde(rename_all = "camelCase")]
1223pub struct ToolDefinition {
1224 pub name: String,
1225 #[serde(skip_serializing_if = "Option::is_none")]
1227 pub title: Option<String>,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1229 pub description: Option<String>,
1230 pub input_schema: Value,
1231 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub output_schema: Option<Value>,
1234 #[serde(skip_serializing_if = "Option::is_none")]
1236 pub icons: Option<Vec<ToolIcon>>,
1237 #[serde(skip_serializing_if = "Option::is_none")]
1240 pub annotations: Option<ToolAnnotations>,
1241}
1242
1243#[derive(Debug, Clone, Serialize, Deserialize)]
1245#[serde(rename_all = "camelCase")]
1246pub struct ToolIcon {
1247 pub src: String,
1249 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub mime_type: Option<String>,
1252 #[serde(skip_serializing_if = "Option::is_none")]
1254 pub sizes: Option<Vec<String>>,
1255}
1256
1257#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1260#[serde(rename_all = "camelCase")]
1261pub struct ToolAnnotations {
1262 #[serde(skip_serializing_if = "Option::is_none")]
1264 pub title: Option<String>,
1265 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1267 pub read_only_hint: bool,
1268 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1271 pub destructive_hint: bool,
1272 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1275 pub idempotent_hint: bool,
1276 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1278 pub open_world_hint: bool,
1279}
1280
1281fn default_true() -> bool {
1282 true
1283}
1284
1285fn is_true(v: &bool) -> bool {
1286 *v
1287}
1288
1289#[derive(Debug, Clone, Serialize, Deserialize)]
1290pub struct CallToolParams {
1291 pub name: String,
1292 #[serde(default)]
1293 pub arguments: Value,
1294 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1296 pub meta: Option<RequestMeta>,
1297}
1298
1299#[derive(Debug, Clone, Serialize, Deserialize)]
1320#[serde(rename_all = "camelCase")]
1321pub struct CallToolResult {
1322 pub content: Vec<Content>,
1324 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1326 pub is_error: bool,
1327 #[serde(default, skip_serializing_if = "Option::is_none")]
1329 pub structured_content: Option<Value>,
1330}
1331
1332impl CallToolResult {
1333 pub fn text(text: impl Into<String>) -> Self {
1337 Self {
1338 content: vec![Content::Text {
1339 text: text.into(),
1340 annotations: None,
1341 }],
1342 is_error: false,
1343 structured_content: None,
1344 }
1345 }
1346
1347 pub fn error(message: impl Into<String>) -> Self {
1352 Self {
1353 content: vec![Content::Text {
1354 text: message.into(),
1355 annotations: None,
1356 }],
1357 is_error: true,
1358 structured_content: None,
1359 }
1360 }
1361
1362 pub fn json(value: Value) -> Self {
1367 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1368 Self {
1369 content: vec![Content::Text {
1370 text,
1371 annotations: None,
1372 }],
1373 is_error: false,
1374 structured_content: Some(value),
1375 }
1376 }
1377
1378 pub fn from_serialize(
1410 value: &impl serde::Serialize,
1411 ) -> std::result::Result<Self, crate::error::Error> {
1412 let json_value = serde_json::to_value(value)
1413 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1414 Ok(Self::json(json_value))
1415 }
1416
1417 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1419 Self {
1420 content: vec![Content::Image {
1421 data: data.into(),
1422 mime_type: mime_type.into(),
1423 annotations: None,
1424 }],
1425 is_error: false,
1426 structured_content: None,
1427 }
1428 }
1429
1430 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1432 Self {
1433 content: vec![Content::Audio {
1434 data: data.into(),
1435 mime_type: mime_type.into(),
1436 annotations: None,
1437 }],
1438 is_error: false,
1439 structured_content: None,
1440 }
1441 }
1442
1443 pub fn resource_link(uri: impl Into<String>) -> Self {
1445 Self {
1446 content: vec![Content::ResourceLink {
1447 uri: uri.into(),
1448 name: None,
1449 description: None,
1450 mime_type: None,
1451 annotations: None,
1452 }],
1453 is_error: false,
1454 structured_content: None,
1455 }
1456 }
1457
1458 pub fn resource_link_with_meta(
1460 uri: impl Into<String>,
1461 name: Option<String>,
1462 description: Option<String>,
1463 mime_type: Option<String>,
1464 ) -> Self {
1465 Self {
1466 content: vec![Content::ResourceLink {
1467 uri: uri.into(),
1468 name,
1469 description,
1470 mime_type,
1471 annotations: None,
1472 }],
1473 is_error: false,
1474 structured_content: None,
1475 }
1476 }
1477
1478 pub fn resource(resource: ResourceContent) -> Self {
1480 Self {
1481 content: vec![Content::Resource {
1482 resource,
1483 annotations: None,
1484 }],
1485 is_error: false,
1486 structured_content: None,
1487 }
1488 }
1489
1490 pub fn all_text(&self) -> String {
1504 self.content.iter().filter_map(|c| c.as_text()).collect()
1505 }
1506
1507 pub fn first_text(&self) -> Option<&str> {
1520 self.content.iter().find_map(|c| c.as_text())
1521 }
1522}
1523
1524#[derive(Debug, Clone, Serialize, Deserialize)]
1529#[serde(tag = "type", rename_all = "snake_case")]
1530pub enum Content {
1531 Text {
1533 text: String,
1535 #[serde(skip_serializing_if = "Option::is_none")]
1537 annotations: Option<ContentAnnotations>,
1538 },
1539 Image {
1541 data: String,
1543 #[serde(rename = "mimeType")]
1545 mime_type: String,
1546 #[serde(skip_serializing_if = "Option::is_none")]
1548 annotations: Option<ContentAnnotations>,
1549 },
1550 Audio {
1552 data: String,
1554 #[serde(rename = "mimeType")]
1556 mime_type: String,
1557 #[serde(skip_serializing_if = "Option::is_none")]
1559 annotations: Option<ContentAnnotations>,
1560 },
1561 Resource {
1563 resource: ResourceContent,
1565 #[serde(skip_serializing_if = "Option::is_none")]
1567 annotations: Option<ContentAnnotations>,
1568 },
1569 ResourceLink {
1571 uri: String,
1573 #[serde(skip_serializing_if = "Option::is_none")]
1575 name: Option<String>,
1576 #[serde(skip_serializing_if = "Option::is_none")]
1578 description: Option<String>,
1579 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1581 mime_type: Option<String>,
1582 #[serde(skip_serializing_if = "Option::is_none")]
1583 annotations: Option<ContentAnnotations>,
1584 },
1585}
1586
1587#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1589pub struct ContentAnnotations {
1590 #[serde(skip_serializing_if = "Option::is_none")]
1592 pub audience: Option<Vec<ContentRole>>,
1593 #[serde(skip_serializing_if = "Option::is_none")]
1595 pub priority: Option<f64>,
1596}
1597
1598impl Content {
1599 pub fn as_text(&self) -> Option<&str> {
1612 match self {
1613 Content::Text { text, .. } => Some(text),
1614 _ => None,
1615 }
1616 }
1617}
1618
1619#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1623#[serde(rename_all = "lowercase")]
1624pub enum ContentRole {
1625 User,
1627 Assistant,
1629}
1630
1631#[derive(Debug, Clone, Serialize, Deserialize)]
1635#[serde(rename_all = "camelCase")]
1636pub struct ResourceContent {
1637 pub uri: String,
1639 #[serde(skip_serializing_if = "Option::is_none")]
1641 pub mime_type: Option<String>,
1642 #[serde(skip_serializing_if = "Option::is_none")]
1644 pub text: Option<String>,
1645 #[serde(skip_serializing_if = "Option::is_none")]
1647 pub blob: Option<String>,
1648}
1649
1650#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1655pub struct ListResourcesParams {
1656 #[serde(default)]
1657 pub cursor: Option<String>,
1658}
1659
1660#[derive(Debug, Clone, Serialize, Deserialize)]
1661#[serde(rename_all = "camelCase")]
1662pub struct ListResourcesResult {
1663 pub resources: Vec<ResourceDefinition>,
1664 #[serde(default, skip_serializing_if = "Option::is_none")]
1665 pub next_cursor: Option<String>,
1666}
1667
1668#[derive(Debug, Clone, Serialize, Deserialize)]
1669#[serde(rename_all = "camelCase")]
1670pub struct ResourceDefinition {
1671 pub uri: String,
1672 pub name: String,
1673 #[serde(skip_serializing_if = "Option::is_none")]
1675 pub title: Option<String>,
1676 #[serde(skip_serializing_if = "Option::is_none")]
1677 pub description: Option<String>,
1678 #[serde(skip_serializing_if = "Option::is_none")]
1679 pub mime_type: Option<String>,
1680 #[serde(skip_serializing_if = "Option::is_none")]
1682 pub icons: Option<Vec<ToolIcon>>,
1683 #[serde(skip_serializing_if = "Option::is_none")]
1685 pub size: Option<u64>,
1686}
1687
1688#[derive(Debug, Clone, Serialize, Deserialize)]
1689pub struct ReadResourceParams {
1690 pub uri: String,
1691}
1692
1693#[derive(Debug, Clone, Serialize, Deserialize)]
1694pub struct ReadResourceResult {
1695 pub contents: Vec<ResourceContent>,
1696}
1697
1698impl ReadResourceResult {
1699 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
1709 Self {
1710 contents: vec![ResourceContent {
1711 uri: uri.into(),
1712 mime_type: Some("text/plain".to_string()),
1713 text: Some(content.into()),
1714 blob: None,
1715 }],
1716 }
1717 }
1718
1719 pub fn text_with_mime(
1733 uri: impl Into<String>,
1734 content: impl Into<String>,
1735 mime_type: impl Into<String>,
1736 ) -> Self {
1737 Self {
1738 contents: vec![ResourceContent {
1739 uri: uri.into(),
1740 mime_type: Some(mime_type.into()),
1741 text: Some(content.into()),
1742 blob: None,
1743 }],
1744 }
1745 }
1746
1747 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
1761 let json_string =
1762 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
1763 Self {
1764 contents: vec![ResourceContent {
1765 uri: uri.into(),
1766 mime_type: Some("application/json".to_string()),
1767 text: Some(json_string),
1768 blob: None,
1769 }],
1770 }
1771 }
1772
1773 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
1784 use base64::Engine;
1785 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1786 Self {
1787 contents: vec![ResourceContent {
1788 uri: uri.into(),
1789 mime_type: Some("application/octet-stream".to_string()),
1790 text: None,
1791 blob: Some(encoded),
1792 }],
1793 }
1794 }
1795
1796 pub fn blob_with_mime(
1807 uri: impl Into<String>,
1808 bytes: &[u8],
1809 mime_type: impl Into<String>,
1810 ) -> Self {
1811 use base64::Engine;
1812 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1813 Self {
1814 contents: vec![ResourceContent {
1815 uri: uri.into(),
1816 mime_type: Some(mime_type.into()),
1817 text: None,
1818 blob: Some(encoded),
1819 }],
1820 }
1821 }
1822
1823 pub fn first_text(&self) -> Option<&str> {
1836 self.contents.first().and_then(|c| c.text.as_deref())
1837 }
1838
1839 pub fn first_uri(&self) -> Option<&str> {
1852 self.contents.first().map(|c| c.uri.as_str())
1853 }
1854}
1855
1856#[derive(Debug, Clone, Deserialize)]
1857pub struct SubscribeResourceParams {
1858 pub uri: String,
1859}
1860
1861#[derive(Debug, Clone, Deserialize)]
1862pub struct UnsubscribeResourceParams {
1863 pub uri: String,
1864}
1865
1866#[derive(Debug, Clone, Default, Deserialize)]
1868pub struct ListResourceTemplatesParams {
1869 #[serde(default)]
1871 pub cursor: Option<String>,
1872}
1873
1874#[derive(Debug, Clone, Serialize)]
1876#[serde(rename_all = "camelCase")]
1877pub struct ListResourceTemplatesResult {
1878 pub resource_templates: Vec<ResourceTemplateDefinition>,
1880 #[serde(skip_serializing_if = "Option::is_none")]
1882 pub next_cursor: Option<String>,
1883}
1884
1885#[derive(Debug, Clone, Serialize, Deserialize)]
1901#[serde(rename_all = "camelCase")]
1902pub struct ResourceTemplateDefinition {
1903 pub uri_template: String,
1905 pub name: String,
1907 #[serde(skip_serializing_if = "Option::is_none")]
1909 pub title: Option<String>,
1910 #[serde(skip_serializing_if = "Option::is_none")]
1912 pub description: Option<String>,
1913 #[serde(skip_serializing_if = "Option::is_none")]
1915 pub mime_type: Option<String>,
1916 #[serde(skip_serializing_if = "Option::is_none")]
1918 pub icons: Option<Vec<ToolIcon>>,
1919}
1920
1921#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1926pub struct ListPromptsParams {
1927 #[serde(default)]
1928 pub cursor: Option<String>,
1929}
1930
1931#[derive(Debug, Clone, Serialize, Deserialize)]
1932#[serde(rename_all = "camelCase")]
1933pub struct ListPromptsResult {
1934 pub prompts: Vec<PromptDefinition>,
1935 #[serde(default, skip_serializing_if = "Option::is_none")]
1936 pub next_cursor: Option<String>,
1937}
1938
1939#[derive(Debug, Clone, Serialize, Deserialize)]
1940pub struct PromptDefinition {
1941 pub name: String,
1942 #[serde(skip_serializing_if = "Option::is_none")]
1944 pub title: Option<String>,
1945 #[serde(skip_serializing_if = "Option::is_none")]
1946 pub description: Option<String>,
1947 #[serde(skip_serializing_if = "Option::is_none")]
1949 pub icons: Option<Vec<ToolIcon>>,
1950 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1951 pub arguments: Vec<PromptArgument>,
1952}
1953
1954#[derive(Debug, Clone, Serialize, Deserialize)]
1955pub struct PromptArgument {
1956 pub name: String,
1957 #[serde(skip_serializing_if = "Option::is_none")]
1958 pub description: Option<String>,
1959 #[serde(default)]
1960 pub required: bool,
1961}
1962
1963#[derive(Debug, Clone, Serialize, Deserialize)]
1964pub struct GetPromptParams {
1965 pub name: String,
1966 #[serde(default)]
1967 pub arguments: std::collections::HashMap<String, String>,
1968}
1969
1970#[derive(Debug, Clone, Serialize, Deserialize)]
1971pub struct GetPromptResult {
1972 #[serde(default, skip_serializing_if = "Option::is_none")]
1973 pub description: Option<String>,
1974 pub messages: Vec<PromptMessage>,
1975}
1976
1977impl GetPromptResult {
1978 pub fn user_message(text: impl Into<String>) -> Self {
1988 Self {
1989 description: None,
1990 messages: vec![PromptMessage {
1991 role: PromptRole::User,
1992 content: Content::Text {
1993 text: text.into(),
1994 annotations: None,
1995 },
1996 }],
1997 }
1998 }
1999
2000 pub fn user_message_with_description(
2013 text: impl Into<String>,
2014 description: impl Into<String>,
2015 ) -> Self {
2016 Self {
2017 description: Some(description.into()),
2018 messages: vec![PromptMessage {
2019 role: PromptRole::User,
2020 content: Content::Text {
2021 text: text.into(),
2022 annotations: None,
2023 },
2024 }],
2025 }
2026 }
2027
2028 pub fn assistant_message(text: impl Into<String>) -> Self {
2038 Self {
2039 description: None,
2040 messages: vec![PromptMessage {
2041 role: PromptRole::Assistant,
2042 content: Content::Text {
2043 text: text.into(),
2044 annotations: None,
2045 },
2046 }],
2047 }
2048 }
2049
2050 pub fn builder() -> GetPromptResultBuilder {
2065 GetPromptResultBuilder::new()
2066 }
2067
2068 pub fn first_message_text(&self) -> Option<&str> {
2082 self.messages.first().and_then(|m| m.content.as_text())
2083 }
2084}
2085
2086#[derive(Debug, Clone, Default)]
2088pub struct GetPromptResultBuilder {
2089 description: Option<String>,
2090 messages: Vec<PromptMessage>,
2091}
2092
2093impl GetPromptResultBuilder {
2094 pub fn new() -> Self {
2096 Self::default()
2097 }
2098
2099 pub fn description(mut self, description: impl Into<String>) -> Self {
2101 self.description = Some(description.into());
2102 self
2103 }
2104
2105 pub fn user(mut self, text: impl Into<String>) -> Self {
2107 self.messages.push(PromptMessage {
2108 role: PromptRole::User,
2109 content: Content::Text {
2110 text: text.into(),
2111 annotations: None,
2112 },
2113 });
2114 self
2115 }
2116
2117 pub fn assistant(mut self, text: impl Into<String>) -> Self {
2119 self.messages.push(PromptMessage {
2120 role: PromptRole::Assistant,
2121 content: Content::Text {
2122 text: text.into(),
2123 annotations: None,
2124 },
2125 });
2126 self
2127 }
2128
2129 pub fn build(self) -> GetPromptResult {
2131 GetPromptResult {
2132 description: self.description,
2133 messages: self.messages,
2134 }
2135 }
2136}
2137
2138#[derive(Debug, Clone, Serialize, Deserialize)]
2139pub struct PromptMessage {
2140 pub role: PromptRole,
2141 pub content: Content,
2142}
2143
2144#[derive(Debug, Clone, Serialize, Deserialize)]
2145#[serde(rename_all = "lowercase")]
2146pub enum PromptRole {
2147 User,
2148 Assistant,
2149}
2150
2151#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2157#[serde(rename_all = "snake_case")]
2158pub enum TaskStatus {
2159 Working,
2161 InputRequired,
2163 Completed,
2165 Failed,
2167 Cancelled,
2169}
2170
2171impl std::fmt::Display for TaskStatus {
2172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2173 match self {
2174 TaskStatus::Working => write!(f, "working"),
2175 TaskStatus::InputRequired => write!(f, "input_required"),
2176 TaskStatus::Completed => write!(f, "completed"),
2177 TaskStatus::Failed => write!(f, "failed"),
2178 TaskStatus::Cancelled => write!(f, "cancelled"),
2179 }
2180 }
2181}
2182
2183impl TaskStatus {
2184 pub fn is_terminal(&self) -> bool {
2186 matches!(
2187 self,
2188 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
2189 )
2190 }
2191}
2192
2193#[derive(Debug, Clone, Serialize, Deserialize)]
2195#[serde(rename_all = "camelCase")]
2196pub struct TaskInfo {
2197 pub task_id: String,
2199 pub status: TaskStatus,
2201 pub created_at: String,
2203 #[serde(skip_serializing_if = "Option::is_none")]
2205 pub ttl: Option<u64>,
2206 #[serde(skip_serializing_if = "Option::is_none")]
2208 pub poll_interval: Option<u64>,
2209 #[serde(skip_serializing_if = "Option::is_none")]
2211 pub progress: Option<f64>,
2212 #[serde(skip_serializing_if = "Option::is_none")]
2214 pub message: Option<String>,
2215}
2216
2217#[derive(Debug, Clone, Deserialize)]
2219#[serde(rename_all = "camelCase")]
2220pub struct EnqueueTaskParams {
2221 pub tool_name: String,
2223 #[serde(default)]
2225 pub arguments: Value,
2226 #[serde(default)]
2228 pub ttl: Option<u64>,
2229}
2230
2231#[derive(Debug, Clone, Serialize)]
2233#[serde(rename_all = "camelCase")]
2234pub struct EnqueueTaskResult {
2235 pub task_id: String,
2237 pub status: TaskStatus,
2239 #[serde(skip_serializing_if = "Option::is_none")]
2241 pub poll_interval: Option<u64>,
2242}
2243
2244#[derive(Debug, Clone, Default, Deserialize)]
2246#[serde(rename_all = "camelCase")]
2247pub struct ListTasksParams {
2248 #[serde(default)]
2250 pub status: Option<TaskStatus>,
2251 #[serde(default)]
2253 pub cursor: Option<String>,
2254}
2255
2256#[derive(Debug, Clone, Serialize)]
2258#[serde(rename_all = "camelCase")]
2259pub struct ListTasksResult {
2260 pub tasks: Vec<TaskInfo>,
2262 #[serde(skip_serializing_if = "Option::is_none")]
2264 pub next_cursor: Option<String>,
2265}
2266
2267#[derive(Debug, Clone, Deserialize)]
2269#[serde(rename_all = "camelCase")]
2270pub struct GetTaskInfoParams {
2271 pub task_id: String,
2273}
2274
2275pub type GetTaskInfoResult = TaskInfo;
2277
2278#[derive(Debug, Clone, Deserialize)]
2280#[serde(rename_all = "camelCase")]
2281pub struct GetTaskResultParams {
2282 pub task_id: String,
2284}
2285
2286#[derive(Debug, Clone, Serialize)]
2288#[serde(rename_all = "camelCase")]
2289pub struct GetTaskResultResult {
2290 pub task_id: String,
2292 pub status: TaskStatus,
2294 #[serde(skip_serializing_if = "Option::is_none")]
2296 pub result: Option<CallToolResult>,
2297 #[serde(skip_serializing_if = "Option::is_none")]
2299 pub error: Option<String>,
2300}
2301
2302#[derive(Debug, Clone, Deserialize)]
2304#[serde(rename_all = "camelCase")]
2305pub struct CancelTaskParams {
2306 pub task_id: String,
2308 #[serde(default)]
2310 pub reason: Option<String>,
2311}
2312
2313#[derive(Debug, Clone, Serialize)]
2315#[serde(rename_all = "camelCase")]
2316pub struct CancelTaskResult {
2317 pub cancelled: bool,
2319 pub status: TaskStatus,
2321}
2322
2323#[derive(Debug, Clone, Serialize, Deserialize)]
2325#[serde(rename_all = "camelCase")]
2326pub struct TaskStatusChangedParams {
2327 pub task_id: String,
2329 pub status: TaskStatus,
2331 #[serde(skip_serializing_if = "Option::is_none")]
2333 pub message: Option<String>,
2334}
2335
2336#[derive(Debug, Clone, Serialize, Deserialize)]
2342#[serde(rename_all = "camelCase")]
2343pub struct ElicitFormParams {
2344 pub mode: ElicitMode,
2346 pub message: String,
2348 pub requested_schema: ElicitFormSchema,
2350 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2352 pub meta: Option<RequestMeta>,
2353}
2354
2355#[derive(Debug, Clone, Serialize, Deserialize)]
2357#[serde(rename_all = "camelCase")]
2358pub struct ElicitUrlParams {
2359 pub mode: ElicitMode,
2361 pub elicitation_id: String,
2363 pub message: String,
2365 pub url: String,
2367 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2369 pub meta: Option<RequestMeta>,
2370}
2371
2372#[derive(Debug, Clone, Serialize, Deserialize)]
2374#[serde(untagged)]
2375pub enum ElicitRequestParams {
2376 Form(ElicitFormParams),
2377 Url(ElicitUrlParams),
2378}
2379
2380#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2382#[serde(rename_all = "lowercase")]
2383pub enum ElicitMode {
2384 Form,
2386 Url,
2388}
2389
2390#[derive(Debug, Clone, Serialize, Deserialize)]
2394pub struct ElicitFormSchema {
2395 #[serde(rename = "type")]
2397 pub schema_type: String,
2398 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
2400 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2402 pub required: Vec<String>,
2403}
2404
2405impl ElicitFormSchema {
2406 pub fn new() -> Self {
2408 Self {
2409 schema_type: "object".to_string(),
2410 properties: std::collections::HashMap::new(),
2411 required: Vec::new(),
2412 }
2413 }
2414
2415 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2417 self.properties.insert(
2418 name.to_string(),
2419 PrimitiveSchemaDefinition::String(StringSchema {
2420 schema_type: "string".to_string(),
2421 description: description.map(|s| s.to_string()),
2422 format: None,
2423 min_length: None,
2424 max_length: None,
2425 default: None,
2426 }),
2427 );
2428 if required {
2429 self.required.push(name.to_string());
2430 }
2431 self
2432 }
2433
2434 pub fn string_field_with_default(
2436 mut self,
2437 name: &str,
2438 description: Option<&str>,
2439 required: bool,
2440 default: &str,
2441 ) -> Self {
2442 self.properties.insert(
2443 name.to_string(),
2444 PrimitiveSchemaDefinition::String(StringSchema {
2445 schema_type: "string".to_string(),
2446 description: description.map(|s| s.to_string()),
2447 format: None,
2448 min_length: None,
2449 max_length: None,
2450 default: Some(default.to_string()),
2451 }),
2452 );
2453 if required {
2454 self.required.push(name.to_string());
2455 }
2456 self
2457 }
2458
2459 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2461 self.properties.insert(
2462 name.to_string(),
2463 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2464 schema_type: "integer".to_string(),
2465 description: description.map(|s| s.to_string()),
2466 minimum: None,
2467 maximum: None,
2468 default: None,
2469 }),
2470 );
2471 if required {
2472 self.required.push(name.to_string());
2473 }
2474 self
2475 }
2476
2477 pub fn integer_field_with_default(
2479 mut self,
2480 name: &str,
2481 description: Option<&str>,
2482 required: bool,
2483 default: i64,
2484 ) -> Self {
2485 self.properties.insert(
2486 name.to_string(),
2487 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2488 schema_type: "integer".to_string(),
2489 description: description.map(|s| s.to_string()),
2490 minimum: None,
2491 maximum: None,
2492 default: Some(default),
2493 }),
2494 );
2495 if required {
2496 self.required.push(name.to_string());
2497 }
2498 self
2499 }
2500
2501 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2503 self.properties.insert(
2504 name.to_string(),
2505 PrimitiveSchemaDefinition::Number(NumberSchema {
2506 schema_type: "number".to_string(),
2507 description: description.map(|s| s.to_string()),
2508 minimum: None,
2509 maximum: None,
2510 default: None,
2511 }),
2512 );
2513 if required {
2514 self.required.push(name.to_string());
2515 }
2516 self
2517 }
2518
2519 pub fn number_field_with_default(
2521 mut self,
2522 name: &str,
2523 description: Option<&str>,
2524 required: bool,
2525 default: f64,
2526 ) -> Self {
2527 self.properties.insert(
2528 name.to_string(),
2529 PrimitiveSchemaDefinition::Number(NumberSchema {
2530 schema_type: "number".to_string(),
2531 description: description.map(|s| s.to_string()),
2532 minimum: None,
2533 maximum: None,
2534 default: Some(default),
2535 }),
2536 );
2537 if required {
2538 self.required.push(name.to_string());
2539 }
2540 self
2541 }
2542
2543 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2545 self.properties.insert(
2546 name.to_string(),
2547 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2548 schema_type: "boolean".to_string(),
2549 description: description.map(|s| s.to_string()),
2550 default: None,
2551 }),
2552 );
2553 if required {
2554 self.required.push(name.to_string());
2555 }
2556 self
2557 }
2558
2559 pub fn boolean_field_with_default(
2561 mut self,
2562 name: &str,
2563 description: Option<&str>,
2564 required: bool,
2565 default: bool,
2566 ) -> Self {
2567 self.properties.insert(
2568 name.to_string(),
2569 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2570 schema_type: "boolean".to_string(),
2571 description: description.map(|s| s.to_string()),
2572 default: Some(default),
2573 }),
2574 );
2575 if required {
2576 self.required.push(name.to_string());
2577 }
2578 self
2579 }
2580
2581 pub fn enum_field(
2583 mut self,
2584 name: &str,
2585 description: Option<&str>,
2586 options: Vec<String>,
2587 required: bool,
2588 ) -> Self {
2589 self.properties.insert(
2590 name.to_string(),
2591 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2592 schema_type: "string".to_string(),
2593 description: description.map(|s| s.to_string()),
2594 enum_values: options,
2595 default: None,
2596 }),
2597 );
2598 if required {
2599 self.required.push(name.to_string());
2600 }
2601 self
2602 }
2603
2604 pub fn enum_field_with_default(
2606 mut self,
2607 name: &str,
2608 description: Option<&str>,
2609 required: bool,
2610 options: &[&str],
2611 default: &str,
2612 ) -> Self {
2613 self.properties.insert(
2614 name.to_string(),
2615 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2616 schema_type: "string".to_string(),
2617 description: description.map(|s| s.to_string()),
2618 enum_values: options.iter().map(|s| s.to_string()).collect(),
2619 default: Some(default.to_string()),
2620 }),
2621 );
2622 if required {
2623 self.required.push(name.to_string());
2624 }
2625 self
2626 }
2627
2628 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
2632 self.properties
2633 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
2634 if required {
2635 self.required.push(name.to_string());
2636 }
2637 self
2638 }
2639}
2640
2641impl Default for ElicitFormSchema {
2642 fn default() -> Self {
2643 Self::new()
2644 }
2645}
2646
2647#[derive(Debug, Clone, Serialize, Deserialize)]
2649#[serde(untagged)]
2650pub enum PrimitiveSchemaDefinition {
2651 String(StringSchema),
2653 Integer(IntegerSchema),
2655 Number(NumberSchema),
2657 Boolean(BooleanSchema),
2659 SingleSelectEnum(SingleSelectEnumSchema),
2661 MultiSelectEnum(MultiSelectEnumSchema),
2663 Raw(serde_json::Value),
2665}
2666
2667#[derive(Debug, Clone, Serialize, Deserialize)]
2669#[serde(rename_all = "camelCase")]
2670pub struct StringSchema {
2671 #[serde(rename = "type")]
2672 pub schema_type: String,
2673 #[serde(skip_serializing_if = "Option::is_none")]
2674 pub description: Option<String>,
2675 #[serde(skip_serializing_if = "Option::is_none")]
2676 pub format: Option<String>,
2677 #[serde(skip_serializing_if = "Option::is_none")]
2678 pub min_length: Option<u64>,
2679 #[serde(skip_serializing_if = "Option::is_none")]
2680 pub max_length: Option<u64>,
2681 #[serde(skip_serializing_if = "Option::is_none")]
2683 pub default: Option<String>,
2684}
2685
2686#[derive(Debug, Clone, Serialize, Deserialize)]
2688#[serde(rename_all = "camelCase")]
2689pub struct IntegerSchema {
2690 #[serde(rename = "type")]
2691 pub schema_type: String,
2692 #[serde(skip_serializing_if = "Option::is_none")]
2693 pub description: Option<String>,
2694 #[serde(skip_serializing_if = "Option::is_none")]
2695 pub minimum: Option<i64>,
2696 #[serde(skip_serializing_if = "Option::is_none")]
2697 pub maximum: Option<i64>,
2698 #[serde(skip_serializing_if = "Option::is_none")]
2700 pub default: Option<i64>,
2701}
2702
2703#[derive(Debug, Clone, Serialize, Deserialize)]
2705#[serde(rename_all = "camelCase")]
2706pub struct NumberSchema {
2707 #[serde(rename = "type")]
2708 pub schema_type: String,
2709 #[serde(skip_serializing_if = "Option::is_none")]
2710 pub description: Option<String>,
2711 #[serde(skip_serializing_if = "Option::is_none")]
2712 pub minimum: Option<f64>,
2713 #[serde(skip_serializing_if = "Option::is_none")]
2714 pub maximum: Option<f64>,
2715 #[serde(skip_serializing_if = "Option::is_none")]
2717 pub default: Option<f64>,
2718}
2719
2720#[derive(Debug, Clone, Serialize, Deserialize)]
2722#[serde(rename_all = "camelCase")]
2723pub struct BooleanSchema {
2724 #[serde(rename = "type")]
2725 pub schema_type: String,
2726 #[serde(skip_serializing_if = "Option::is_none")]
2727 pub description: Option<String>,
2728 #[serde(skip_serializing_if = "Option::is_none")]
2730 pub default: Option<bool>,
2731}
2732
2733#[derive(Debug, Clone, Serialize, Deserialize)]
2735#[serde(rename_all = "camelCase")]
2736pub struct SingleSelectEnumSchema {
2737 #[serde(rename = "type")]
2738 pub schema_type: String,
2739 #[serde(skip_serializing_if = "Option::is_none")]
2740 pub description: Option<String>,
2741 #[serde(rename = "enum")]
2742 pub enum_values: Vec<String>,
2743 #[serde(skip_serializing_if = "Option::is_none")]
2745 pub default: Option<String>,
2746}
2747
2748#[derive(Debug, Clone, Serialize, Deserialize)]
2750#[serde(rename_all = "camelCase")]
2751pub struct MultiSelectEnumSchema {
2752 #[serde(rename = "type")]
2753 pub schema_type: String,
2754 #[serde(skip_serializing_if = "Option::is_none")]
2755 pub description: Option<String>,
2756 pub items: MultiSelectEnumItems,
2757 #[serde(skip_serializing_if = "Option::is_none")]
2758 pub unique_items: Option<bool>,
2759}
2760
2761#[derive(Debug, Clone, Serialize, Deserialize)]
2763pub struct MultiSelectEnumItems {
2764 #[serde(rename = "type")]
2765 pub schema_type: String,
2766 #[serde(rename = "enum")]
2767 pub enum_values: Vec<String>,
2768}
2769
2770#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2772#[serde(rename_all = "lowercase")]
2773pub enum ElicitAction {
2774 Accept,
2776 Decline,
2778 Cancel,
2780}
2781
2782#[derive(Debug, Clone, Serialize, Deserialize)]
2784pub struct ElicitResult {
2785 pub action: ElicitAction,
2787 #[serde(default, skip_serializing_if = "Option::is_none")]
2789 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
2790}
2791
2792impl ElicitResult {
2793 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
2795 Self {
2796 action: ElicitAction::Accept,
2797 content: Some(content),
2798 }
2799 }
2800
2801 pub fn decline() -> Self {
2803 Self {
2804 action: ElicitAction::Decline,
2805 content: None,
2806 }
2807 }
2808
2809 pub fn cancel() -> Self {
2811 Self {
2812 action: ElicitAction::Cancel,
2813 content: None,
2814 }
2815 }
2816}
2817
2818#[derive(Debug, Clone, Serialize, Deserialize)]
2820#[serde(untagged)]
2821pub enum ElicitFieldValue {
2822 String(String),
2823 Number(f64),
2824 Integer(i64),
2825 Boolean(bool),
2826 StringArray(Vec<String>),
2827}
2828
2829#[derive(Debug, Clone, Serialize, Deserialize)]
2831#[serde(rename_all = "camelCase")]
2832pub struct ElicitationCompleteParams {
2833 pub elicitation_id: String,
2835}
2836
2837#[derive(Debug, Clone, Default, Serialize)]
2842pub struct EmptyResult {}
2843
2844impl McpRequest {
2849 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
2851 let params = req
2852 .params
2853 .clone()
2854 .unwrap_or(Value::Object(Default::default()));
2855
2856 match req.method.as_str() {
2857 "initialize" => {
2858 let p: InitializeParams = serde_json::from_value(params)?;
2859 Ok(McpRequest::Initialize(p))
2860 }
2861 "tools/list" => {
2862 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
2863 Ok(McpRequest::ListTools(p))
2864 }
2865 "tools/call" => {
2866 let p: CallToolParams = serde_json::from_value(params)?;
2867 Ok(McpRequest::CallTool(p))
2868 }
2869 "resources/list" => {
2870 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
2871 Ok(McpRequest::ListResources(p))
2872 }
2873 "resources/templates/list" => {
2874 let p: ListResourceTemplatesParams =
2875 serde_json::from_value(params).unwrap_or_default();
2876 Ok(McpRequest::ListResourceTemplates(p))
2877 }
2878 "resources/read" => {
2879 let p: ReadResourceParams = serde_json::from_value(params)?;
2880 Ok(McpRequest::ReadResource(p))
2881 }
2882 "resources/subscribe" => {
2883 let p: SubscribeResourceParams = serde_json::from_value(params)?;
2884 Ok(McpRequest::SubscribeResource(p))
2885 }
2886 "resources/unsubscribe" => {
2887 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
2888 Ok(McpRequest::UnsubscribeResource(p))
2889 }
2890 "prompts/list" => {
2891 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
2892 Ok(McpRequest::ListPrompts(p))
2893 }
2894 "prompts/get" => {
2895 let p: GetPromptParams = serde_json::from_value(params)?;
2896 Ok(McpRequest::GetPrompt(p))
2897 }
2898 "tasks/enqueue" => {
2899 let p: EnqueueTaskParams = serde_json::from_value(params)?;
2900 Ok(McpRequest::EnqueueTask(p))
2901 }
2902 "tasks/list" => {
2903 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
2904 Ok(McpRequest::ListTasks(p))
2905 }
2906 "tasks/get" => {
2907 let p: GetTaskInfoParams = serde_json::from_value(params)?;
2908 Ok(McpRequest::GetTaskInfo(p))
2909 }
2910 "tasks/result" => {
2911 let p: GetTaskResultParams = serde_json::from_value(params)?;
2912 Ok(McpRequest::GetTaskResult(p))
2913 }
2914 "tasks/cancel" => {
2915 let p: CancelTaskParams = serde_json::from_value(params)?;
2916 Ok(McpRequest::CancelTask(p))
2917 }
2918 "ping" => Ok(McpRequest::Ping),
2919 "logging/setLevel" => {
2920 let p: SetLogLevelParams = serde_json::from_value(params)?;
2921 Ok(McpRequest::SetLoggingLevel(p))
2922 }
2923 "completion/complete" => {
2924 let p: CompleteParams = serde_json::from_value(params)?;
2925 Ok(McpRequest::Complete(p))
2926 }
2927 method => Ok(McpRequest::Unknown {
2928 method: method.to_string(),
2929 params: req.params.clone(),
2930 }),
2931 }
2932 }
2933}
2934
2935impl McpNotification {
2936 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
2938 let params = notif
2939 .params
2940 .clone()
2941 .unwrap_or(Value::Object(Default::default()));
2942
2943 match notif.method.as_str() {
2944 notifications::INITIALIZED => Ok(McpNotification::Initialized),
2945 notifications::CANCELLED => {
2946 let p: CancelledParams = serde_json::from_value(params)?;
2947 Ok(McpNotification::Cancelled(p))
2948 }
2949 notifications::PROGRESS => {
2950 let p: ProgressParams = serde_json::from_value(params)?;
2951 Ok(McpNotification::Progress(p))
2952 }
2953 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
2954 method => Ok(McpNotification::Unknown {
2955 method: method.to_string(),
2956 params: notif.params.clone(),
2957 }),
2958 }
2959 }
2960}
2961
2962#[cfg(test)]
2963mod tests {
2964 use super::*;
2965
2966 #[test]
2967 fn test_elicit_form_schema_builder() {
2968 let schema = ElicitFormSchema::new()
2969 .string_field("name", Some("Your name"), true)
2970 .number_field("age", Some("Your age"), false)
2971 .boolean_field("agree", Some("Do you agree?"), true)
2972 .enum_field(
2973 "color",
2974 Some("Favorite color"),
2975 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
2976 false,
2977 );
2978
2979 assert_eq!(schema.schema_type, "object");
2980 assert_eq!(schema.properties.len(), 4);
2981 assert_eq!(schema.required.len(), 2);
2982 assert!(schema.required.contains(&"name".to_string()));
2983 assert!(schema.required.contains(&"agree".to_string()));
2984 }
2985
2986 #[test]
2987 fn test_elicit_form_schema_serialization() {
2988 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
2989
2990 let json = serde_json::to_value(&schema).unwrap();
2991 assert_eq!(json["type"], "object");
2992 assert!(json["properties"]["username"]["type"] == "string");
2993 assert!(
2994 json["required"]
2995 .as_array()
2996 .unwrap()
2997 .contains(&serde_json::json!("username"))
2998 );
2999 }
3000
3001 #[test]
3002 fn test_elicit_result_accept() {
3003 let mut content = std::collections::HashMap::new();
3004 content.insert(
3005 "name".to_string(),
3006 ElicitFieldValue::String("Alice".to_string()),
3007 );
3008 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
3009
3010 let result = ElicitResult::accept(content);
3011 assert_eq!(result.action, ElicitAction::Accept);
3012 assert!(result.content.is_some());
3013 }
3014
3015 #[test]
3016 fn test_elicit_result_decline() {
3017 let result = ElicitResult::decline();
3018 assert_eq!(result.action, ElicitAction::Decline);
3019 assert!(result.content.is_none());
3020 }
3021
3022 #[test]
3023 fn test_elicit_result_cancel() {
3024 let result = ElicitResult::cancel();
3025 assert_eq!(result.action, ElicitAction::Cancel);
3026 assert!(result.content.is_none());
3027 }
3028
3029 #[test]
3030 fn test_elicit_mode_serialization() {
3031 assert_eq!(
3032 serde_json::to_string(&ElicitMode::Form).unwrap(),
3033 "\"form\""
3034 );
3035 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
3036 }
3037
3038 #[test]
3039 fn test_elicit_action_serialization() {
3040 assert_eq!(
3041 serde_json::to_string(&ElicitAction::Accept).unwrap(),
3042 "\"accept\""
3043 );
3044 assert_eq!(
3045 serde_json::to_string(&ElicitAction::Decline).unwrap(),
3046 "\"decline\""
3047 );
3048 assert_eq!(
3049 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
3050 "\"cancel\""
3051 );
3052 }
3053
3054 #[test]
3055 fn test_elicitation_capability() {
3056 let cap = ElicitationCapability {
3057 form: Some(ElicitationFormCapability {}),
3058 url: None,
3059 };
3060
3061 let json = serde_json::to_value(&cap).unwrap();
3062 assert!(json["form"].is_object());
3063 assert!(json.get("url").is_none());
3064 }
3065
3066 #[test]
3067 fn test_client_capabilities_with_elicitation() {
3068 let caps = ClientCapabilities {
3069 roots: None,
3070 sampling: None,
3071 elicitation: Some(ElicitationCapability {
3072 form: Some(ElicitationFormCapability {}),
3073 url: Some(ElicitationUrlCapability {}),
3074 }),
3075 };
3076
3077 let json = serde_json::to_value(&caps).unwrap();
3078 assert!(json["elicitation"]["form"].is_object());
3079 assert!(json["elicitation"]["url"].is_object());
3080 }
3081
3082 #[test]
3083 fn test_elicit_url_params() {
3084 let params = ElicitUrlParams {
3085 mode: ElicitMode::Url,
3086 elicitation_id: "abc123".to_string(),
3087 message: "Please authorize".to_string(),
3088 url: "https://example.com/auth".to_string(),
3089 meta: None,
3090 };
3091
3092 let json = serde_json::to_value(¶ms).unwrap();
3093 assert_eq!(json["mode"], "url");
3094 assert_eq!(json["elicitationId"], "abc123");
3095 assert_eq!(json["message"], "Please authorize");
3096 assert_eq!(json["url"], "https://example.com/auth");
3097 }
3098
3099 #[test]
3100 fn test_elicitation_complete_params() {
3101 let params = ElicitationCompleteParams {
3102 elicitation_id: "xyz789".to_string(),
3103 };
3104
3105 let json = serde_json::to_value(¶ms).unwrap();
3106 assert_eq!(json["elicitationId"], "xyz789");
3107 }
3108
3109 #[test]
3110 fn test_root_new() {
3111 let root = Root::new("file:///home/user/project");
3112 assert_eq!(root.uri, "file:///home/user/project");
3113 assert!(root.name.is_none());
3114 }
3115
3116 #[test]
3117 fn test_root_with_name() {
3118 let root = Root::with_name("file:///home/user/project", "My Project");
3119 assert_eq!(root.uri, "file:///home/user/project");
3120 assert_eq!(root.name.as_deref(), Some("My Project"));
3121 }
3122
3123 #[test]
3124 fn test_root_serialization() {
3125 let root = Root::with_name("file:///workspace", "Workspace");
3126 let json = serde_json::to_value(&root).unwrap();
3127 assert_eq!(json["uri"], "file:///workspace");
3128 assert_eq!(json["name"], "Workspace");
3129 }
3130
3131 #[test]
3132 fn test_root_serialization_without_name() {
3133 let root = Root::new("file:///workspace");
3134 let json = serde_json::to_value(&root).unwrap();
3135 assert_eq!(json["uri"], "file:///workspace");
3136 assert!(json.get("name").is_none());
3137 }
3138
3139 #[test]
3140 fn test_root_deserialization() {
3141 let json = serde_json::json!({
3142 "uri": "file:///home/user",
3143 "name": "Home"
3144 });
3145 let root: Root = serde_json::from_value(json).unwrap();
3146 assert_eq!(root.uri, "file:///home/user");
3147 assert_eq!(root.name.as_deref(), Some("Home"));
3148 }
3149
3150 #[test]
3151 fn test_list_roots_result() {
3152 let result = ListRootsResult {
3153 roots: vec![
3154 Root::new("file:///project1"),
3155 Root::with_name("file:///project2", "Project 2"),
3156 ],
3157 };
3158
3159 let json = serde_json::to_value(&result).unwrap();
3160 let roots = json["roots"].as_array().unwrap();
3161 assert_eq!(roots.len(), 2);
3162 assert_eq!(roots[0]["uri"], "file:///project1");
3163 assert_eq!(roots[1]["name"], "Project 2");
3164 }
3165
3166 #[test]
3167 fn test_roots_capability_serialization() {
3168 let cap = RootsCapability { list_changed: true };
3169 let json = serde_json::to_value(&cap).unwrap();
3170 assert_eq!(json["listChanged"], true);
3171 }
3172
3173 #[test]
3174 fn test_client_capabilities_with_roots() {
3175 let caps = ClientCapabilities {
3176 roots: Some(RootsCapability { list_changed: true }),
3177 sampling: None,
3178 elicitation: None,
3179 };
3180
3181 let json = serde_json::to_value(&caps).unwrap();
3182 assert_eq!(json["roots"]["listChanged"], true);
3183 }
3184
3185 #[test]
3186 fn test_roots_list_changed_notification_parsing() {
3187 let notif = JsonRpcNotification {
3188 jsonrpc: "2.0".to_string(),
3189 method: notifications::ROOTS_LIST_CHANGED.to_string(),
3190 params: None,
3191 };
3192
3193 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
3194 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
3195 }
3196
3197 #[test]
3202 fn test_prompt_reference() {
3203 let ref_ = PromptReference::new("my-prompt");
3204 assert_eq!(ref_.ref_type, "ref/prompt");
3205 assert_eq!(ref_.name, "my-prompt");
3206
3207 let json = serde_json::to_value(&ref_).unwrap();
3208 assert_eq!(json["type"], "ref/prompt");
3209 assert_eq!(json["name"], "my-prompt");
3210 }
3211
3212 #[test]
3213 fn test_resource_reference() {
3214 let ref_ = ResourceReference::new("file:///path/to/file");
3215 assert_eq!(ref_.ref_type, "ref/resource");
3216 assert_eq!(ref_.uri, "file:///path/to/file");
3217
3218 let json = serde_json::to_value(&ref_).unwrap();
3219 assert_eq!(json["type"], "ref/resource");
3220 assert_eq!(json["uri"], "file:///path/to/file");
3221 }
3222
3223 #[test]
3224 fn test_completion_reference_prompt() {
3225 let ref_ = CompletionReference::prompt("test-prompt");
3226 let json = serde_json::to_value(&ref_).unwrap();
3227 assert_eq!(json["type"], "ref/prompt");
3228 assert_eq!(json["name"], "test-prompt");
3229 }
3230
3231 #[test]
3232 fn test_completion_reference_resource() {
3233 let ref_ = CompletionReference::resource("file:///test");
3234 let json = serde_json::to_value(&ref_).unwrap();
3235 assert_eq!(json["type"], "ref/resource");
3236 assert_eq!(json["uri"], "file:///test");
3237 }
3238
3239 #[test]
3240 fn test_completion_argument() {
3241 let arg = CompletionArgument::new("query", "SELECT * FROM");
3242 assert_eq!(arg.name, "query");
3243 assert_eq!(arg.value, "SELECT * FROM");
3244 }
3245
3246 #[test]
3247 fn test_complete_params_serialization() {
3248 let params = CompleteParams {
3249 reference: CompletionReference::prompt("sql-prompt"),
3250 argument: CompletionArgument::new("query", "SEL"),
3251 };
3252
3253 let json = serde_json::to_value(¶ms).unwrap();
3254 assert_eq!(json["ref"]["type"], "ref/prompt");
3255 assert_eq!(json["ref"]["name"], "sql-prompt");
3256 assert_eq!(json["argument"]["name"], "query");
3257 assert_eq!(json["argument"]["value"], "SEL");
3258 }
3259
3260 #[test]
3261 fn test_completion_new() {
3262 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
3263 assert_eq!(completion.values.len(), 2);
3264 assert!(completion.total.is_none());
3265 assert!(completion.has_more.is_none());
3266 }
3267
3268 #[test]
3269 fn test_completion_with_pagination() {
3270 let completion =
3271 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
3272 assert_eq!(completion.values.len(), 2);
3273 assert_eq!(completion.total, Some(100));
3274 assert_eq!(completion.has_more, Some(true));
3275 }
3276
3277 #[test]
3278 fn test_complete_result() {
3279 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
3280 let json = serde_json::to_value(&result).unwrap();
3281 assert!(json["completion"]["values"].is_array());
3282 assert_eq!(json["completion"]["values"][0], "option1");
3283 }
3284
3285 #[test]
3290 fn test_model_hint() {
3291 let hint = ModelHint::new("claude-3-opus");
3292 assert_eq!(hint.name, "claude-3-opus");
3293 }
3294
3295 #[test]
3296 fn test_model_preferences_builder() {
3297 let prefs = ModelPreferences::new()
3298 .speed(0.8)
3299 .intelligence(0.9)
3300 .cost(0.5)
3301 .hint("gpt-4")
3302 .hint("claude-3");
3303
3304 assert_eq!(prefs.speed_priority, Some(0.8));
3305 assert_eq!(prefs.intelligence_priority, Some(0.9));
3306 assert_eq!(prefs.cost_priority, Some(0.5));
3307 assert_eq!(prefs.hints.len(), 2);
3308 }
3309
3310 #[test]
3311 fn test_model_preferences_clamping() {
3312 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
3313
3314 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
3317
3318 #[test]
3319 fn test_include_context_serialization() {
3320 assert_eq!(
3321 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
3322 "\"allServers\""
3323 );
3324 assert_eq!(
3325 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
3326 "\"thisServer\""
3327 );
3328 assert_eq!(
3329 serde_json::to_string(&IncludeContext::None).unwrap(),
3330 "\"none\""
3331 );
3332 }
3333
3334 #[test]
3335 fn test_sampling_message_user() {
3336 let msg = SamplingMessage::user("Hello, how are you?");
3337 assert_eq!(msg.role, ContentRole::User);
3338 assert!(
3339 matches!(msg.content, SamplingContent::Text { text } if text == "Hello, how are you?")
3340 );
3341 }
3342
3343 #[test]
3344 fn test_sampling_message_assistant() {
3345 let msg = SamplingMessage::assistant("I'm doing well!");
3346 assert_eq!(msg.role, ContentRole::Assistant);
3347 }
3348
3349 #[test]
3350 fn test_sampling_content_text_serialization() {
3351 let content = SamplingContent::Text {
3352 text: "Hello".to_string(),
3353 };
3354 let json = serde_json::to_value(&content).unwrap();
3355 assert_eq!(json["type"], "text");
3356 assert_eq!(json["text"], "Hello");
3357 }
3358
3359 #[test]
3360 fn test_sampling_content_image_serialization() {
3361 let content = SamplingContent::Image {
3362 data: "base64data".to_string(),
3363 mime_type: "image/png".to_string(),
3364 };
3365 let json = serde_json::to_value(&content).unwrap();
3366 assert_eq!(json["type"], "image");
3367 assert_eq!(json["data"], "base64data");
3368 assert_eq!(json["mimeType"], "image/png");
3369 }
3370
3371 #[test]
3372 fn test_create_message_params() {
3373 let params = CreateMessageParams::new(
3374 vec![
3375 SamplingMessage::user("What is 2+2?"),
3376 SamplingMessage::assistant("4"),
3377 SamplingMessage::user("And 3+3?"),
3378 ],
3379 100,
3380 )
3381 .system_prompt("You are a math tutor")
3382 .temperature(0.7)
3383 .stop_sequence("END")
3384 .include_context(IncludeContext::ThisServer);
3385
3386 assert_eq!(params.messages.len(), 3);
3387 assert_eq!(params.max_tokens, 100);
3388 assert_eq!(
3389 params.system_prompt.as_deref(),
3390 Some("You are a math tutor")
3391 );
3392 assert_eq!(params.temperature, Some(0.7));
3393 assert_eq!(params.stop_sequences.len(), 1);
3394 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
3395 }
3396
3397 #[test]
3398 fn test_create_message_params_serialization() {
3399 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
3400
3401 let json = serde_json::to_value(¶ms).unwrap();
3402 assert!(json["messages"].is_array());
3403 assert_eq!(json["maxTokens"], 50);
3404 }
3405
3406 #[test]
3407 fn test_create_message_result_deserialization() {
3408 let json = serde_json::json!({
3409 "content": {
3410 "type": "text",
3411 "text": "The answer is 42"
3412 },
3413 "model": "claude-3-opus",
3414 "role": "assistant",
3415 "stopReason": "end_turn"
3416 });
3417
3418 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
3419 assert_eq!(result.model, "claude-3-opus");
3420 assert_eq!(result.role, ContentRole::Assistant);
3421 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
3422 }
3423
3424 #[test]
3425 fn test_completions_capability_serialization() {
3426 let cap = CompletionsCapability {};
3427 let json = serde_json::to_value(&cap).unwrap();
3428 assert!(json.is_object());
3429 }
3430
3431 #[test]
3432 fn test_server_capabilities_with_completions() {
3433 let caps = ServerCapabilities {
3434 completions: Some(CompletionsCapability {}),
3435 ..Default::default()
3436 };
3437
3438 let json = serde_json::to_value(&caps).unwrap();
3439 assert!(json["completions"].is_object());
3440 }
3441
3442 #[test]
3443 fn test_content_resource_link_serialization() {
3444 let content = Content::ResourceLink {
3445 uri: "file:///test.txt".to_string(),
3446 name: Some("test.txt".to_string()),
3447 description: Some("A test file".to_string()),
3448 mime_type: Some("text/plain".to_string()),
3449 annotations: None,
3450 };
3451 let json = serde_json::to_value(&content).unwrap();
3452 assert_eq!(json["type"], "resource_link");
3453 assert_eq!(json["uri"], "file:///test.txt");
3454 assert_eq!(json["name"], "test.txt");
3455 assert_eq!(json["description"], "A test file");
3456 assert_eq!(json["mimeType"], "text/plain");
3457 }
3458
3459 #[test]
3460 fn test_call_tool_result_resource_link() {
3461 let result = CallToolResult::resource_link("file:///output.json");
3462 assert_eq!(result.content.len(), 1);
3463 assert!(!result.is_error);
3464 match &result.content[0] {
3465 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
3466 _ => panic!("Expected ResourceLink content"),
3467 }
3468 }
3469
3470 #[test]
3471 fn test_call_tool_result_image() {
3472 let result = CallToolResult::image("base64data", "image/png");
3473 assert_eq!(result.content.len(), 1);
3474 match &result.content[0] {
3475 Content::Image {
3476 data, mime_type, ..
3477 } => {
3478 assert_eq!(data, "base64data");
3479 assert_eq!(mime_type, "image/png");
3480 }
3481 _ => panic!("Expected Image content"),
3482 }
3483 }
3484
3485 #[test]
3486 fn test_call_tool_result_audio() {
3487 let result = CallToolResult::audio("audiodata", "audio/wav");
3488 assert_eq!(result.content.len(), 1);
3489 match &result.content[0] {
3490 Content::Audio {
3491 data, mime_type, ..
3492 } => {
3493 assert_eq!(data, "audiodata");
3494 assert_eq!(mime_type, "audio/wav");
3495 }
3496 _ => panic!("Expected Audio content"),
3497 }
3498 }
3499
3500 #[test]
3501 fn test_sampling_tool_serialization() {
3502 let tool = SamplingTool {
3503 name: "get_weather".to_string(),
3504 description: Some("Get current weather".to_string()),
3505 input_schema: serde_json::json!({
3506 "type": "object",
3507 "properties": {
3508 "location": { "type": "string" }
3509 }
3510 }),
3511 };
3512 let json = serde_json::to_value(&tool).unwrap();
3513 assert_eq!(json["name"], "get_weather");
3514 assert_eq!(json["description"], "Get current weather");
3515 assert!(json["inputSchema"]["properties"]["location"].is_object());
3516 }
3517
3518 #[test]
3519 fn test_tool_choice_modes() {
3520 let auto = ToolChoice::auto();
3521 assert_eq!(auto.mode, "auto");
3522
3523 let required = ToolChoice::required();
3524 assert_eq!(required.mode, "required");
3525
3526 let none = ToolChoice::none();
3527 assert_eq!(none.mode, "none");
3528
3529 let json = serde_json::to_value(&auto).unwrap();
3531 assert_eq!(json["type"], "auto");
3532 }
3533
3534 #[test]
3535 fn test_sampling_content_tool_use() {
3536 let content = SamplingContent::ToolUse {
3537 id: "tool_123".to_string(),
3538 name: "get_weather".to_string(),
3539 input: serde_json::json!({"location": "San Francisco"}),
3540 };
3541 let json = serde_json::to_value(&content).unwrap();
3542 assert_eq!(json["type"], "tool_use");
3543 assert_eq!(json["id"], "tool_123");
3544 assert_eq!(json["name"], "get_weather");
3545 assert_eq!(json["input"]["location"], "San Francisco");
3546 }
3547
3548 #[test]
3549 fn test_sampling_content_tool_result() {
3550 let content = SamplingContent::ToolResult {
3551 tool_use_id: "tool_123".to_string(),
3552 content: vec![SamplingContent::Text {
3553 text: "72F, sunny".to_string(),
3554 }],
3555 is_error: None,
3556 };
3557 let json = serde_json::to_value(&content).unwrap();
3558 assert_eq!(json["type"], "tool_result");
3559 assert_eq!(json["tool_use_id"], "tool_123");
3560 assert_eq!(json["content"][0]["type"], "text");
3561 }
3562
3563 #[test]
3564 fn test_sampling_content_or_array_single() {
3565 let json = serde_json::json!({
3566 "type": "text",
3567 "text": "Hello"
3568 });
3569 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3570 let items = content.items();
3571 assert_eq!(items.len(), 1);
3572 match items[0] {
3573 SamplingContent::Text { text } => assert_eq!(text, "Hello"),
3574 _ => panic!("Expected text content"),
3575 }
3576 }
3577
3578 #[test]
3579 fn test_sampling_content_or_array_multiple() {
3580 let json = serde_json::json!([
3581 { "type": "text", "text": "Hello" },
3582 { "type": "text", "text": "World" }
3583 ]);
3584 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3585 let items = content.items();
3586 assert_eq!(items.len(), 2);
3587 }
3588
3589 #[test]
3590 fn test_create_message_params_with_tools() {
3591 let tool = SamplingTool {
3592 name: "calculator".to_string(),
3593 description: Some("Do math".to_string()),
3594 input_schema: serde_json::json!({"type": "object"}),
3595 };
3596 let params = CreateMessageParams::new(vec![], 100)
3597 .tools(vec![tool])
3598 .tool_choice(ToolChoice::auto());
3599
3600 let json = serde_json::to_value(¶ms).unwrap();
3601 assert!(json["tools"].is_array());
3602 assert_eq!(json["tools"][0]["name"], "calculator");
3603 assert_eq!(json["toolChoice"]["type"], "auto");
3604 }
3605
3606 #[test]
3607 fn test_create_message_result_content_items() {
3608 let result = CreateMessageResult {
3609 content: SamplingContentOrArray::Array(vec![
3610 SamplingContent::Text {
3611 text: "First".to_string(),
3612 },
3613 SamplingContent::Text {
3614 text: "Second".to_string(),
3615 },
3616 ]),
3617 model: "test".to_string(),
3618 role: ContentRole::Assistant,
3619 stop_reason: None,
3620 };
3621 let items = result.content_items();
3622 assert_eq!(items.len(), 2);
3623 }
3624}