1use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use crate::error::JsonRpcError;
11
12pub const JSONRPC_VERSION: &str = "2.0";
14
15pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
17
18pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct JsonRpcRequest {
24 pub jsonrpc: String,
26 pub id: RequestId,
28 pub method: String,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub params: Option<Value>,
33}
34
35impl JsonRpcRequest {
36 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
38 Self {
39 jsonrpc: JSONRPC_VERSION.to_string(),
40 id: id.into(),
41 method: method.into(),
42 params: None,
43 }
44 }
45
46 pub fn with_params(mut self, params: Value) -> Self {
48 self.params = Some(params);
49 self
50 }
51
52 pub fn validate(&self) -> Result<(), JsonRpcError> {
55 if self.jsonrpc != JSONRPC_VERSION {
56 return Err(JsonRpcError::invalid_request(format!(
57 "Invalid JSON-RPC version: expected '{}', got '{}'",
58 JSONRPC_VERSION, self.jsonrpc
59 )));
60 }
61 Ok(())
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct JsonRpcResultResponse {
68 pub jsonrpc: String,
70 pub id: RequestId,
72 pub result: Value,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct JsonRpcErrorResponse {
79 pub jsonrpc: String,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub id: Option<RequestId>,
84 pub error: JsonRpcError,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(untagged)]
91pub enum JsonRpcResponse {
92 Result(JsonRpcResultResponse),
94 Error(JsonRpcErrorResponse),
96}
97
98impl JsonRpcResponse {
99 pub fn result(id: RequestId, result: Value) -> Self {
101 Self::Result(JsonRpcResultResponse {
102 jsonrpc: JSONRPC_VERSION.to_string(),
103 id,
104 result,
105 })
106 }
107
108 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
110 Self::Error(JsonRpcErrorResponse {
111 jsonrpc: JSONRPC_VERSION.to_string(),
112 id,
113 error,
114 })
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(untagged)]
121pub enum JsonRpcMessage {
122 Single(JsonRpcRequest),
124 Batch(Vec<JsonRpcRequest>),
126}
127
128impl JsonRpcMessage {
129 pub fn is_batch(&self) -> bool {
131 matches!(self, JsonRpcMessage::Batch(_))
132 }
133
134 pub fn len(&self) -> usize {
136 match self {
137 JsonRpcMessage::Single(_) => 1,
138 JsonRpcMessage::Batch(batch) => batch.len(),
139 }
140 }
141
142 pub fn is_empty(&self) -> bool {
144 self.len() == 0
145 }
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150#[serde(untagged)]
151pub enum JsonRpcResponseMessage {
152 Single(JsonRpcResponse),
154 Batch(Vec<JsonRpcResponse>),
156}
157
158impl JsonRpcResponseMessage {
159 pub fn is_batch(&self) -> bool {
161 matches!(self, JsonRpcResponseMessage::Batch(_))
162 }
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct JsonRpcNotification {
168 pub jsonrpc: String,
169 pub method: String,
170 #[serde(default, skip_serializing_if = "Option::is_none")]
171 pub params: Option<Value>,
172}
173
174impl JsonRpcNotification {
175 pub fn new(method: impl Into<String>) -> Self {
176 Self {
177 jsonrpc: JSONRPC_VERSION.to_string(),
178 method: method.into(),
179 params: None,
180 }
181 }
182
183 pub fn with_params(mut self, params: Value) -> Self {
184 self.params = Some(params);
185 self
186 }
187}
188
189pub mod notifications {
191 pub const INITIALIZED: &str = "notifications/initialized";
193 pub const CANCELLED: &str = "notifications/cancelled";
195 pub const PROGRESS: &str = "notifications/progress";
197 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
199 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
201 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
203 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
205 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
207 pub const MESSAGE: &str = "notifications/message";
209 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status_changed";
211 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
213}
214
215#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
219#[serde(rename_all = "lowercase")]
220pub enum LogLevel {
221 Emergency,
223 Alert,
225 Critical,
227 Error,
229 Warning,
231 Notice,
233 #[default]
235 Info,
236 Debug,
238}
239
240impl std::fmt::Display for LogLevel {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 match self {
243 LogLevel::Emergency => write!(f, "emergency"),
244 LogLevel::Alert => write!(f, "alert"),
245 LogLevel::Critical => write!(f, "critical"),
246 LogLevel::Error => write!(f, "error"),
247 LogLevel::Warning => write!(f, "warning"),
248 LogLevel::Notice => write!(f, "notice"),
249 LogLevel::Info => write!(f, "info"),
250 LogLevel::Debug => write!(f, "debug"),
251 }
252 }
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct LoggingMessageParams {
258 pub level: LogLevel,
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub logger: Option<String>,
263 #[serde(skip_serializing_if = "Option::is_none")]
265 pub data: Option<Value>,
266}
267
268impl LoggingMessageParams {
269 pub fn new(level: LogLevel) -> Self {
271 Self {
272 level,
273 logger: None,
274 data: None,
275 }
276 }
277
278 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
280 self.logger = Some(logger.into());
281 self
282 }
283
284 pub fn with_data(mut self, data: Value) -> Self {
286 self.data = Some(data);
287 self
288 }
289}
290
291#[derive(Debug, Clone, Deserialize)]
293pub struct SetLogLevelParams {
294 pub level: LogLevel,
296}
297
298#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
300#[serde(untagged)]
301pub enum RequestId {
302 String(String),
303 Number(i64),
304}
305
306impl From<String> for RequestId {
307 fn from(s: String) -> Self {
308 RequestId::String(s)
309 }
310}
311
312impl From<&str> for RequestId {
313 fn from(s: &str) -> Self {
314 RequestId::String(s.to_string())
315 }
316}
317
318impl From<i64> for RequestId {
319 fn from(n: i64) -> Self {
320 RequestId::Number(n)
321 }
322}
323
324impl From<i32> for RequestId {
325 fn from(n: i32) -> Self {
326 RequestId::Number(n as i64)
327 }
328}
329
330#[derive(Debug, Clone)]
336pub enum McpRequest {
337 Initialize(InitializeParams),
339 ListTools(ListToolsParams),
341 CallTool(CallToolParams),
343 ListResources(ListResourcesParams),
345 ListResourceTemplates(ListResourceTemplatesParams),
347 ReadResource(ReadResourceParams),
349 SubscribeResource(SubscribeResourceParams),
351 UnsubscribeResource(UnsubscribeResourceParams),
353 ListPrompts(ListPromptsParams),
355 GetPrompt(GetPromptParams),
357 EnqueueTask(EnqueueTaskParams),
359 ListTasks(ListTasksParams),
361 GetTaskInfo(GetTaskInfoParams),
363 GetTaskResult(GetTaskResultParams),
365 CancelTask(CancelTaskParams),
367 Ping,
369 SetLoggingLevel(SetLogLevelParams),
371 Complete(CompleteParams),
373 Unknown {
375 method: String,
376 params: Option<Value>,
377 },
378}
379
380impl McpRequest {
381 pub fn method_name(&self) -> &str {
383 match self {
384 McpRequest::Initialize(_) => "initialize",
385 McpRequest::ListTools(_) => "tools/list",
386 McpRequest::CallTool(_) => "tools/call",
387 McpRequest::ListResources(_) => "resources/list",
388 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
389 McpRequest::ReadResource(_) => "resources/read",
390 McpRequest::SubscribeResource(_) => "resources/subscribe",
391 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
392 McpRequest::ListPrompts(_) => "prompts/list",
393 McpRequest::GetPrompt(_) => "prompts/get",
394 McpRequest::EnqueueTask(_) => "tasks/enqueue",
395 McpRequest::ListTasks(_) => "tasks/list",
396 McpRequest::GetTaskInfo(_) => "tasks/get",
397 McpRequest::GetTaskResult(_) => "tasks/result",
398 McpRequest::CancelTask(_) => "tasks/cancel",
399 McpRequest::Ping => "ping",
400 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
401 McpRequest::Complete(_) => "completion/complete",
402 McpRequest::Unknown { method, .. } => method,
403 }
404 }
405}
406
407#[derive(Debug, Clone)]
409pub enum McpNotification {
410 Initialized,
412 Cancelled(CancelledParams),
414 Progress(ProgressParams),
416 RootsListChanged,
418 Unknown {
420 method: String,
421 params: Option<Value>,
422 },
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
427#[serde(rename_all = "camelCase")]
428pub struct CancelledParams {
429 pub request_id: RequestId,
431 #[serde(skip_serializing_if = "Option::is_none")]
433 pub reason: Option<String>,
434}
435
436#[derive(Debug, Clone, Serialize, Deserialize)]
438#[serde(rename_all = "camelCase")]
439pub struct ProgressParams {
440 pub progress_token: ProgressToken,
442 pub progress: f64,
444 #[serde(skip_serializing_if = "Option::is_none")]
446 pub total: Option<f64>,
447 #[serde(skip_serializing_if = "Option::is_none")]
449 pub message: Option<String>,
450}
451
452#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
454#[serde(untagged)]
455pub enum ProgressToken {
456 String(String),
457 Number(i64),
458}
459
460#[derive(Debug, Clone, Default, Serialize, Deserialize)]
462#[serde(rename_all = "camelCase")]
463pub struct RequestMeta {
464 #[serde(skip_serializing_if = "Option::is_none")]
466 pub progress_token: Option<ProgressToken>,
467}
468
469#[derive(Debug, Clone, Serialize)]
471#[serde(untagged)]
472pub enum McpResponse {
473 Initialize(InitializeResult),
474 ListTools(ListToolsResult),
475 CallTool(CallToolResult),
476 ListResources(ListResourcesResult),
477 ListResourceTemplates(ListResourceTemplatesResult),
478 ReadResource(ReadResourceResult),
479 SubscribeResource(EmptyResult),
480 UnsubscribeResource(EmptyResult),
481 ListPrompts(ListPromptsResult),
482 GetPrompt(GetPromptResult),
483 EnqueueTask(EnqueueTaskResult),
484 ListTasks(ListTasksResult),
485 GetTaskInfo(TaskInfo),
486 GetTaskResult(GetTaskResultResult),
487 CancelTask(CancelTaskResult),
488 SetLoggingLevel(EmptyResult),
489 Complete(CompleteResult),
490 Pong(EmptyResult),
491 Empty(EmptyResult),
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
499#[serde(rename_all = "camelCase")]
500pub struct InitializeParams {
501 pub protocol_version: String,
502 pub capabilities: ClientCapabilities,
503 pub client_info: Implementation,
504}
505
506#[derive(Debug, Clone, Default, Deserialize, Serialize)]
507pub struct ClientCapabilities {
508 #[serde(default, skip_serializing_if = "Option::is_none")]
509 pub roots: Option<RootsCapability>,
510 #[serde(default, skip_serializing_if = "Option::is_none")]
511 pub sampling: Option<SamplingCapability>,
512 #[serde(default, skip_serializing_if = "Option::is_none")]
513 pub elicitation: Option<ElicitationCapability>,
514}
515
516#[derive(Debug, Clone, Default, Deserialize, Serialize)]
518pub struct ElicitationCapability {
519 #[serde(default, skip_serializing_if = "Option::is_none")]
521 pub form: Option<ElicitationFormCapability>,
522 #[serde(default, skip_serializing_if = "Option::is_none")]
524 pub url: Option<ElicitationUrlCapability>,
525}
526
527#[derive(Debug, Clone, Default, Deserialize, Serialize)]
529pub struct ElicitationFormCapability {}
530
531#[derive(Debug, Clone, Default, Deserialize, Serialize)]
533pub struct ElicitationUrlCapability {}
534
535#[derive(Debug, Clone, Default, Deserialize, Serialize)]
537#[serde(rename_all = "camelCase")]
538pub struct RootsCapability {
539 #[serde(default)]
541 pub list_changed: bool,
542}
543
544#[derive(Debug, Clone, Deserialize, Serialize)]
551pub struct Root {
552 pub uri: String,
554 #[serde(default, skip_serializing_if = "Option::is_none")]
556 pub name: Option<String>,
557}
558
559impl Root {
560 pub fn new(uri: impl Into<String>) -> Self {
562 Self {
563 uri: uri.into(),
564 name: None,
565 }
566 }
567
568 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
570 Self {
571 uri: uri.into(),
572 name: Some(name.into()),
573 }
574 }
575}
576
577#[derive(Debug, Clone, Default, Deserialize, Serialize)]
579pub struct ListRootsParams {
580 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
582 pub meta: Option<RequestMeta>,
583}
584
585#[derive(Debug, Clone, Deserialize, Serialize)]
587pub struct ListRootsResult {
588 pub roots: Vec<Root>,
590}
591
592#[derive(Debug, Clone, Default, Deserialize, Serialize)]
593pub struct SamplingCapability {}
594
595#[derive(Debug, Clone, Default, Deserialize, Serialize)]
597pub struct CompletionsCapability {}
598
599#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct PromptReference {
606 #[serde(rename = "type")]
608 pub ref_type: String,
609 pub name: String,
611}
612
613impl PromptReference {
614 pub fn new(name: impl Into<String>) -> Self {
616 Self {
617 ref_type: "ref/prompt".to_string(),
618 name: name.into(),
619 }
620 }
621}
622
623#[derive(Debug, Clone, Serialize, Deserialize)]
625pub struct ResourceReference {
626 #[serde(rename = "type")]
628 pub ref_type: String,
629 pub uri: String,
631}
632
633impl ResourceReference {
634 pub fn new(uri: impl Into<String>) -> Self {
636 Self {
637 ref_type: "ref/resource".to_string(),
638 uri: uri.into(),
639 }
640 }
641}
642
643#[derive(Debug, Clone, Serialize, Deserialize)]
645#[serde(tag = "type")]
646pub enum CompletionReference {
647 #[serde(rename = "ref/prompt")]
649 Prompt {
650 name: String,
652 },
653 #[serde(rename = "ref/resource")]
655 Resource {
656 uri: String,
658 },
659}
660
661impl CompletionReference {
662 pub fn prompt(name: impl Into<String>) -> Self {
664 Self::Prompt { name: name.into() }
665 }
666
667 pub fn resource(uri: impl Into<String>) -> Self {
669 Self::Resource { uri: uri.into() }
670 }
671}
672
673#[derive(Debug, Clone, Serialize, Deserialize)]
675pub struct CompletionArgument {
676 pub name: String,
678 pub value: String,
680}
681
682impl CompletionArgument {
683 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
685 Self {
686 name: name.into(),
687 value: value.into(),
688 }
689 }
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize)]
694#[serde(rename_all = "camelCase")]
695pub struct CompleteParams {
696 #[serde(rename = "ref")]
698 pub reference: CompletionReference,
699 pub argument: CompletionArgument,
701}
702
703#[derive(Debug, Clone, Serialize, Deserialize)]
705#[serde(rename_all = "camelCase")]
706pub struct Completion {
707 pub values: Vec<String>,
709 #[serde(default, skip_serializing_if = "Option::is_none")]
711 pub total: Option<u32>,
712 #[serde(default, skip_serializing_if = "Option::is_none")]
714 pub has_more: Option<bool>,
715}
716
717impl Completion {
718 pub fn new(values: Vec<String>) -> Self {
720 Self {
721 values,
722 total: None,
723 has_more: None,
724 }
725 }
726
727 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
729 Self {
730 values,
731 total: Some(total),
732 has_more: Some(has_more),
733 }
734 }
735}
736
737#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct CompleteResult {
740 pub completion: Completion,
742}
743
744impl CompleteResult {
745 pub fn new(values: Vec<String>) -> Self {
747 Self {
748 completion: Completion::new(values),
749 }
750 }
751
752 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
754 Self {
755 completion: Completion::with_pagination(values, total, has_more),
756 }
757 }
758}
759
760#[derive(Debug, Clone, Serialize, Deserialize)]
766pub struct ModelHint {
767 pub name: String,
769}
770
771impl ModelHint {
772 pub fn new(name: impl Into<String>) -> Self {
774 Self { name: name.into() }
775 }
776}
777
778#[derive(Debug, Clone, Default, Serialize, Deserialize)]
780#[serde(rename_all = "camelCase")]
781pub struct ModelPreferences {
782 #[serde(default, skip_serializing_if = "Option::is_none")]
784 pub speed_priority: Option<f64>,
785 #[serde(default, skip_serializing_if = "Option::is_none")]
787 pub intelligence_priority: Option<f64>,
788 #[serde(default, skip_serializing_if = "Option::is_none")]
790 pub cost_priority: Option<f64>,
791 #[serde(default, skip_serializing_if = "Vec::is_empty")]
793 pub hints: Vec<ModelHint>,
794}
795
796impl ModelPreferences {
797 pub fn new() -> Self {
799 Self::default()
800 }
801
802 pub fn speed(mut self, priority: f64) -> Self {
804 self.speed_priority = Some(priority.clamp(0.0, 1.0));
805 self
806 }
807
808 pub fn intelligence(mut self, priority: f64) -> Self {
810 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
811 self
812 }
813
814 pub fn cost(mut self, priority: f64) -> Self {
816 self.cost_priority = Some(priority.clamp(0.0, 1.0));
817 self
818 }
819
820 pub fn hint(mut self, name: impl Into<String>) -> Self {
822 self.hints.push(ModelHint::new(name));
823 self
824 }
825}
826
827#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
829#[serde(rename_all = "camelCase")]
830pub enum IncludeContext {
831 AllServers,
833 ThisServer,
835 #[default]
837 None,
838}
839
840#[derive(Debug, Clone, Serialize, Deserialize)]
842pub struct SamplingMessage {
843 pub role: ContentRole,
845 pub content: SamplingContent,
847}
848
849impl SamplingMessage {
850 pub fn user(text: impl Into<String>) -> Self {
852 Self {
853 role: ContentRole::User,
854 content: SamplingContent::Text { text: text.into() },
855 }
856 }
857
858 pub fn assistant(text: impl Into<String>) -> Self {
860 Self {
861 role: ContentRole::Assistant,
862 content: SamplingContent::Text { text: text.into() },
863 }
864 }
865}
866
867#[derive(Debug, Clone, Serialize, Deserialize)]
871#[serde(rename_all = "camelCase")]
872pub struct SamplingTool {
873 pub name: String,
875 #[serde(skip_serializing_if = "Option::is_none")]
877 pub description: Option<String>,
878 pub input_schema: Value,
880}
881
882#[derive(Debug, Clone, Serialize, Deserialize)]
886#[serde(rename_all = "camelCase")]
887pub struct ToolChoice {
888 #[serde(rename = "type")]
893 pub mode: String,
894}
895
896impl ToolChoice {
897 pub fn auto() -> Self {
899 Self {
900 mode: "auto".to_string(),
901 }
902 }
903
904 pub fn required() -> Self {
906 Self {
907 mode: "required".to_string(),
908 }
909 }
910
911 pub fn none() -> Self {
913 Self {
914 mode: "none".to_string(),
915 }
916 }
917}
918
919#[derive(Debug, Clone, Serialize, Deserialize)]
921#[serde(tag = "type", rename_all = "lowercase")]
922pub enum SamplingContent {
923 Text {
925 text: String,
927 },
928 Image {
930 data: String,
932 #[serde(rename = "mimeType")]
934 mime_type: String,
935 },
936 Audio {
938 data: String,
940 #[serde(rename = "mimeType")]
942 mime_type: String,
943 },
944 #[serde(rename = "tool_use")]
946 ToolUse {
947 id: String,
949 name: String,
951 input: Value,
953 },
954 #[serde(rename = "tool_result")]
956 ToolResult {
957 tool_use_id: String,
959 content: Vec<SamplingContent>,
961 #[serde(default, skip_serializing_if = "Option::is_none")]
963 is_error: Option<bool>,
964 },
965}
966
967impl SamplingContent {
968 pub fn as_text(&self) -> Option<&str> {
987 match self {
988 SamplingContent::Text { text } => Some(text),
989 _ => None,
990 }
991 }
992}
993
994#[derive(Debug, Clone, Serialize, Deserialize)]
999#[serde(untagged)]
1000pub enum SamplingContentOrArray {
1001 Single(SamplingContent),
1003 Array(Vec<SamplingContent>),
1005}
1006
1007impl SamplingContentOrArray {
1008 pub fn items(&self) -> Vec<&SamplingContent> {
1010 match self {
1011 Self::Single(c) => vec![c],
1012 Self::Array(arr) => arr.iter().collect(),
1013 }
1014 }
1015
1016 pub fn into_items(self) -> Vec<SamplingContent> {
1018 match self {
1019 Self::Single(c) => vec![c],
1020 Self::Array(arr) => arr,
1021 }
1022 }
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1027#[serde(rename_all = "camelCase")]
1028pub struct CreateMessageParams {
1029 pub messages: Vec<SamplingMessage>,
1031 pub max_tokens: u32,
1033 #[serde(default, skip_serializing_if = "Option::is_none")]
1035 pub system_prompt: Option<String>,
1036 #[serde(default, skip_serializing_if = "Option::is_none")]
1038 pub temperature: Option<f64>,
1039 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1041 pub stop_sequences: Vec<String>,
1042 #[serde(default, skip_serializing_if = "Option::is_none")]
1044 pub model_preferences: Option<ModelPreferences>,
1045 #[serde(default, skip_serializing_if = "Option::is_none")]
1047 pub include_context: Option<IncludeContext>,
1048 #[serde(default, skip_serializing_if = "Option::is_none")]
1050 pub metadata: Option<serde_json::Map<String, Value>>,
1051 #[serde(default, skip_serializing_if = "Option::is_none")]
1053 pub tools: Option<Vec<SamplingTool>>,
1054 #[serde(default, skip_serializing_if = "Option::is_none")]
1056 pub tool_choice: Option<ToolChoice>,
1057}
1058
1059impl CreateMessageParams {
1060 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1062 Self {
1063 messages,
1064 max_tokens,
1065 system_prompt: None,
1066 temperature: None,
1067 stop_sequences: Vec::new(),
1068 model_preferences: None,
1069 include_context: None,
1070 metadata: None,
1071 tools: None,
1072 tool_choice: None,
1073 }
1074 }
1075
1076 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1078 self.system_prompt = Some(prompt.into());
1079 self
1080 }
1081
1082 pub fn temperature(mut self, temp: f64) -> Self {
1084 self.temperature = Some(temp.clamp(0.0, 1.0));
1085 self
1086 }
1087
1088 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1090 self.stop_sequences.push(seq.into());
1091 self
1092 }
1093
1094 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1096 self.model_preferences = Some(prefs);
1097 self
1098 }
1099
1100 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1102 self.include_context = Some(mode);
1103 self
1104 }
1105
1106 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1108 self.tools = Some(tools);
1109 self
1110 }
1111
1112 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1114 self.tool_choice = Some(choice);
1115 self
1116 }
1117}
1118
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1121#[serde(rename_all = "camelCase")]
1122pub struct CreateMessageResult {
1123 pub content: SamplingContentOrArray,
1125 pub model: String,
1127 pub role: ContentRole,
1129 #[serde(default, skip_serializing_if = "Option::is_none")]
1131 pub stop_reason: Option<String>,
1132}
1133
1134impl CreateMessageResult {
1135 pub fn content_items(&self) -> Vec<&SamplingContent> {
1137 self.content.items()
1138 }
1139
1140 pub fn first_text(&self) -> Option<&str> {
1161 self.content.items().iter().find_map(|c| c.as_text())
1162 }
1163}
1164
1165#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1167#[serde(rename_all = "camelCase")]
1168pub struct Implementation {
1169 pub name: String,
1171 pub version: String,
1173 #[serde(skip_serializing_if = "Option::is_none")]
1175 pub title: Option<String>,
1176 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub description: Option<String>,
1179 #[serde(skip_serializing_if = "Option::is_none")]
1181 pub icons: Option<Vec<ToolIcon>>,
1182 #[serde(skip_serializing_if = "Option::is_none")]
1184 pub website_url: Option<String>,
1185}
1186
1187#[derive(Debug, Clone, Serialize, Deserialize)]
1188#[serde(rename_all = "camelCase")]
1189pub struct InitializeResult {
1190 pub protocol_version: String,
1191 pub capabilities: ServerCapabilities,
1192 pub server_info: Implementation,
1193 #[serde(skip_serializing_if = "Option::is_none")]
1196 pub instructions: Option<String>,
1197}
1198
1199#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1200#[serde(rename_all = "camelCase")]
1201pub struct ServerCapabilities {
1202 #[serde(default, skip_serializing_if = "Option::is_none")]
1203 pub tools: Option<ToolsCapability>,
1204 #[serde(default, skip_serializing_if = "Option::is_none")]
1205 pub resources: Option<ResourcesCapability>,
1206 #[serde(default, skip_serializing_if = "Option::is_none")]
1207 pub prompts: Option<PromptsCapability>,
1208 #[serde(default, skip_serializing_if = "Option::is_none")]
1210 pub logging: Option<LoggingCapability>,
1211 #[serde(default, skip_serializing_if = "Option::is_none")]
1212 pub tasks: Option<TasksCapability>,
1213 #[serde(default, skip_serializing_if = "Option::is_none")]
1215 pub completions: Option<CompletionsCapability>,
1216}
1217
1218#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1220pub struct LoggingCapability {}
1221
1222#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1224#[serde(rename_all = "camelCase")]
1225pub struct TasksCapability {
1226 #[serde(default, skip_serializing_if = "Option::is_none")]
1228 pub default_poll_interval: Option<u64>,
1229}
1230
1231#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1232#[serde(rename_all = "camelCase")]
1233pub struct ToolsCapability {
1234 #[serde(default)]
1235 pub list_changed: bool,
1236}
1237
1238#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1239#[serde(rename_all = "camelCase")]
1240pub struct ResourcesCapability {
1241 #[serde(default)]
1242 pub subscribe: bool,
1243 #[serde(default)]
1244 pub list_changed: bool,
1245}
1246
1247#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1248#[serde(rename_all = "camelCase")]
1249pub struct PromptsCapability {
1250 #[serde(default)]
1251 pub list_changed: bool,
1252}
1253
1254#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1259pub struct ListToolsParams {
1260 #[serde(default)]
1261 pub cursor: Option<String>,
1262}
1263
1264#[derive(Debug, Clone, Serialize, Deserialize)]
1265#[serde(rename_all = "camelCase")]
1266pub struct ListToolsResult {
1267 pub tools: Vec<ToolDefinition>,
1268 #[serde(default, skip_serializing_if = "Option::is_none")]
1269 pub next_cursor: Option<String>,
1270}
1271
1272#[derive(Debug, Clone, Serialize, Deserialize)]
1274#[serde(rename_all = "camelCase")]
1275pub struct ToolDefinition {
1276 pub name: String,
1277 #[serde(skip_serializing_if = "Option::is_none")]
1279 pub title: Option<String>,
1280 #[serde(skip_serializing_if = "Option::is_none")]
1281 pub description: Option<String>,
1282 pub input_schema: Value,
1283 #[serde(skip_serializing_if = "Option::is_none")]
1285 pub output_schema: Option<Value>,
1286 #[serde(skip_serializing_if = "Option::is_none")]
1288 pub icons: Option<Vec<ToolIcon>>,
1289 #[serde(skip_serializing_if = "Option::is_none")]
1292 pub annotations: Option<ToolAnnotations>,
1293}
1294
1295#[derive(Debug, Clone, Serialize, Deserialize)]
1297#[serde(rename_all = "camelCase")]
1298pub struct ToolIcon {
1299 pub src: String,
1301 #[serde(skip_serializing_if = "Option::is_none")]
1303 pub mime_type: Option<String>,
1304 #[serde(skip_serializing_if = "Option::is_none")]
1306 pub sizes: Option<Vec<String>>,
1307}
1308
1309#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1312#[serde(rename_all = "camelCase")]
1313pub struct ToolAnnotations {
1314 #[serde(skip_serializing_if = "Option::is_none")]
1316 pub title: Option<String>,
1317 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1319 pub read_only_hint: bool,
1320 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1323 pub destructive_hint: bool,
1324 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1327 pub idempotent_hint: bool,
1328 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1330 pub open_world_hint: bool,
1331}
1332
1333impl ToolAnnotations {
1334 pub fn is_read_only(&self) -> bool {
1336 self.read_only_hint
1337 }
1338
1339 pub fn is_destructive(&self) -> bool {
1341 self.destructive_hint
1342 }
1343
1344 pub fn is_idempotent(&self) -> bool {
1346 self.idempotent_hint
1347 }
1348
1349 pub fn is_open_world(&self) -> bool {
1351 self.open_world_hint
1352 }
1353}
1354
1355impl ToolDefinition {
1356 pub fn is_read_only(&self) -> bool {
1360 self.annotations.as_ref().is_some_and(|a| a.read_only_hint)
1361 }
1362
1363 pub fn is_destructive(&self) -> bool {
1367 self.annotations.as_ref().is_none_or(|a| a.destructive_hint)
1368 }
1369
1370 pub fn is_idempotent(&self) -> bool {
1374 self.annotations.as_ref().is_some_and(|a| a.idempotent_hint)
1375 }
1376
1377 pub fn is_open_world(&self) -> bool {
1381 self.annotations.as_ref().is_none_or(|a| a.open_world_hint)
1382 }
1383}
1384
1385fn default_true() -> bool {
1386 true
1387}
1388
1389fn is_true(v: &bool) -> bool {
1390 *v
1391}
1392
1393#[derive(Debug, Clone, Serialize, Deserialize)]
1394pub struct CallToolParams {
1395 pub name: String,
1396 #[serde(default)]
1397 pub arguments: Value,
1398 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1400 pub meta: Option<RequestMeta>,
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize)]
1424#[serde(rename_all = "camelCase")]
1425pub struct CallToolResult {
1426 pub content: Vec<Content>,
1428 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1430 pub is_error: bool,
1431 #[serde(default, skip_serializing_if = "Option::is_none")]
1433 pub structured_content: Option<Value>,
1434}
1435
1436impl CallToolResult {
1437 pub fn text(text: impl Into<String>) -> Self {
1441 Self {
1442 content: vec![Content::Text {
1443 text: text.into(),
1444 annotations: None,
1445 }],
1446 is_error: false,
1447 structured_content: None,
1448 }
1449 }
1450
1451 pub fn error(message: impl Into<String>) -> Self {
1456 Self {
1457 content: vec![Content::Text {
1458 text: message.into(),
1459 annotations: None,
1460 }],
1461 is_error: true,
1462 structured_content: None,
1463 }
1464 }
1465
1466 pub fn json(value: Value) -> Self {
1474 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1475 Self {
1476 content: vec![Content::Text {
1477 text,
1478 annotations: None,
1479 }],
1480 is_error: false,
1481 structured_content: Some(value),
1482 }
1483 }
1484
1485 pub fn from_serialize(
1517 value: &impl serde::Serialize,
1518 ) -> std::result::Result<Self, crate::error::Error> {
1519 let json_value = serde_json::to_value(value)
1520 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1521 Ok(Self::json(json_value))
1522 }
1523
1524 pub fn from_list<T: serde::Serialize>(
1551 key: &str,
1552 items: &[T],
1553 ) -> std::result::Result<Self, crate::error::Error> {
1554 Self::from_serialize(&serde_json::json!({ key: items, "count": items.len() }))
1555 }
1556
1557 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1559 Self {
1560 content: vec![Content::Image {
1561 data: data.into(),
1562 mime_type: mime_type.into(),
1563 annotations: None,
1564 }],
1565 is_error: false,
1566 structured_content: None,
1567 }
1568 }
1569
1570 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1572 Self {
1573 content: vec![Content::Audio {
1574 data: data.into(),
1575 mime_type: mime_type.into(),
1576 annotations: None,
1577 }],
1578 is_error: false,
1579 structured_content: None,
1580 }
1581 }
1582
1583 pub fn resource_link(uri: impl Into<String>) -> Self {
1585 Self {
1586 content: vec![Content::ResourceLink {
1587 uri: uri.into(),
1588 name: None,
1589 description: None,
1590 mime_type: None,
1591 annotations: None,
1592 }],
1593 is_error: false,
1594 structured_content: None,
1595 }
1596 }
1597
1598 pub fn resource_link_with_meta(
1600 uri: impl Into<String>,
1601 name: Option<String>,
1602 description: Option<String>,
1603 mime_type: Option<String>,
1604 ) -> Self {
1605 Self {
1606 content: vec![Content::ResourceLink {
1607 uri: uri.into(),
1608 name,
1609 description,
1610 mime_type,
1611 annotations: None,
1612 }],
1613 is_error: false,
1614 structured_content: None,
1615 }
1616 }
1617
1618 pub fn resource(resource: ResourceContent) -> Self {
1620 Self {
1621 content: vec![Content::Resource {
1622 resource,
1623 annotations: None,
1624 }],
1625 is_error: false,
1626 structured_content: None,
1627 }
1628 }
1629
1630 pub fn all_text(&self) -> String {
1644 self.content.iter().filter_map(|c| c.as_text()).collect()
1645 }
1646
1647 pub fn first_text(&self) -> Option<&str> {
1660 self.content.iter().find_map(|c| c.as_text())
1661 }
1662
1663 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
1680 if let Some(ref sc) = self.structured_content {
1681 return Some(Ok(sc.clone()));
1682 }
1683 self.first_text().map(serde_json::from_str)
1684 }
1685
1686 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
1706 if let Some(ref sc) = self.structured_content {
1707 return Some(serde_json::from_value(sc.clone()));
1708 }
1709 self.first_text().map(serde_json::from_str)
1710 }
1711}
1712
1713#[derive(Debug, Clone, Serialize, Deserialize)]
1718#[serde(tag = "type", rename_all = "snake_case")]
1719pub enum Content {
1720 Text {
1722 text: String,
1724 #[serde(skip_serializing_if = "Option::is_none")]
1726 annotations: Option<ContentAnnotations>,
1727 },
1728 Image {
1730 data: String,
1732 #[serde(rename = "mimeType")]
1734 mime_type: String,
1735 #[serde(skip_serializing_if = "Option::is_none")]
1737 annotations: Option<ContentAnnotations>,
1738 },
1739 Audio {
1741 data: String,
1743 #[serde(rename = "mimeType")]
1745 mime_type: String,
1746 #[serde(skip_serializing_if = "Option::is_none")]
1748 annotations: Option<ContentAnnotations>,
1749 },
1750 Resource {
1752 resource: ResourceContent,
1754 #[serde(skip_serializing_if = "Option::is_none")]
1756 annotations: Option<ContentAnnotations>,
1757 },
1758 ResourceLink {
1760 uri: String,
1762 #[serde(skip_serializing_if = "Option::is_none")]
1764 name: Option<String>,
1765 #[serde(skip_serializing_if = "Option::is_none")]
1767 description: Option<String>,
1768 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1770 mime_type: Option<String>,
1771 #[serde(skip_serializing_if = "Option::is_none")]
1772 annotations: Option<ContentAnnotations>,
1773 },
1774}
1775
1776#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1778pub struct ContentAnnotations {
1779 #[serde(skip_serializing_if = "Option::is_none")]
1781 pub audience: Option<Vec<ContentRole>>,
1782 #[serde(skip_serializing_if = "Option::is_none")]
1784 pub priority: Option<f64>,
1785}
1786
1787impl Content {
1788 pub fn text(text: impl Into<String>) -> Self {
1814 Content::Text {
1815 text: text.into(),
1816 annotations: None,
1817 }
1818 }
1819
1820 pub fn as_text(&self) -> Option<&str> {
1833 match self {
1834 Content::Text { text, .. } => Some(text),
1835 _ => None,
1836 }
1837 }
1838}
1839
1840#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1844#[serde(rename_all = "lowercase")]
1845pub enum ContentRole {
1846 User,
1848 Assistant,
1850}
1851
1852#[derive(Debug, Clone, Serialize, Deserialize)]
1856#[serde(rename_all = "camelCase")]
1857pub struct ResourceContent {
1858 pub uri: String,
1860 #[serde(skip_serializing_if = "Option::is_none")]
1862 pub mime_type: Option<String>,
1863 #[serde(skip_serializing_if = "Option::is_none")]
1865 pub text: Option<String>,
1866 #[serde(skip_serializing_if = "Option::is_none")]
1868 pub blob: Option<String>,
1869}
1870
1871#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1876pub struct ListResourcesParams {
1877 #[serde(default)]
1878 pub cursor: Option<String>,
1879}
1880
1881#[derive(Debug, Clone, Serialize, Deserialize)]
1882#[serde(rename_all = "camelCase")]
1883pub struct ListResourcesResult {
1884 pub resources: Vec<ResourceDefinition>,
1885 #[serde(default, skip_serializing_if = "Option::is_none")]
1886 pub next_cursor: Option<String>,
1887}
1888
1889#[derive(Debug, Clone, Serialize, Deserialize)]
1890#[serde(rename_all = "camelCase")]
1891pub struct ResourceDefinition {
1892 pub uri: String,
1893 pub name: String,
1894 #[serde(skip_serializing_if = "Option::is_none")]
1896 pub title: Option<String>,
1897 #[serde(skip_serializing_if = "Option::is_none")]
1898 pub description: Option<String>,
1899 #[serde(skip_serializing_if = "Option::is_none")]
1900 pub mime_type: Option<String>,
1901 #[serde(skip_serializing_if = "Option::is_none")]
1903 pub icons: Option<Vec<ToolIcon>>,
1904 #[serde(skip_serializing_if = "Option::is_none")]
1906 pub size: Option<u64>,
1907}
1908
1909#[derive(Debug, Clone, Serialize, Deserialize)]
1910pub struct ReadResourceParams {
1911 pub uri: String,
1912}
1913
1914#[derive(Debug, Clone, Serialize, Deserialize)]
1915pub struct ReadResourceResult {
1916 pub contents: Vec<ResourceContent>,
1917}
1918
1919impl ReadResourceResult {
1920 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
1930 Self {
1931 contents: vec![ResourceContent {
1932 uri: uri.into(),
1933 mime_type: Some("text/plain".to_string()),
1934 text: Some(content.into()),
1935 blob: None,
1936 }],
1937 }
1938 }
1939
1940 pub fn text_with_mime(
1954 uri: impl Into<String>,
1955 content: impl Into<String>,
1956 mime_type: impl Into<String>,
1957 ) -> Self {
1958 Self {
1959 contents: vec![ResourceContent {
1960 uri: uri.into(),
1961 mime_type: Some(mime_type.into()),
1962 text: Some(content.into()),
1963 blob: None,
1964 }],
1965 }
1966 }
1967
1968 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
1982 let json_string =
1983 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
1984 Self {
1985 contents: vec![ResourceContent {
1986 uri: uri.into(),
1987 mime_type: Some("application/json".to_string()),
1988 text: Some(json_string),
1989 blob: None,
1990 }],
1991 }
1992 }
1993
1994 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
2005 use base64::Engine;
2006 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2007 Self {
2008 contents: vec![ResourceContent {
2009 uri: uri.into(),
2010 mime_type: Some("application/octet-stream".to_string()),
2011 text: None,
2012 blob: Some(encoded),
2013 }],
2014 }
2015 }
2016
2017 pub fn blob_with_mime(
2028 uri: impl Into<String>,
2029 bytes: &[u8],
2030 mime_type: impl Into<String>,
2031 ) -> Self {
2032 use base64::Engine;
2033 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2034 Self {
2035 contents: vec![ResourceContent {
2036 uri: uri.into(),
2037 mime_type: Some(mime_type.into()),
2038 text: None,
2039 blob: Some(encoded),
2040 }],
2041 }
2042 }
2043
2044 pub fn first_text(&self) -> Option<&str> {
2057 self.contents.first().and_then(|c| c.text.as_deref())
2058 }
2059
2060 pub fn first_uri(&self) -> Option<&str> {
2073 self.contents.first().map(|c| c.uri.as_str())
2074 }
2075
2076 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2091 self.first_text().map(serde_json::from_str)
2092 }
2093
2094 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2113 self.first_text().map(serde_json::from_str)
2114 }
2115}
2116
2117#[derive(Debug, Clone, Deserialize)]
2118pub struct SubscribeResourceParams {
2119 pub uri: String,
2120}
2121
2122#[derive(Debug, Clone, Deserialize)]
2123pub struct UnsubscribeResourceParams {
2124 pub uri: String,
2125}
2126
2127#[derive(Debug, Clone, Default, Deserialize)]
2129pub struct ListResourceTemplatesParams {
2130 #[serde(default)]
2132 pub cursor: Option<String>,
2133}
2134
2135#[derive(Debug, Clone, Serialize)]
2137#[serde(rename_all = "camelCase")]
2138pub struct ListResourceTemplatesResult {
2139 pub resource_templates: Vec<ResourceTemplateDefinition>,
2141 #[serde(skip_serializing_if = "Option::is_none")]
2143 pub next_cursor: Option<String>,
2144}
2145
2146#[derive(Debug, Clone, Serialize, Deserialize)]
2162#[serde(rename_all = "camelCase")]
2163pub struct ResourceTemplateDefinition {
2164 pub uri_template: String,
2166 pub name: String,
2168 #[serde(skip_serializing_if = "Option::is_none")]
2170 pub title: Option<String>,
2171 #[serde(skip_serializing_if = "Option::is_none")]
2173 pub description: Option<String>,
2174 #[serde(skip_serializing_if = "Option::is_none")]
2176 pub mime_type: Option<String>,
2177 #[serde(skip_serializing_if = "Option::is_none")]
2179 pub icons: Option<Vec<ToolIcon>>,
2180}
2181
2182#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2187pub struct ListPromptsParams {
2188 #[serde(default)]
2189 pub cursor: Option<String>,
2190}
2191
2192#[derive(Debug, Clone, Serialize, Deserialize)]
2193#[serde(rename_all = "camelCase")]
2194pub struct ListPromptsResult {
2195 pub prompts: Vec<PromptDefinition>,
2196 #[serde(default, skip_serializing_if = "Option::is_none")]
2197 pub next_cursor: Option<String>,
2198}
2199
2200#[derive(Debug, Clone, Serialize, Deserialize)]
2201pub struct PromptDefinition {
2202 pub name: String,
2203 #[serde(skip_serializing_if = "Option::is_none")]
2205 pub title: Option<String>,
2206 #[serde(skip_serializing_if = "Option::is_none")]
2207 pub description: Option<String>,
2208 #[serde(skip_serializing_if = "Option::is_none")]
2210 pub icons: Option<Vec<ToolIcon>>,
2211 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2212 pub arguments: Vec<PromptArgument>,
2213}
2214
2215#[derive(Debug, Clone, Serialize, Deserialize)]
2216pub struct PromptArgument {
2217 pub name: String,
2218 #[serde(skip_serializing_if = "Option::is_none")]
2219 pub description: Option<String>,
2220 #[serde(default)]
2221 pub required: bool,
2222}
2223
2224#[derive(Debug, Clone, Serialize, Deserialize)]
2225pub struct GetPromptParams {
2226 pub name: String,
2227 #[serde(default)]
2228 pub arguments: std::collections::HashMap<String, String>,
2229}
2230
2231#[derive(Debug, Clone, Serialize, Deserialize)]
2232pub struct GetPromptResult {
2233 #[serde(default, skip_serializing_if = "Option::is_none")]
2234 pub description: Option<String>,
2235 pub messages: Vec<PromptMessage>,
2236}
2237
2238impl GetPromptResult {
2239 pub fn user_message(text: impl Into<String>) -> Self {
2249 Self {
2250 description: None,
2251 messages: vec![PromptMessage {
2252 role: PromptRole::User,
2253 content: Content::Text {
2254 text: text.into(),
2255 annotations: None,
2256 },
2257 }],
2258 }
2259 }
2260
2261 pub fn user_message_with_description(
2274 text: impl Into<String>,
2275 description: impl Into<String>,
2276 ) -> Self {
2277 Self {
2278 description: Some(description.into()),
2279 messages: vec![PromptMessage {
2280 role: PromptRole::User,
2281 content: Content::Text {
2282 text: text.into(),
2283 annotations: None,
2284 },
2285 }],
2286 }
2287 }
2288
2289 pub fn assistant_message(text: impl Into<String>) -> Self {
2299 Self {
2300 description: None,
2301 messages: vec![PromptMessage {
2302 role: PromptRole::Assistant,
2303 content: Content::Text {
2304 text: text.into(),
2305 annotations: None,
2306 },
2307 }],
2308 }
2309 }
2310
2311 pub fn builder() -> GetPromptResultBuilder {
2326 GetPromptResultBuilder::new()
2327 }
2328
2329 pub fn first_message_text(&self) -> Option<&str> {
2343 self.messages.first().and_then(|m| m.content.as_text())
2344 }
2345
2346 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2361 self.first_message_text().map(serde_json::from_str)
2362 }
2363
2364 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2383 self.first_message_text().map(serde_json::from_str)
2384 }
2385}
2386
2387#[derive(Debug, Clone, Default)]
2389pub struct GetPromptResultBuilder {
2390 description: Option<String>,
2391 messages: Vec<PromptMessage>,
2392}
2393
2394impl GetPromptResultBuilder {
2395 pub fn new() -> Self {
2397 Self::default()
2398 }
2399
2400 pub fn description(mut self, description: impl Into<String>) -> Self {
2402 self.description = Some(description.into());
2403 self
2404 }
2405
2406 pub fn user(mut self, text: impl Into<String>) -> Self {
2408 self.messages.push(PromptMessage {
2409 role: PromptRole::User,
2410 content: Content::Text {
2411 text: text.into(),
2412 annotations: None,
2413 },
2414 });
2415 self
2416 }
2417
2418 pub fn assistant(mut self, text: impl Into<String>) -> Self {
2420 self.messages.push(PromptMessage {
2421 role: PromptRole::Assistant,
2422 content: Content::Text {
2423 text: text.into(),
2424 annotations: None,
2425 },
2426 });
2427 self
2428 }
2429
2430 pub fn build(self) -> GetPromptResult {
2432 GetPromptResult {
2433 description: self.description,
2434 messages: self.messages,
2435 }
2436 }
2437}
2438
2439#[derive(Debug, Clone, Serialize, Deserialize)]
2440pub struct PromptMessage {
2441 pub role: PromptRole,
2442 pub content: Content,
2443}
2444
2445#[derive(Debug, Clone, Serialize, Deserialize)]
2446#[serde(rename_all = "lowercase")]
2447pub enum PromptRole {
2448 User,
2449 Assistant,
2450}
2451
2452#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2458#[serde(rename_all = "snake_case")]
2459pub enum TaskStatus {
2460 Working,
2462 InputRequired,
2464 Completed,
2466 Failed,
2468 Cancelled,
2470}
2471
2472impl std::fmt::Display for TaskStatus {
2473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2474 match self {
2475 TaskStatus::Working => write!(f, "working"),
2476 TaskStatus::InputRequired => write!(f, "input_required"),
2477 TaskStatus::Completed => write!(f, "completed"),
2478 TaskStatus::Failed => write!(f, "failed"),
2479 TaskStatus::Cancelled => write!(f, "cancelled"),
2480 }
2481 }
2482}
2483
2484impl TaskStatus {
2485 pub fn is_terminal(&self) -> bool {
2487 matches!(
2488 self,
2489 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
2490 )
2491 }
2492}
2493
2494#[derive(Debug, Clone, Serialize, Deserialize)]
2496#[serde(rename_all = "camelCase")]
2497pub struct TaskInfo {
2498 pub task_id: String,
2500 pub status: TaskStatus,
2502 pub created_at: String,
2504 #[serde(skip_serializing_if = "Option::is_none")]
2506 pub ttl: Option<u64>,
2507 #[serde(skip_serializing_if = "Option::is_none")]
2509 pub poll_interval: Option<u64>,
2510 #[serde(skip_serializing_if = "Option::is_none")]
2512 pub progress: Option<f64>,
2513 #[serde(skip_serializing_if = "Option::is_none")]
2515 pub message: Option<String>,
2516}
2517
2518#[derive(Debug, Clone, Deserialize)]
2520#[serde(rename_all = "camelCase")]
2521pub struct EnqueueTaskParams {
2522 pub tool_name: String,
2524 #[serde(default)]
2526 pub arguments: Value,
2527 #[serde(default)]
2529 pub ttl: Option<u64>,
2530}
2531
2532#[derive(Debug, Clone, Serialize)]
2534#[serde(rename_all = "camelCase")]
2535pub struct EnqueueTaskResult {
2536 pub task_id: String,
2538 pub status: TaskStatus,
2540 #[serde(skip_serializing_if = "Option::is_none")]
2542 pub poll_interval: Option<u64>,
2543}
2544
2545#[derive(Debug, Clone, Default, Deserialize)]
2547#[serde(rename_all = "camelCase")]
2548pub struct ListTasksParams {
2549 #[serde(default)]
2551 pub status: Option<TaskStatus>,
2552 #[serde(default)]
2554 pub cursor: Option<String>,
2555}
2556
2557#[derive(Debug, Clone, Serialize)]
2559#[serde(rename_all = "camelCase")]
2560pub struct ListTasksResult {
2561 pub tasks: Vec<TaskInfo>,
2563 #[serde(skip_serializing_if = "Option::is_none")]
2565 pub next_cursor: Option<String>,
2566}
2567
2568#[derive(Debug, Clone, Deserialize)]
2570#[serde(rename_all = "camelCase")]
2571pub struct GetTaskInfoParams {
2572 pub task_id: String,
2574}
2575
2576pub type GetTaskInfoResult = TaskInfo;
2578
2579#[derive(Debug, Clone, Deserialize)]
2581#[serde(rename_all = "camelCase")]
2582pub struct GetTaskResultParams {
2583 pub task_id: String,
2585}
2586
2587#[derive(Debug, Clone, Serialize)]
2589#[serde(rename_all = "camelCase")]
2590pub struct GetTaskResultResult {
2591 pub task_id: String,
2593 pub status: TaskStatus,
2595 #[serde(skip_serializing_if = "Option::is_none")]
2597 pub result: Option<CallToolResult>,
2598 #[serde(skip_serializing_if = "Option::is_none")]
2600 pub error: Option<String>,
2601}
2602
2603#[derive(Debug, Clone, Deserialize)]
2605#[serde(rename_all = "camelCase")]
2606pub struct CancelTaskParams {
2607 pub task_id: String,
2609 #[serde(default)]
2611 pub reason: Option<String>,
2612}
2613
2614#[derive(Debug, Clone, Serialize)]
2616#[serde(rename_all = "camelCase")]
2617pub struct CancelTaskResult {
2618 pub cancelled: bool,
2620 pub status: TaskStatus,
2622}
2623
2624#[derive(Debug, Clone, Serialize, Deserialize)]
2626#[serde(rename_all = "camelCase")]
2627pub struct TaskStatusChangedParams {
2628 pub task_id: String,
2630 pub status: TaskStatus,
2632 #[serde(skip_serializing_if = "Option::is_none")]
2634 pub message: Option<String>,
2635}
2636
2637#[derive(Debug, Clone, Serialize, Deserialize)]
2643#[serde(rename_all = "camelCase")]
2644pub struct ElicitFormParams {
2645 pub mode: ElicitMode,
2647 pub message: String,
2649 pub requested_schema: ElicitFormSchema,
2651 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2653 pub meta: Option<RequestMeta>,
2654}
2655
2656#[derive(Debug, Clone, Serialize, Deserialize)]
2658#[serde(rename_all = "camelCase")]
2659pub struct ElicitUrlParams {
2660 pub mode: ElicitMode,
2662 pub elicitation_id: String,
2664 pub message: String,
2666 pub url: String,
2668 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2670 pub meta: Option<RequestMeta>,
2671}
2672
2673#[derive(Debug, Clone, Serialize, Deserialize)]
2675#[serde(untagged)]
2676pub enum ElicitRequestParams {
2677 Form(ElicitFormParams),
2678 Url(ElicitUrlParams),
2679}
2680
2681#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2683#[serde(rename_all = "lowercase")]
2684pub enum ElicitMode {
2685 Form,
2687 Url,
2689}
2690
2691#[derive(Debug, Clone, Serialize, Deserialize)]
2695pub struct ElicitFormSchema {
2696 #[serde(rename = "type")]
2698 pub schema_type: String,
2699 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
2701 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2703 pub required: Vec<String>,
2704}
2705
2706impl ElicitFormSchema {
2707 pub fn new() -> Self {
2709 Self {
2710 schema_type: "object".to_string(),
2711 properties: std::collections::HashMap::new(),
2712 required: Vec::new(),
2713 }
2714 }
2715
2716 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2718 self.properties.insert(
2719 name.to_string(),
2720 PrimitiveSchemaDefinition::String(StringSchema {
2721 schema_type: "string".to_string(),
2722 description: description.map(|s| s.to_string()),
2723 format: None,
2724 min_length: None,
2725 max_length: None,
2726 default: None,
2727 }),
2728 );
2729 if required {
2730 self.required.push(name.to_string());
2731 }
2732 self
2733 }
2734
2735 pub fn string_field_with_default(
2737 mut self,
2738 name: &str,
2739 description: Option<&str>,
2740 required: bool,
2741 default: &str,
2742 ) -> Self {
2743 self.properties.insert(
2744 name.to_string(),
2745 PrimitiveSchemaDefinition::String(StringSchema {
2746 schema_type: "string".to_string(),
2747 description: description.map(|s| s.to_string()),
2748 format: None,
2749 min_length: None,
2750 max_length: None,
2751 default: Some(default.to_string()),
2752 }),
2753 );
2754 if required {
2755 self.required.push(name.to_string());
2756 }
2757 self
2758 }
2759
2760 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2762 self.properties.insert(
2763 name.to_string(),
2764 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2765 schema_type: "integer".to_string(),
2766 description: description.map(|s| s.to_string()),
2767 minimum: None,
2768 maximum: None,
2769 default: None,
2770 }),
2771 );
2772 if required {
2773 self.required.push(name.to_string());
2774 }
2775 self
2776 }
2777
2778 pub fn integer_field_with_default(
2780 mut self,
2781 name: &str,
2782 description: Option<&str>,
2783 required: bool,
2784 default: i64,
2785 ) -> Self {
2786 self.properties.insert(
2787 name.to_string(),
2788 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2789 schema_type: "integer".to_string(),
2790 description: description.map(|s| s.to_string()),
2791 minimum: None,
2792 maximum: None,
2793 default: Some(default),
2794 }),
2795 );
2796 if required {
2797 self.required.push(name.to_string());
2798 }
2799 self
2800 }
2801
2802 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2804 self.properties.insert(
2805 name.to_string(),
2806 PrimitiveSchemaDefinition::Number(NumberSchema {
2807 schema_type: "number".to_string(),
2808 description: description.map(|s| s.to_string()),
2809 minimum: None,
2810 maximum: None,
2811 default: None,
2812 }),
2813 );
2814 if required {
2815 self.required.push(name.to_string());
2816 }
2817 self
2818 }
2819
2820 pub fn number_field_with_default(
2822 mut self,
2823 name: &str,
2824 description: Option<&str>,
2825 required: bool,
2826 default: f64,
2827 ) -> Self {
2828 self.properties.insert(
2829 name.to_string(),
2830 PrimitiveSchemaDefinition::Number(NumberSchema {
2831 schema_type: "number".to_string(),
2832 description: description.map(|s| s.to_string()),
2833 minimum: None,
2834 maximum: None,
2835 default: Some(default),
2836 }),
2837 );
2838 if required {
2839 self.required.push(name.to_string());
2840 }
2841 self
2842 }
2843
2844 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2846 self.properties.insert(
2847 name.to_string(),
2848 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2849 schema_type: "boolean".to_string(),
2850 description: description.map(|s| s.to_string()),
2851 default: None,
2852 }),
2853 );
2854 if required {
2855 self.required.push(name.to_string());
2856 }
2857 self
2858 }
2859
2860 pub fn boolean_field_with_default(
2862 mut self,
2863 name: &str,
2864 description: Option<&str>,
2865 required: bool,
2866 default: bool,
2867 ) -> Self {
2868 self.properties.insert(
2869 name.to_string(),
2870 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2871 schema_type: "boolean".to_string(),
2872 description: description.map(|s| s.to_string()),
2873 default: Some(default),
2874 }),
2875 );
2876 if required {
2877 self.required.push(name.to_string());
2878 }
2879 self
2880 }
2881
2882 pub fn enum_field(
2884 mut self,
2885 name: &str,
2886 description: Option<&str>,
2887 options: Vec<String>,
2888 required: bool,
2889 ) -> Self {
2890 self.properties.insert(
2891 name.to_string(),
2892 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2893 schema_type: "string".to_string(),
2894 description: description.map(|s| s.to_string()),
2895 enum_values: options,
2896 default: None,
2897 }),
2898 );
2899 if required {
2900 self.required.push(name.to_string());
2901 }
2902 self
2903 }
2904
2905 pub fn enum_field_with_default(
2907 mut self,
2908 name: &str,
2909 description: Option<&str>,
2910 required: bool,
2911 options: &[&str],
2912 default: &str,
2913 ) -> Self {
2914 self.properties.insert(
2915 name.to_string(),
2916 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2917 schema_type: "string".to_string(),
2918 description: description.map(|s| s.to_string()),
2919 enum_values: options.iter().map(|s| s.to_string()).collect(),
2920 default: Some(default.to_string()),
2921 }),
2922 );
2923 if required {
2924 self.required.push(name.to_string());
2925 }
2926 self
2927 }
2928
2929 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
2933 self.properties
2934 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
2935 if required {
2936 self.required.push(name.to_string());
2937 }
2938 self
2939 }
2940}
2941
2942impl Default for ElicitFormSchema {
2943 fn default() -> Self {
2944 Self::new()
2945 }
2946}
2947
2948#[derive(Debug, Clone, Serialize, Deserialize)]
2950#[serde(untagged)]
2951pub enum PrimitiveSchemaDefinition {
2952 String(StringSchema),
2954 Integer(IntegerSchema),
2956 Number(NumberSchema),
2958 Boolean(BooleanSchema),
2960 SingleSelectEnum(SingleSelectEnumSchema),
2962 MultiSelectEnum(MultiSelectEnumSchema),
2964 Raw(serde_json::Value),
2966}
2967
2968#[derive(Debug, Clone, Serialize, Deserialize)]
2970#[serde(rename_all = "camelCase")]
2971pub struct StringSchema {
2972 #[serde(rename = "type")]
2973 pub schema_type: String,
2974 #[serde(skip_serializing_if = "Option::is_none")]
2975 pub description: Option<String>,
2976 #[serde(skip_serializing_if = "Option::is_none")]
2977 pub format: Option<String>,
2978 #[serde(skip_serializing_if = "Option::is_none")]
2979 pub min_length: Option<u64>,
2980 #[serde(skip_serializing_if = "Option::is_none")]
2981 pub max_length: Option<u64>,
2982 #[serde(skip_serializing_if = "Option::is_none")]
2984 pub default: Option<String>,
2985}
2986
2987#[derive(Debug, Clone, Serialize, Deserialize)]
2989#[serde(rename_all = "camelCase")]
2990pub struct IntegerSchema {
2991 #[serde(rename = "type")]
2992 pub schema_type: String,
2993 #[serde(skip_serializing_if = "Option::is_none")]
2994 pub description: Option<String>,
2995 #[serde(skip_serializing_if = "Option::is_none")]
2996 pub minimum: Option<i64>,
2997 #[serde(skip_serializing_if = "Option::is_none")]
2998 pub maximum: Option<i64>,
2999 #[serde(skip_serializing_if = "Option::is_none")]
3001 pub default: Option<i64>,
3002}
3003
3004#[derive(Debug, Clone, Serialize, Deserialize)]
3006#[serde(rename_all = "camelCase")]
3007pub struct NumberSchema {
3008 #[serde(rename = "type")]
3009 pub schema_type: String,
3010 #[serde(skip_serializing_if = "Option::is_none")]
3011 pub description: Option<String>,
3012 #[serde(skip_serializing_if = "Option::is_none")]
3013 pub minimum: Option<f64>,
3014 #[serde(skip_serializing_if = "Option::is_none")]
3015 pub maximum: Option<f64>,
3016 #[serde(skip_serializing_if = "Option::is_none")]
3018 pub default: Option<f64>,
3019}
3020
3021#[derive(Debug, Clone, Serialize, Deserialize)]
3023#[serde(rename_all = "camelCase")]
3024pub struct BooleanSchema {
3025 #[serde(rename = "type")]
3026 pub schema_type: String,
3027 #[serde(skip_serializing_if = "Option::is_none")]
3028 pub description: Option<String>,
3029 #[serde(skip_serializing_if = "Option::is_none")]
3031 pub default: Option<bool>,
3032}
3033
3034#[derive(Debug, Clone, Serialize, Deserialize)]
3036#[serde(rename_all = "camelCase")]
3037pub struct SingleSelectEnumSchema {
3038 #[serde(rename = "type")]
3039 pub schema_type: String,
3040 #[serde(skip_serializing_if = "Option::is_none")]
3041 pub description: Option<String>,
3042 #[serde(rename = "enum")]
3043 pub enum_values: Vec<String>,
3044 #[serde(skip_serializing_if = "Option::is_none")]
3046 pub default: Option<String>,
3047}
3048
3049#[derive(Debug, Clone, Serialize, Deserialize)]
3051#[serde(rename_all = "camelCase")]
3052pub struct MultiSelectEnumSchema {
3053 #[serde(rename = "type")]
3054 pub schema_type: String,
3055 #[serde(skip_serializing_if = "Option::is_none")]
3056 pub description: Option<String>,
3057 pub items: MultiSelectEnumItems,
3058 #[serde(skip_serializing_if = "Option::is_none")]
3059 pub unique_items: Option<bool>,
3060}
3061
3062#[derive(Debug, Clone, Serialize, Deserialize)]
3064pub struct MultiSelectEnumItems {
3065 #[serde(rename = "type")]
3066 pub schema_type: String,
3067 #[serde(rename = "enum")]
3068 pub enum_values: Vec<String>,
3069}
3070
3071#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3073#[serde(rename_all = "lowercase")]
3074pub enum ElicitAction {
3075 Accept,
3077 Decline,
3079 Cancel,
3081}
3082
3083#[derive(Debug, Clone, Serialize, Deserialize)]
3085pub struct ElicitResult {
3086 pub action: ElicitAction,
3088 #[serde(default, skip_serializing_if = "Option::is_none")]
3090 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
3091}
3092
3093impl ElicitResult {
3094 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
3096 Self {
3097 action: ElicitAction::Accept,
3098 content: Some(content),
3099 }
3100 }
3101
3102 pub fn decline() -> Self {
3104 Self {
3105 action: ElicitAction::Decline,
3106 content: None,
3107 }
3108 }
3109
3110 pub fn cancel() -> Self {
3112 Self {
3113 action: ElicitAction::Cancel,
3114 content: None,
3115 }
3116 }
3117}
3118
3119#[derive(Debug, Clone, Serialize, Deserialize)]
3121#[serde(untagged)]
3122pub enum ElicitFieldValue {
3123 String(String),
3124 Number(f64),
3125 Integer(i64),
3126 Boolean(bool),
3127 StringArray(Vec<String>),
3128}
3129
3130#[derive(Debug, Clone, Serialize, Deserialize)]
3132#[serde(rename_all = "camelCase")]
3133pub struct ElicitationCompleteParams {
3134 pub elicitation_id: String,
3136}
3137
3138#[derive(Debug, Clone, Default, Serialize)]
3143pub struct EmptyResult {}
3144
3145impl McpRequest {
3150 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
3152 let params = req
3153 .params
3154 .clone()
3155 .unwrap_or(Value::Object(Default::default()));
3156
3157 match req.method.as_str() {
3158 "initialize" => {
3159 let p: InitializeParams = serde_json::from_value(params)?;
3160 Ok(McpRequest::Initialize(p))
3161 }
3162 "tools/list" => {
3163 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
3164 Ok(McpRequest::ListTools(p))
3165 }
3166 "tools/call" => {
3167 let p: CallToolParams = serde_json::from_value(params)?;
3168 Ok(McpRequest::CallTool(p))
3169 }
3170 "resources/list" => {
3171 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
3172 Ok(McpRequest::ListResources(p))
3173 }
3174 "resources/templates/list" => {
3175 let p: ListResourceTemplatesParams =
3176 serde_json::from_value(params).unwrap_or_default();
3177 Ok(McpRequest::ListResourceTemplates(p))
3178 }
3179 "resources/read" => {
3180 let p: ReadResourceParams = serde_json::from_value(params)?;
3181 Ok(McpRequest::ReadResource(p))
3182 }
3183 "resources/subscribe" => {
3184 let p: SubscribeResourceParams = serde_json::from_value(params)?;
3185 Ok(McpRequest::SubscribeResource(p))
3186 }
3187 "resources/unsubscribe" => {
3188 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
3189 Ok(McpRequest::UnsubscribeResource(p))
3190 }
3191 "prompts/list" => {
3192 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
3193 Ok(McpRequest::ListPrompts(p))
3194 }
3195 "prompts/get" => {
3196 let p: GetPromptParams = serde_json::from_value(params)?;
3197 Ok(McpRequest::GetPrompt(p))
3198 }
3199 "tasks/enqueue" => {
3200 let p: EnqueueTaskParams = serde_json::from_value(params)?;
3201 Ok(McpRequest::EnqueueTask(p))
3202 }
3203 "tasks/list" => {
3204 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
3205 Ok(McpRequest::ListTasks(p))
3206 }
3207 "tasks/get" => {
3208 let p: GetTaskInfoParams = serde_json::from_value(params)?;
3209 Ok(McpRequest::GetTaskInfo(p))
3210 }
3211 "tasks/result" => {
3212 let p: GetTaskResultParams = serde_json::from_value(params)?;
3213 Ok(McpRequest::GetTaskResult(p))
3214 }
3215 "tasks/cancel" => {
3216 let p: CancelTaskParams = serde_json::from_value(params)?;
3217 Ok(McpRequest::CancelTask(p))
3218 }
3219 "ping" => Ok(McpRequest::Ping),
3220 "logging/setLevel" => {
3221 let p: SetLogLevelParams = serde_json::from_value(params)?;
3222 Ok(McpRequest::SetLoggingLevel(p))
3223 }
3224 "completion/complete" => {
3225 let p: CompleteParams = serde_json::from_value(params)?;
3226 Ok(McpRequest::Complete(p))
3227 }
3228 method => Ok(McpRequest::Unknown {
3229 method: method.to_string(),
3230 params: req.params.clone(),
3231 }),
3232 }
3233 }
3234}
3235
3236impl McpNotification {
3237 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
3239 let params = notif
3240 .params
3241 .clone()
3242 .unwrap_or(Value::Object(Default::default()));
3243
3244 match notif.method.as_str() {
3245 notifications::INITIALIZED => Ok(McpNotification::Initialized),
3246 notifications::CANCELLED => {
3247 let p: CancelledParams = serde_json::from_value(params)?;
3248 Ok(McpNotification::Cancelled(p))
3249 }
3250 notifications::PROGRESS => {
3251 let p: ProgressParams = serde_json::from_value(params)?;
3252 Ok(McpNotification::Progress(p))
3253 }
3254 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3255 method => Ok(McpNotification::Unknown {
3256 method: method.to_string(),
3257 params: notif.params.clone(),
3258 }),
3259 }
3260 }
3261}
3262
3263#[cfg(test)]
3264mod tests {
3265 use super::*;
3266
3267 #[test]
3268 fn test_content_text_constructor() {
3269 let content = Content::text("hello world");
3270 assert_eq!(content.as_text(), Some("hello world"));
3271
3272 match &content {
3274 Content::Text { text, annotations } => {
3275 assert_eq!(text, "hello world");
3276 assert!(annotations.is_none());
3277 }
3278 _ => panic!("expected Content::Text"),
3279 }
3280
3281 let content = Content::text(String::from("owned"));
3283 assert_eq!(content.as_text(), Some("owned"));
3284 }
3285
3286 #[test]
3287 fn test_elicit_form_schema_builder() {
3288 let schema = ElicitFormSchema::new()
3289 .string_field("name", Some("Your name"), true)
3290 .number_field("age", Some("Your age"), false)
3291 .boolean_field("agree", Some("Do you agree?"), true)
3292 .enum_field(
3293 "color",
3294 Some("Favorite color"),
3295 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
3296 false,
3297 );
3298
3299 assert_eq!(schema.schema_type, "object");
3300 assert_eq!(schema.properties.len(), 4);
3301 assert_eq!(schema.required.len(), 2);
3302 assert!(schema.required.contains(&"name".to_string()));
3303 assert!(schema.required.contains(&"agree".to_string()));
3304 }
3305
3306 #[test]
3307 fn test_elicit_form_schema_serialization() {
3308 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
3309
3310 let json = serde_json::to_value(&schema).unwrap();
3311 assert_eq!(json["type"], "object");
3312 assert!(json["properties"]["username"]["type"] == "string");
3313 assert!(
3314 json["required"]
3315 .as_array()
3316 .unwrap()
3317 .contains(&serde_json::json!("username"))
3318 );
3319 }
3320
3321 #[test]
3322 fn test_elicit_result_accept() {
3323 let mut content = std::collections::HashMap::new();
3324 content.insert(
3325 "name".to_string(),
3326 ElicitFieldValue::String("Alice".to_string()),
3327 );
3328 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
3329
3330 let result = ElicitResult::accept(content);
3331 assert_eq!(result.action, ElicitAction::Accept);
3332 assert!(result.content.is_some());
3333 }
3334
3335 #[test]
3336 fn test_elicit_result_decline() {
3337 let result = ElicitResult::decline();
3338 assert_eq!(result.action, ElicitAction::Decline);
3339 assert!(result.content.is_none());
3340 }
3341
3342 #[test]
3343 fn test_elicit_result_cancel() {
3344 let result = ElicitResult::cancel();
3345 assert_eq!(result.action, ElicitAction::Cancel);
3346 assert!(result.content.is_none());
3347 }
3348
3349 #[test]
3350 fn test_elicit_mode_serialization() {
3351 assert_eq!(
3352 serde_json::to_string(&ElicitMode::Form).unwrap(),
3353 "\"form\""
3354 );
3355 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
3356 }
3357
3358 #[test]
3359 fn test_elicit_action_serialization() {
3360 assert_eq!(
3361 serde_json::to_string(&ElicitAction::Accept).unwrap(),
3362 "\"accept\""
3363 );
3364 assert_eq!(
3365 serde_json::to_string(&ElicitAction::Decline).unwrap(),
3366 "\"decline\""
3367 );
3368 assert_eq!(
3369 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
3370 "\"cancel\""
3371 );
3372 }
3373
3374 #[test]
3375 fn test_elicitation_capability() {
3376 let cap = ElicitationCapability {
3377 form: Some(ElicitationFormCapability {}),
3378 url: None,
3379 };
3380
3381 let json = serde_json::to_value(&cap).unwrap();
3382 assert!(json["form"].is_object());
3383 assert!(json.get("url").is_none());
3384 }
3385
3386 #[test]
3387 fn test_client_capabilities_with_elicitation() {
3388 let caps = ClientCapabilities {
3389 roots: None,
3390 sampling: None,
3391 elicitation: Some(ElicitationCapability {
3392 form: Some(ElicitationFormCapability {}),
3393 url: Some(ElicitationUrlCapability {}),
3394 }),
3395 };
3396
3397 let json = serde_json::to_value(&caps).unwrap();
3398 assert!(json["elicitation"]["form"].is_object());
3399 assert!(json["elicitation"]["url"].is_object());
3400 }
3401
3402 #[test]
3403 fn test_elicit_url_params() {
3404 let params = ElicitUrlParams {
3405 mode: ElicitMode::Url,
3406 elicitation_id: "abc123".to_string(),
3407 message: "Please authorize".to_string(),
3408 url: "https://example.com/auth".to_string(),
3409 meta: None,
3410 };
3411
3412 let json = serde_json::to_value(¶ms).unwrap();
3413 assert_eq!(json["mode"], "url");
3414 assert_eq!(json["elicitationId"], "abc123");
3415 assert_eq!(json["message"], "Please authorize");
3416 assert_eq!(json["url"], "https://example.com/auth");
3417 }
3418
3419 #[test]
3420 fn test_elicitation_complete_params() {
3421 let params = ElicitationCompleteParams {
3422 elicitation_id: "xyz789".to_string(),
3423 };
3424
3425 let json = serde_json::to_value(¶ms).unwrap();
3426 assert_eq!(json["elicitationId"], "xyz789");
3427 }
3428
3429 #[test]
3430 fn test_root_new() {
3431 let root = Root::new("file:///home/user/project");
3432 assert_eq!(root.uri, "file:///home/user/project");
3433 assert!(root.name.is_none());
3434 }
3435
3436 #[test]
3437 fn test_root_with_name() {
3438 let root = Root::with_name("file:///home/user/project", "My Project");
3439 assert_eq!(root.uri, "file:///home/user/project");
3440 assert_eq!(root.name.as_deref(), Some("My Project"));
3441 }
3442
3443 #[test]
3444 fn test_root_serialization() {
3445 let root = Root::with_name("file:///workspace", "Workspace");
3446 let json = serde_json::to_value(&root).unwrap();
3447 assert_eq!(json["uri"], "file:///workspace");
3448 assert_eq!(json["name"], "Workspace");
3449 }
3450
3451 #[test]
3452 fn test_root_serialization_without_name() {
3453 let root = Root::new("file:///workspace");
3454 let json = serde_json::to_value(&root).unwrap();
3455 assert_eq!(json["uri"], "file:///workspace");
3456 assert!(json.get("name").is_none());
3457 }
3458
3459 #[test]
3460 fn test_root_deserialization() {
3461 let json = serde_json::json!({
3462 "uri": "file:///home/user",
3463 "name": "Home"
3464 });
3465 let root: Root = serde_json::from_value(json).unwrap();
3466 assert_eq!(root.uri, "file:///home/user");
3467 assert_eq!(root.name.as_deref(), Some("Home"));
3468 }
3469
3470 #[test]
3471 fn test_list_roots_result() {
3472 let result = ListRootsResult {
3473 roots: vec![
3474 Root::new("file:///project1"),
3475 Root::with_name("file:///project2", "Project 2"),
3476 ],
3477 };
3478
3479 let json = serde_json::to_value(&result).unwrap();
3480 let roots = json["roots"].as_array().unwrap();
3481 assert_eq!(roots.len(), 2);
3482 assert_eq!(roots[0]["uri"], "file:///project1");
3483 assert_eq!(roots[1]["name"], "Project 2");
3484 }
3485
3486 #[test]
3487 fn test_roots_capability_serialization() {
3488 let cap = RootsCapability { list_changed: true };
3489 let json = serde_json::to_value(&cap).unwrap();
3490 assert_eq!(json["listChanged"], true);
3491 }
3492
3493 #[test]
3494 fn test_client_capabilities_with_roots() {
3495 let caps = ClientCapabilities {
3496 roots: Some(RootsCapability { list_changed: true }),
3497 sampling: None,
3498 elicitation: None,
3499 };
3500
3501 let json = serde_json::to_value(&caps).unwrap();
3502 assert_eq!(json["roots"]["listChanged"], true);
3503 }
3504
3505 #[test]
3506 fn test_roots_list_changed_notification_parsing() {
3507 let notif = JsonRpcNotification {
3508 jsonrpc: "2.0".to_string(),
3509 method: notifications::ROOTS_LIST_CHANGED.to_string(),
3510 params: None,
3511 };
3512
3513 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
3514 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
3515 }
3516
3517 #[test]
3522 fn test_prompt_reference() {
3523 let ref_ = PromptReference::new("my-prompt");
3524 assert_eq!(ref_.ref_type, "ref/prompt");
3525 assert_eq!(ref_.name, "my-prompt");
3526
3527 let json = serde_json::to_value(&ref_).unwrap();
3528 assert_eq!(json["type"], "ref/prompt");
3529 assert_eq!(json["name"], "my-prompt");
3530 }
3531
3532 #[test]
3533 fn test_resource_reference() {
3534 let ref_ = ResourceReference::new("file:///path/to/file");
3535 assert_eq!(ref_.ref_type, "ref/resource");
3536 assert_eq!(ref_.uri, "file:///path/to/file");
3537
3538 let json = serde_json::to_value(&ref_).unwrap();
3539 assert_eq!(json["type"], "ref/resource");
3540 assert_eq!(json["uri"], "file:///path/to/file");
3541 }
3542
3543 #[test]
3544 fn test_completion_reference_prompt() {
3545 let ref_ = CompletionReference::prompt("test-prompt");
3546 let json = serde_json::to_value(&ref_).unwrap();
3547 assert_eq!(json["type"], "ref/prompt");
3548 assert_eq!(json["name"], "test-prompt");
3549 }
3550
3551 #[test]
3552 fn test_completion_reference_resource() {
3553 let ref_ = CompletionReference::resource("file:///test");
3554 let json = serde_json::to_value(&ref_).unwrap();
3555 assert_eq!(json["type"], "ref/resource");
3556 assert_eq!(json["uri"], "file:///test");
3557 }
3558
3559 #[test]
3560 fn test_completion_argument() {
3561 let arg = CompletionArgument::new("query", "SELECT * FROM");
3562 assert_eq!(arg.name, "query");
3563 assert_eq!(arg.value, "SELECT * FROM");
3564 }
3565
3566 #[test]
3567 fn test_complete_params_serialization() {
3568 let params = CompleteParams {
3569 reference: CompletionReference::prompt("sql-prompt"),
3570 argument: CompletionArgument::new("query", "SEL"),
3571 };
3572
3573 let json = serde_json::to_value(¶ms).unwrap();
3574 assert_eq!(json["ref"]["type"], "ref/prompt");
3575 assert_eq!(json["ref"]["name"], "sql-prompt");
3576 assert_eq!(json["argument"]["name"], "query");
3577 assert_eq!(json["argument"]["value"], "SEL");
3578 }
3579
3580 #[test]
3581 fn test_completion_new() {
3582 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
3583 assert_eq!(completion.values.len(), 2);
3584 assert!(completion.total.is_none());
3585 assert!(completion.has_more.is_none());
3586 }
3587
3588 #[test]
3589 fn test_completion_with_pagination() {
3590 let completion =
3591 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
3592 assert_eq!(completion.values.len(), 2);
3593 assert_eq!(completion.total, Some(100));
3594 assert_eq!(completion.has_more, Some(true));
3595 }
3596
3597 #[test]
3598 fn test_complete_result() {
3599 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
3600 let json = serde_json::to_value(&result).unwrap();
3601 assert!(json["completion"]["values"].is_array());
3602 assert_eq!(json["completion"]["values"][0], "option1");
3603 }
3604
3605 #[test]
3610 fn test_model_hint() {
3611 let hint = ModelHint::new("claude-3-opus");
3612 assert_eq!(hint.name, "claude-3-opus");
3613 }
3614
3615 #[test]
3616 fn test_model_preferences_builder() {
3617 let prefs = ModelPreferences::new()
3618 .speed(0.8)
3619 .intelligence(0.9)
3620 .cost(0.5)
3621 .hint("gpt-4")
3622 .hint("claude-3");
3623
3624 assert_eq!(prefs.speed_priority, Some(0.8));
3625 assert_eq!(prefs.intelligence_priority, Some(0.9));
3626 assert_eq!(prefs.cost_priority, Some(0.5));
3627 assert_eq!(prefs.hints.len(), 2);
3628 }
3629
3630 #[test]
3631 fn test_model_preferences_clamping() {
3632 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
3633
3634 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
3637
3638 #[test]
3639 fn test_include_context_serialization() {
3640 assert_eq!(
3641 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
3642 "\"allServers\""
3643 );
3644 assert_eq!(
3645 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
3646 "\"thisServer\""
3647 );
3648 assert_eq!(
3649 serde_json::to_string(&IncludeContext::None).unwrap(),
3650 "\"none\""
3651 );
3652 }
3653
3654 #[test]
3655 fn test_sampling_message_user() {
3656 let msg = SamplingMessage::user("Hello, how are you?");
3657 assert_eq!(msg.role, ContentRole::User);
3658 assert!(
3659 matches!(msg.content, SamplingContent::Text { text } if text == "Hello, how are you?")
3660 );
3661 }
3662
3663 #[test]
3664 fn test_sampling_message_assistant() {
3665 let msg = SamplingMessage::assistant("I'm doing well!");
3666 assert_eq!(msg.role, ContentRole::Assistant);
3667 }
3668
3669 #[test]
3670 fn test_sampling_content_text_serialization() {
3671 let content = SamplingContent::Text {
3672 text: "Hello".to_string(),
3673 };
3674 let json = serde_json::to_value(&content).unwrap();
3675 assert_eq!(json["type"], "text");
3676 assert_eq!(json["text"], "Hello");
3677 }
3678
3679 #[test]
3680 fn test_sampling_content_image_serialization() {
3681 let content = SamplingContent::Image {
3682 data: "base64data".to_string(),
3683 mime_type: "image/png".to_string(),
3684 };
3685 let json = serde_json::to_value(&content).unwrap();
3686 assert_eq!(json["type"], "image");
3687 assert_eq!(json["data"], "base64data");
3688 assert_eq!(json["mimeType"], "image/png");
3689 }
3690
3691 #[test]
3692 fn test_create_message_params() {
3693 let params = CreateMessageParams::new(
3694 vec![
3695 SamplingMessage::user("What is 2+2?"),
3696 SamplingMessage::assistant("4"),
3697 SamplingMessage::user("And 3+3?"),
3698 ],
3699 100,
3700 )
3701 .system_prompt("You are a math tutor")
3702 .temperature(0.7)
3703 .stop_sequence("END")
3704 .include_context(IncludeContext::ThisServer);
3705
3706 assert_eq!(params.messages.len(), 3);
3707 assert_eq!(params.max_tokens, 100);
3708 assert_eq!(
3709 params.system_prompt.as_deref(),
3710 Some("You are a math tutor")
3711 );
3712 assert_eq!(params.temperature, Some(0.7));
3713 assert_eq!(params.stop_sequences.len(), 1);
3714 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
3715 }
3716
3717 #[test]
3718 fn test_create_message_params_serialization() {
3719 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
3720
3721 let json = serde_json::to_value(¶ms).unwrap();
3722 assert!(json["messages"].is_array());
3723 assert_eq!(json["maxTokens"], 50);
3724 }
3725
3726 #[test]
3727 fn test_create_message_result_deserialization() {
3728 let json = serde_json::json!({
3729 "content": {
3730 "type": "text",
3731 "text": "The answer is 42"
3732 },
3733 "model": "claude-3-opus",
3734 "role": "assistant",
3735 "stopReason": "end_turn"
3736 });
3737
3738 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
3739 assert_eq!(result.model, "claude-3-opus");
3740 assert_eq!(result.role, ContentRole::Assistant);
3741 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
3742 }
3743
3744 #[test]
3745 fn test_completions_capability_serialization() {
3746 let cap = CompletionsCapability {};
3747 let json = serde_json::to_value(&cap).unwrap();
3748 assert!(json.is_object());
3749 }
3750
3751 #[test]
3752 fn test_server_capabilities_with_completions() {
3753 let caps = ServerCapabilities {
3754 completions: Some(CompletionsCapability {}),
3755 ..Default::default()
3756 };
3757
3758 let json = serde_json::to_value(&caps).unwrap();
3759 assert!(json["completions"].is_object());
3760 }
3761
3762 #[test]
3763 fn test_content_resource_link_serialization() {
3764 let content = Content::ResourceLink {
3765 uri: "file:///test.txt".to_string(),
3766 name: Some("test.txt".to_string()),
3767 description: Some("A test file".to_string()),
3768 mime_type: Some("text/plain".to_string()),
3769 annotations: None,
3770 };
3771 let json = serde_json::to_value(&content).unwrap();
3772 assert_eq!(json["type"], "resource_link");
3773 assert_eq!(json["uri"], "file:///test.txt");
3774 assert_eq!(json["name"], "test.txt");
3775 assert_eq!(json["description"], "A test file");
3776 assert_eq!(json["mimeType"], "text/plain");
3777 }
3778
3779 #[test]
3780 fn test_call_tool_result_resource_link() {
3781 let result = CallToolResult::resource_link("file:///output.json");
3782 assert_eq!(result.content.len(), 1);
3783 assert!(!result.is_error);
3784 match &result.content[0] {
3785 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
3786 _ => panic!("Expected ResourceLink content"),
3787 }
3788 }
3789
3790 #[test]
3791 fn test_call_tool_result_image() {
3792 let result = CallToolResult::image("base64data", "image/png");
3793 assert_eq!(result.content.len(), 1);
3794 match &result.content[0] {
3795 Content::Image {
3796 data, mime_type, ..
3797 } => {
3798 assert_eq!(data, "base64data");
3799 assert_eq!(mime_type, "image/png");
3800 }
3801 _ => panic!("Expected Image content"),
3802 }
3803 }
3804
3805 #[test]
3806 fn test_call_tool_result_audio() {
3807 let result = CallToolResult::audio("audiodata", "audio/wav");
3808 assert_eq!(result.content.len(), 1);
3809 match &result.content[0] {
3810 Content::Audio {
3811 data, mime_type, ..
3812 } => {
3813 assert_eq!(data, "audiodata");
3814 assert_eq!(mime_type, "audio/wav");
3815 }
3816 _ => panic!("Expected Audio content"),
3817 }
3818 }
3819
3820 #[test]
3821 fn test_sampling_tool_serialization() {
3822 let tool = SamplingTool {
3823 name: "get_weather".to_string(),
3824 description: Some("Get current weather".to_string()),
3825 input_schema: serde_json::json!({
3826 "type": "object",
3827 "properties": {
3828 "location": { "type": "string" }
3829 }
3830 }),
3831 };
3832 let json = serde_json::to_value(&tool).unwrap();
3833 assert_eq!(json["name"], "get_weather");
3834 assert_eq!(json["description"], "Get current weather");
3835 assert!(json["inputSchema"]["properties"]["location"].is_object());
3836 }
3837
3838 #[test]
3839 fn test_tool_choice_modes() {
3840 let auto = ToolChoice::auto();
3841 assert_eq!(auto.mode, "auto");
3842
3843 let required = ToolChoice::required();
3844 assert_eq!(required.mode, "required");
3845
3846 let none = ToolChoice::none();
3847 assert_eq!(none.mode, "none");
3848
3849 let json = serde_json::to_value(&auto).unwrap();
3851 assert_eq!(json["type"], "auto");
3852 }
3853
3854 #[test]
3855 fn test_sampling_content_tool_use() {
3856 let content = SamplingContent::ToolUse {
3857 id: "tool_123".to_string(),
3858 name: "get_weather".to_string(),
3859 input: serde_json::json!({"location": "San Francisco"}),
3860 };
3861 let json = serde_json::to_value(&content).unwrap();
3862 assert_eq!(json["type"], "tool_use");
3863 assert_eq!(json["id"], "tool_123");
3864 assert_eq!(json["name"], "get_weather");
3865 assert_eq!(json["input"]["location"], "San Francisco");
3866 }
3867
3868 #[test]
3869 fn test_sampling_content_tool_result() {
3870 let content = SamplingContent::ToolResult {
3871 tool_use_id: "tool_123".to_string(),
3872 content: vec![SamplingContent::Text {
3873 text: "72F, sunny".to_string(),
3874 }],
3875 is_error: None,
3876 };
3877 let json = serde_json::to_value(&content).unwrap();
3878 assert_eq!(json["type"], "tool_result");
3879 assert_eq!(json["tool_use_id"], "tool_123");
3880 assert_eq!(json["content"][0]["type"], "text");
3881 }
3882
3883 #[test]
3884 fn test_sampling_content_or_array_single() {
3885 let json = serde_json::json!({
3886 "type": "text",
3887 "text": "Hello"
3888 });
3889 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3890 let items = content.items();
3891 assert_eq!(items.len(), 1);
3892 match items[0] {
3893 SamplingContent::Text { text } => assert_eq!(text, "Hello"),
3894 _ => panic!("Expected text content"),
3895 }
3896 }
3897
3898 #[test]
3899 fn test_sampling_content_or_array_multiple() {
3900 let json = serde_json::json!([
3901 { "type": "text", "text": "Hello" },
3902 { "type": "text", "text": "World" }
3903 ]);
3904 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3905 let items = content.items();
3906 assert_eq!(items.len(), 2);
3907 }
3908
3909 #[test]
3910 fn test_create_message_params_with_tools() {
3911 let tool = SamplingTool {
3912 name: "calculator".to_string(),
3913 description: Some("Do math".to_string()),
3914 input_schema: serde_json::json!({"type": "object"}),
3915 };
3916 let params = CreateMessageParams::new(vec![], 100)
3917 .tools(vec![tool])
3918 .tool_choice(ToolChoice::auto());
3919
3920 let json = serde_json::to_value(¶ms).unwrap();
3921 assert!(json["tools"].is_array());
3922 assert_eq!(json["tools"][0]["name"], "calculator");
3923 assert_eq!(json["toolChoice"]["type"], "auto");
3924 }
3925
3926 #[test]
3927 fn test_create_message_result_content_items() {
3928 let result = CreateMessageResult {
3929 content: SamplingContentOrArray::Array(vec![
3930 SamplingContent::Text {
3931 text: "First".to_string(),
3932 },
3933 SamplingContent::Text {
3934 text: "Second".to_string(),
3935 },
3936 ]),
3937 model: "test".to_string(),
3938 role: ContentRole::Assistant,
3939 stop_reason: None,
3940 };
3941 let items = result.content_items();
3942 assert_eq!(items.len(), 2);
3943 }
3944
3945 #[test]
3946 fn test_sampling_content_as_text() {
3947 let text_content = SamplingContent::Text {
3948 text: "Hello".to_string(),
3949 };
3950 assert_eq!(text_content.as_text(), Some("Hello"));
3951
3952 let image_content = SamplingContent::Image {
3953 data: "base64data".to_string(),
3954 mime_type: "image/png".to_string(),
3955 };
3956 assert_eq!(image_content.as_text(), None);
3957
3958 let audio_content = SamplingContent::Audio {
3959 data: "base64audio".to_string(),
3960 mime_type: "audio/wav".to_string(),
3961 };
3962 assert_eq!(audio_content.as_text(), None);
3963 }
3964
3965 #[test]
3966 fn test_create_message_result_first_text_single() {
3967 let result = CreateMessageResult {
3968 content: SamplingContentOrArray::Single(SamplingContent::Text {
3969 text: "Hello, world!".to_string(),
3970 }),
3971 model: "test".to_string(),
3972 role: ContentRole::Assistant,
3973 stop_reason: None,
3974 };
3975 assert_eq!(result.first_text(), Some("Hello, world!"));
3976 }
3977
3978 #[test]
3979 fn test_create_message_result_first_text_array() {
3980 let result = CreateMessageResult {
3981 content: SamplingContentOrArray::Array(vec![
3982 SamplingContent::Text {
3983 text: "First".to_string(),
3984 },
3985 SamplingContent::Text {
3986 text: "Second".to_string(),
3987 },
3988 ]),
3989 model: "test".to_string(),
3990 role: ContentRole::Assistant,
3991 stop_reason: None,
3992 };
3993 assert_eq!(result.first_text(), Some("First"));
3994 }
3995
3996 #[test]
3997 fn test_create_message_result_first_text_skips_non_text() {
3998 let result = CreateMessageResult {
3999 content: SamplingContentOrArray::Array(vec![
4000 SamplingContent::Image {
4001 data: "base64data".to_string(),
4002 mime_type: "image/png".to_string(),
4003 },
4004 SamplingContent::Text {
4005 text: "After image".to_string(),
4006 },
4007 ]),
4008 model: "test".to_string(),
4009 role: ContentRole::Assistant,
4010 stop_reason: None,
4011 };
4012 assert_eq!(result.first_text(), Some("After image"));
4013 }
4014
4015 #[test]
4016 fn test_create_message_result_first_text_none() {
4017 let result = CreateMessageResult {
4018 content: SamplingContentOrArray::Single(SamplingContent::Image {
4019 data: "base64data".to_string(),
4020 mime_type: "image/png".to_string(),
4021 }),
4022 model: "test".to_string(),
4023 role: ContentRole::Assistant,
4024 stop_reason: None,
4025 };
4026 assert_eq!(result.first_text(), None);
4027 }
4028
4029 #[test]
4030 fn test_tool_annotations_accessors() {
4031 let annotations = ToolAnnotations {
4032 read_only_hint: true,
4033 destructive_hint: false,
4034 idempotent_hint: true,
4035 open_world_hint: false,
4036 ..Default::default()
4037 };
4038
4039 assert!(annotations.is_read_only());
4040 assert!(!annotations.is_destructive());
4041 assert!(annotations.is_idempotent());
4042 assert!(!annotations.is_open_world());
4043 }
4044
4045 #[test]
4046 fn test_tool_annotations_defaults() {
4047 let annotations = ToolAnnotations::default();
4051
4052 assert!(!annotations.is_read_only());
4053 assert!(!annotations.is_destructive());
4054 assert!(!annotations.is_idempotent());
4055 assert!(!annotations.is_open_world());
4056 }
4057
4058 #[test]
4059 fn test_tool_annotations_serde_defaults() {
4060 let annotations: ToolAnnotations = serde_json::from_str("{}").unwrap();
4063
4064 assert!(!annotations.is_read_only());
4065 assert!(annotations.is_destructive());
4066 assert!(!annotations.is_idempotent());
4067 assert!(annotations.is_open_world());
4068 }
4069
4070 #[test]
4071 fn test_tool_definition_accessors_with_annotations() {
4072 let def = ToolDefinition {
4073 name: "test".to_string(),
4074 title: None,
4075 description: None,
4076 input_schema: serde_json::json!({"type": "object"}),
4077 output_schema: None,
4078 icons: None,
4079 annotations: Some(ToolAnnotations {
4080 read_only_hint: true,
4081 idempotent_hint: true,
4082 destructive_hint: false,
4083 open_world_hint: false,
4084 ..Default::default()
4085 }),
4086 };
4087
4088 assert!(def.is_read_only());
4089 assert!(!def.is_destructive());
4090 assert!(def.is_idempotent());
4091 assert!(!def.is_open_world());
4092 }
4093
4094 #[test]
4095 fn test_tool_definition_accessors_without_annotations() {
4096 let def = ToolDefinition {
4097 name: "test".to_string(),
4098 title: None,
4099 description: None,
4100 input_schema: serde_json::json!({"type": "object"}),
4101 output_schema: None,
4102 icons: None,
4103 annotations: None,
4104 };
4105
4106 assert!(!def.is_read_only());
4108 assert!(def.is_destructive());
4109 assert!(!def.is_idempotent());
4110 assert!(def.is_open_world());
4111 }
4112
4113 #[test]
4114 fn test_call_tool_result_from_list() {
4115 #[derive(serde::Serialize)]
4116 struct Item {
4117 name: String,
4118 }
4119
4120 let items = vec![
4121 Item {
4122 name: "a".to_string(),
4123 },
4124 Item {
4125 name: "b".to_string(),
4126 },
4127 Item {
4128 name: "c".to_string(),
4129 },
4130 ];
4131
4132 let result = CallToolResult::from_list("items", &items).unwrap();
4133 assert!(!result.is_error);
4134
4135 let structured = result.structured_content.unwrap();
4136 assert_eq!(structured["count"], 3);
4137 assert_eq!(structured["items"].as_array().unwrap().len(), 3);
4138 assert_eq!(structured["items"][0]["name"], "a");
4139 }
4140
4141 #[test]
4142 fn test_call_tool_result_from_list_empty() {
4143 let items: Vec<String> = vec![];
4144 let result = CallToolResult::from_list("results", &items).unwrap();
4145 assert!(!result.is_error);
4146
4147 let structured = result.structured_content.unwrap();
4148 assert_eq!(structured["count"], 0);
4149 assert_eq!(structured["results"].as_array().unwrap().len(), 0);
4150 }
4151
4152 #[test]
4157 fn test_call_tool_result_as_json() {
4158 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4159 let value = result.as_json().unwrap().unwrap();
4160 assert_eq!(value["key"], "value");
4161 }
4162
4163 #[test]
4164 fn test_call_tool_result_as_json_from_text() {
4165 let result = CallToolResult::text(r#"{"key": "value"}"#);
4166 let value = result.as_json().unwrap().unwrap();
4167 assert_eq!(value["key"], "value");
4168 }
4169
4170 #[test]
4171 fn test_call_tool_result_as_json_none() {
4172 let result = CallToolResult::text("not json");
4173 let parsed = result.as_json().unwrap();
4174 assert!(parsed.is_err());
4175 }
4176
4177 #[test]
4178 fn test_call_tool_result_deserialize() {
4179 #[derive(Debug, serde::Deserialize, PartialEq)]
4180 struct Output {
4181 key: String,
4182 }
4183
4184 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4185 let output: Output = result.deserialize().unwrap().unwrap();
4186 assert_eq!(output.key, "value");
4187 }
4188
4189 #[test]
4190 fn test_call_tool_result_as_json_empty() {
4191 let result = CallToolResult {
4192 content: vec![],
4193 is_error: false,
4194 structured_content: None,
4195 };
4196 assert!(result.as_json().is_none());
4197 }
4198
4199 #[test]
4200 fn test_call_tool_result_deserialize_from_text() {
4201 #[derive(Debug, serde::Deserialize, PartialEq)]
4202 struct Output {
4203 key: String,
4204 }
4205
4206 let result = CallToolResult::text(r#"{"key": "from_text"}"#);
4207 let output: Output = result.deserialize().unwrap().unwrap();
4208 assert_eq!(output.key, "from_text");
4209 }
4210
4211 #[test]
4212 fn test_read_resource_result_as_json() {
4213 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
4214 let value = result.as_json().unwrap().unwrap();
4215 assert_eq!(value["port"], 8080);
4216 }
4217
4218 #[test]
4219 fn test_read_resource_result_deserialize() {
4220 #[derive(Debug, serde::Deserialize, PartialEq)]
4221 struct Config {
4222 port: u16,
4223 }
4224
4225 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
4226 let config: Config = result.deserialize().unwrap().unwrap();
4227 assert_eq!(config.port, 8080);
4228 }
4229
4230 #[test]
4231 fn test_get_prompt_result_as_json() {
4232 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
4233 let value = result.as_json().unwrap().unwrap();
4234 assert_eq!(value["action"], "analyze");
4235 }
4236
4237 #[test]
4238 fn test_get_prompt_result_deserialize() {
4239 #[derive(Debug, serde::Deserialize, PartialEq)]
4240 struct Params {
4241 action: String,
4242 }
4243
4244 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
4245 let params: Params = result.deserialize().unwrap().unwrap();
4246 assert_eq!(params.action, "analyze");
4247 }
4248
4249 #[test]
4250 fn test_get_prompt_result_as_json_empty() {
4251 let result = GetPromptResult {
4252 description: None,
4253 messages: vec![],
4254 };
4255 assert!(result.as_json().is_none());
4256 }
4257}