1use std::collections::HashMap;
7
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12use crate::error::JsonRpcError;
13
14pub const JSONRPC_VERSION: &str = "2.0";
16
17pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
19
20pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct JsonRpcRequest {
37 pub jsonrpc: String,
39 pub id: RequestId,
41 pub method: String,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub params: Option<Value>,
46}
47
48impl JsonRpcRequest {
49 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
51 Self {
52 jsonrpc: JSONRPC_VERSION.to_string(),
53 id: id.into(),
54 method: method.into(),
55 params: None,
56 }
57 }
58
59 pub fn with_params(mut self, params: Value) -> Self {
61 self.params = Some(params);
62 self
63 }
64
65 pub fn validate(&self) -> Result<(), JsonRpcError> {
68 if self.jsonrpc != JSONRPC_VERSION {
69 return Err(JsonRpcError::invalid_request(format!(
70 "Invalid JSON-RPC version: expected '{}', got '{}'",
71 JSONRPC_VERSION, self.jsonrpc
72 )));
73 }
74 Ok(())
75 }
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonRpcResultResponse {
81 pub jsonrpc: String,
83 pub id: RequestId,
85 pub result: Value,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct JsonRpcErrorResponse {
92 pub jsonrpc: String,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub id: Option<RequestId>,
97 pub error: JsonRpcError,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(untagged)]
104#[non_exhaustive]
105pub enum JsonRpcResponse {
106 Result(JsonRpcResultResponse),
108 Error(JsonRpcErrorResponse),
110}
111
112impl JsonRpcResponse {
113 pub fn result(id: RequestId, result: Value) -> Self {
115 Self::Result(JsonRpcResultResponse {
116 jsonrpc: JSONRPC_VERSION.to_string(),
117 id,
118 result,
119 })
120 }
121
122 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
124 Self::Error(JsonRpcErrorResponse {
125 jsonrpc: JSONRPC_VERSION.to_string(),
126 id,
127 error,
128 })
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(untagged)]
135#[non_exhaustive]
136pub enum JsonRpcMessage {
137 Single(JsonRpcRequest),
139 Batch(Vec<JsonRpcRequest>),
141}
142
143impl JsonRpcMessage {
144 pub fn is_batch(&self) -> bool {
146 matches!(self, JsonRpcMessage::Batch(_))
147 }
148
149 pub fn len(&self) -> usize {
151 match self {
152 JsonRpcMessage::Single(_) => 1,
153 JsonRpcMessage::Batch(batch) => batch.len(),
154 }
155 }
156
157 pub fn is_empty(&self) -> bool {
159 self.len() == 0
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(untagged)]
166#[non_exhaustive]
167pub enum JsonRpcResponseMessage {
168 Single(JsonRpcResponse),
170 Batch(Vec<JsonRpcResponse>),
172}
173
174impl JsonRpcResponseMessage {
175 pub fn is_batch(&self) -> bool {
177 matches!(self, JsonRpcResponseMessage::Batch(_))
178 }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct JsonRpcNotification {
184 pub jsonrpc: String,
185 pub method: String,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub params: Option<Value>,
188}
189
190impl JsonRpcNotification {
191 pub fn new(method: impl Into<String>) -> Self {
192 Self {
193 jsonrpc: JSONRPC_VERSION.to_string(),
194 method: method.into(),
195 params: None,
196 }
197 }
198
199 pub fn with_params(mut self, params: Value) -> Self {
200 self.params = Some(params);
201 self
202 }
203}
204
205pub mod notifications {
207 pub const INITIALIZED: &str = "notifications/initialized";
209 pub const CANCELLED: &str = "notifications/cancelled";
211 pub const PROGRESS: &str = "notifications/progress";
213 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
215 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
217 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
219 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
221 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
223 pub const MESSAGE: &str = "notifications/message";
225 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status";
227 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
229}
230
231#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
235#[serde(rename_all = "lowercase")]
236#[non_exhaustive]
237pub enum LogLevel {
238 Emergency,
240 Alert,
242 Critical,
244 Error,
246 Warning,
248 Notice,
250 #[default]
252 Info,
253 Debug,
255}
256
257impl std::fmt::Display for LogLevel {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 match self {
260 LogLevel::Emergency => write!(f, "emergency"),
261 LogLevel::Alert => write!(f, "alert"),
262 LogLevel::Critical => write!(f, "critical"),
263 LogLevel::Error => write!(f, "error"),
264 LogLevel::Warning => write!(f, "warning"),
265 LogLevel::Notice => write!(f, "notice"),
266 LogLevel::Info => write!(f, "info"),
267 LogLevel::Debug => write!(f, "debug"),
268 }
269 }
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct LoggingMessageParams {
275 pub level: LogLevel,
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub logger: Option<String>,
280 #[serde(default)]
282 pub data: Value,
283 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
285 pub meta: Option<Value>,
286}
287
288impl LoggingMessageParams {
289 pub fn new(level: LogLevel, data: impl Into<Value>) -> Self {
291 Self {
292 level,
293 logger: None,
294 data: data.into(),
295 meta: None,
296 }
297 }
298
299 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
301 self.logger = Some(logger.into());
302 self
303 }
304
305 pub fn with_data(mut self, data: impl Into<Value>) -> Self {
307 self.data = data.into();
308 self
309 }
310}
311
312#[derive(Debug, Clone, Deserialize)]
314pub struct SetLogLevelParams {
315 pub level: LogLevel,
317 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
319 pub meta: Option<RequestMeta>,
320}
321
322#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
324#[serde(untagged)]
325#[non_exhaustive]
326pub enum RequestId {
327 String(String),
328 Number(i64),
329}
330
331impl From<String> for RequestId {
332 fn from(s: String) -> Self {
333 RequestId::String(s)
334 }
335}
336
337impl From<&str> for RequestId {
338 fn from(s: &str) -> Self {
339 RequestId::String(s.to_string())
340 }
341}
342
343impl From<i64> for RequestId {
344 fn from(n: i64) -> Self {
345 RequestId::Number(n)
346 }
347}
348
349impl From<i32> for RequestId {
350 fn from(n: i32) -> Self {
351 RequestId::Number(n as i64)
352 }
353}
354
355#[derive(Debug, Clone)]
361#[non_exhaustive]
362pub enum McpRequest {
363 Initialize(InitializeParams),
365 ListTools(ListToolsParams),
367 CallTool(CallToolParams),
369 ListResources(ListResourcesParams),
371 ListResourceTemplates(ListResourceTemplatesParams),
373 ReadResource(ReadResourceParams),
375 SubscribeResource(SubscribeResourceParams),
377 UnsubscribeResource(UnsubscribeResourceParams),
379 ListPrompts(ListPromptsParams),
381 GetPrompt(GetPromptParams),
383 ListTasks(ListTasksParams),
385 GetTaskInfo(GetTaskInfoParams),
387 GetTaskResult(GetTaskResultParams),
389 CancelTask(CancelTaskParams),
391 Ping,
393 SetLoggingLevel(SetLogLevelParams),
395 Complete(CompleteParams),
397 Unknown {
399 method: String,
400 params: Option<Value>,
401 },
402}
403
404impl McpRequest {
405 pub fn method_name(&self) -> &str {
407 match self {
408 McpRequest::Initialize(_) => "initialize",
409 McpRequest::ListTools(_) => "tools/list",
410 McpRequest::CallTool(_) => "tools/call",
411 McpRequest::ListResources(_) => "resources/list",
412 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
413 McpRequest::ReadResource(_) => "resources/read",
414 McpRequest::SubscribeResource(_) => "resources/subscribe",
415 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
416 McpRequest::ListPrompts(_) => "prompts/list",
417 McpRequest::GetPrompt(_) => "prompts/get",
418 McpRequest::ListTasks(_) => "tasks/list",
419 McpRequest::GetTaskInfo(_) => "tasks/get",
420 McpRequest::GetTaskResult(_) => "tasks/result",
421 McpRequest::CancelTask(_) => "tasks/cancel",
422 McpRequest::Ping => "ping",
423 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
424 McpRequest::Complete(_) => "completion/complete",
425 McpRequest::Unknown { method, .. } => method,
426 }
427 }
428}
429
430#[derive(Debug, Clone)]
432#[non_exhaustive]
433pub enum McpNotification {
434 Initialized,
436 Cancelled(CancelledParams),
438 Progress(ProgressParams),
440 RootsListChanged,
442 Unknown {
444 method: String,
445 params: Option<Value>,
446 },
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct CancelledParams {
453 #[serde(default, skip_serializing_if = "Option::is_none")]
455 pub request_id: Option<RequestId>,
456 #[serde(skip_serializing_if = "Option::is_none")]
458 pub reason: Option<String>,
459 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
461 pub meta: Option<Value>,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(rename_all = "camelCase")]
467pub struct ProgressParams {
468 pub progress_token: ProgressToken,
470 pub progress: f64,
472 #[serde(skip_serializing_if = "Option::is_none")]
474 pub total: Option<f64>,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub message: Option<String>,
478 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
480 pub meta: Option<Value>,
481}
482
483#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
485#[serde(untagged)]
486#[non_exhaustive]
487pub enum ProgressToken {
488 String(String),
489 Number(i64),
490}
491
492#[derive(Debug, Clone, Default, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct RequestMeta {
496 #[serde(skip_serializing_if = "Option::is_none")]
498 pub progress_token: Option<ProgressToken>,
499}
500
501#[derive(Debug, Clone, Serialize)]
503#[serde(untagged)]
504#[non_exhaustive]
505pub enum McpResponse {
506 Initialize(InitializeResult),
507 ListTools(ListToolsResult),
508 CallTool(CallToolResult),
509 ListResources(ListResourcesResult),
510 ListResourceTemplates(ListResourceTemplatesResult),
511 ReadResource(ReadResourceResult),
512 SubscribeResource(EmptyResult),
513 UnsubscribeResource(EmptyResult),
514 ListPrompts(ListPromptsResult),
515 GetPrompt(GetPromptResult),
516 CreateTask(CreateTaskResult),
517 ListTasks(ListTasksResult),
518 GetTaskInfo(TaskObject),
519 GetTaskResult(CallToolResult),
520 CancelTask(TaskObject),
521 SetLoggingLevel(EmptyResult),
522 Complete(CompleteResult),
523 Pong(EmptyResult),
524 Empty(EmptyResult),
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
532#[serde(rename_all = "camelCase")]
533pub struct InitializeParams {
534 pub protocol_version: String,
535 pub capabilities: ClientCapabilities,
536 pub client_info: Implementation,
537 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
539 pub meta: Option<Value>,
540}
541
542#[derive(Debug, Clone, Default, Serialize, Deserialize)]
543pub struct ClientCapabilities {
544 #[serde(default, skip_serializing_if = "Option::is_none")]
545 pub roots: Option<RootsCapability>,
546 #[serde(default, skip_serializing_if = "Option::is_none")]
547 pub sampling: Option<SamplingCapability>,
548 #[serde(default, skip_serializing_if = "Option::is_none")]
549 pub elicitation: Option<ElicitationCapability>,
550 #[serde(default, skip_serializing_if = "Option::is_none")]
551 pub tasks: Option<ClientTasksCapability>,
552 #[serde(default, skip_serializing_if = "Option::is_none")]
554 pub experimental: Option<HashMap<String, serde_json::Value>>,
555 #[serde(default, skip_serializing_if = "Option::is_none")]
557 pub extensions: Option<HashMap<String, serde_json::Value>>,
558}
559
560#[derive(Debug, Clone, Default, Serialize, Deserialize)]
562pub struct ElicitationCapability {
563 #[serde(default, skip_serializing_if = "Option::is_none")]
565 pub form: Option<ElicitationFormCapability>,
566 #[serde(default, skip_serializing_if = "Option::is_none")]
568 pub url: Option<ElicitationUrlCapability>,
569}
570
571#[derive(Debug, Clone, Default, Serialize, Deserialize)]
573pub struct ElicitationFormCapability {}
574
575#[derive(Debug, Clone, Default, Serialize, Deserialize)]
577pub struct ElicitationUrlCapability {}
578
579#[derive(Debug, Clone, Default, Serialize, Deserialize)]
581#[serde(rename_all = "camelCase")]
582pub struct ClientTasksCapability {
583 #[serde(default, skip_serializing_if = "Option::is_none")]
585 pub list: Option<ClientTasksListCapability>,
586 #[serde(default, skip_serializing_if = "Option::is_none")]
588 pub cancel: Option<ClientTasksCancelCapability>,
589 #[serde(default, skip_serializing_if = "Option::is_none")]
591 pub requests: Option<ClientTasksRequestsCapability>,
592}
593
594#[derive(Debug, Clone, Default, Serialize, Deserialize)]
596pub struct ClientTasksListCapability {}
597
598#[derive(Debug, Clone, Default, Serialize, Deserialize)]
600pub struct ClientTasksCancelCapability {}
601
602#[derive(Debug, Clone, Default, Serialize, Deserialize)]
604#[serde(rename_all = "camelCase")]
605pub struct ClientTasksRequestsCapability {
606 #[serde(default, skip_serializing_if = "Option::is_none")]
608 pub sampling: Option<ClientTasksSamplingCapability>,
609 #[serde(default, skip_serializing_if = "Option::is_none")]
611 pub elicitation: Option<ClientTasksElicitationCapability>,
612}
613
614#[derive(Debug, Clone, Default, Serialize, Deserialize)]
616#[serde(rename_all = "camelCase")]
617pub struct ClientTasksSamplingCapability {
618 #[serde(default, skip_serializing_if = "Option::is_none")]
620 pub create_message: Option<ClientTasksSamplingCreateMessageCapability>,
621}
622
623#[derive(Debug, Clone, Default, Serialize, Deserialize)]
625pub struct ClientTasksSamplingCreateMessageCapability {}
626
627#[derive(Debug, Clone, Default, Serialize, Deserialize)]
629#[serde(rename_all = "camelCase")]
630pub struct ClientTasksElicitationCapability {
631 #[serde(default, skip_serializing_if = "Option::is_none")]
633 pub create: Option<ClientTasksElicitationCreateCapability>,
634}
635
636#[derive(Debug, Clone, Default, Serialize, Deserialize)]
638pub struct ClientTasksElicitationCreateCapability {}
639
640#[derive(Debug, Clone, Default, Serialize, Deserialize)]
664#[serde(rename_all = "camelCase")]
665pub struct RootsCapability {
666 #[serde(default)]
668 pub list_changed: bool,
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct Root {
692 pub uri: String,
694 #[serde(default, skip_serializing_if = "Option::is_none")]
696 pub name: Option<String>,
697 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
699 pub meta: Option<Value>,
700}
701
702impl Root {
703 pub fn new(uri: impl Into<String>) -> Self {
705 Self {
706 uri: uri.into(),
707 name: None,
708 meta: None,
709 }
710 }
711
712 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
714 Self {
715 uri: uri.into(),
716 name: Some(name.into()),
717 meta: None,
718 }
719 }
720}
721
722#[derive(Debug, Clone, Default, Serialize, Deserialize)]
729pub struct ListRootsParams {
730 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
732 pub meta: Option<RequestMeta>,
733}
734
735#[derive(Debug, Clone, Serialize, Deserialize)]
737pub struct ListRootsResult {
738 pub roots: Vec<Root>,
740 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
742 pub meta: Option<Value>,
743}
744
745#[derive(Debug, Clone, Default, Serialize, Deserialize)]
746pub struct SamplingCapability {
747 #[serde(default, skip_serializing_if = "Option::is_none")]
749 pub tools: Option<SamplingToolsCapability>,
750 #[serde(default, skip_serializing_if = "Option::is_none")]
752 pub context: Option<SamplingContextCapability>,
753}
754
755#[derive(Debug, Clone, Default, Serialize, Deserialize)]
757pub struct SamplingToolsCapability {}
758
759#[derive(Debug, Clone, Default, Serialize, Deserialize)]
761pub struct SamplingContextCapability {}
762
763#[derive(Debug, Clone, Default, Serialize, Deserialize)]
765pub struct CompletionsCapability {}
766
767#[derive(Debug, Clone, Serialize, Deserialize)]
773pub struct PromptReference {
774 #[serde(rename = "type")]
776 pub ref_type: String,
777 pub name: String,
779}
780
781impl PromptReference {
782 pub fn new(name: impl Into<String>) -> Self {
784 Self {
785 ref_type: "ref/prompt".to_string(),
786 name: name.into(),
787 }
788 }
789}
790
791#[derive(Debug, Clone, Serialize, Deserialize)]
793pub struct ResourceReference {
794 #[serde(rename = "type")]
796 pub ref_type: String,
797 pub uri: String,
799}
800
801impl ResourceReference {
802 pub fn new(uri: impl Into<String>) -> Self {
804 Self {
805 ref_type: "ref/resource".to_string(),
806 uri: uri.into(),
807 }
808 }
809}
810
811#[derive(Debug, Clone, Serialize, Deserialize)]
813#[serde(tag = "type")]
814#[non_exhaustive]
815pub enum CompletionReference {
816 #[serde(rename = "ref/prompt")]
818 Prompt {
819 name: String,
821 },
822 #[serde(rename = "ref/resource")]
824 Resource {
825 uri: String,
827 },
828}
829
830impl CompletionReference {
831 pub fn prompt(name: impl Into<String>) -> Self {
833 Self::Prompt { name: name.into() }
834 }
835
836 pub fn resource(uri: impl Into<String>) -> Self {
838 Self::Resource { uri: uri.into() }
839 }
840}
841
842#[derive(Debug, Clone, Serialize, Deserialize)]
844pub struct CompletionArgument {
845 pub name: String,
847 pub value: String,
849}
850
851impl CompletionArgument {
852 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
854 Self {
855 name: name.into(),
856 value: value.into(),
857 }
858 }
859}
860
861#[derive(Debug, Clone, Serialize, Deserialize)]
863#[serde(rename_all = "camelCase")]
864pub struct CompleteParams {
865 #[serde(rename = "ref")]
867 pub reference: CompletionReference,
868 pub argument: CompletionArgument,
870 #[serde(default, skip_serializing_if = "Option::is_none")]
872 pub context: Option<CompletionContext>,
873 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
875 pub meta: Option<Value>,
876}
877
878#[derive(Debug, Clone, Serialize, Deserialize)]
880#[serde(rename_all = "camelCase")]
881pub struct CompletionContext {
882 #[serde(default, skip_serializing_if = "Option::is_none")]
884 pub arguments: Option<std::collections::HashMap<String, String>>,
885}
886
887#[derive(Debug, Clone, Serialize, Deserialize)]
889#[serde(rename_all = "camelCase")]
890pub struct Completion {
891 pub values: Vec<String>,
893 #[serde(default, skip_serializing_if = "Option::is_none")]
895 pub total: Option<u32>,
896 #[serde(default, skip_serializing_if = "Option::is_none")]
898 pub has_more: Option<bool>,
899}
900
901impl Completion {
902 pub fn new(values: Vec<String>) -> Self {
904 Self {
905 values,
906 total: None,
907 has_more: None,
908 }
909 }
910
911 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
913 Self {
914 values,
915 total: Some(total),
916 has_more: Some(has_more),
917 }
918 }
919}
920
921#[derive(Debug, Clone, Serialize, Deserialize)]
923pub struct CompleteResult {
924 pub completion: Completion,
926 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
928 pub meta: Option<Value>,
929}
930
931impl CompleteResult {
932 pub fn new(values: Vec<String>) -> Self {
934 Self {
935 completion: Completion::new(values),
936 meta: None,
937 }
938 }
939
940 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
942 Self {
943 completion: Completion::with_pagination(values, total, has_more),
944 meta: None,
945 }
946 }
947}
948
949#[derive(Debug, Clone, Serialize, Deserialize)]
955pub struct ModelHint {
956 #[serde(default, skip_serializing_if = "Option::is_none")]
958 pub name: Option<String>,
959}
960
961impl ModelHint {
962 pub fn new(name: impl Into<String>) -> Self {
964 Self {
965 name: Some(name.into()),
966 }
967 }
968}
969
970#[derive(Debug, Clone, Default, Serialize, Deserialize)]
972#[serde(rename_all = "camelCase")]
973pub struct ModelPreferences {
974 #[serde(default, skip_serializing_if = "Option::is_none")]
976 pub speed_priority: Option<f64>,
977 #[serde(default, skip_serializing_if = "Option::is_none")]
979 pub intelligence_priority: Option<f64>,
980 #[serde(default, skip_serializing_if = "Option::is_none")]
982 pub cost_priority: Option<f64>,
983 #[serde(default, skip_serializing_if = "Vec::is_empty")]
985 pub hints: Vec<ModelHint>,
986}
987
988impl ModelPreferences {
989 pub fn new() -> Self {
991 Self::default()
992 }
993
994 pub fn speed(mut self, priority: f64) -> Self {
996 self.speed_priority = Some(priority.clamp(0.0, 1.0));
997 self
998 }
999
1000 pub fn intelligence(mut self, priority: f64) -> Self {
1002 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
1003 self
1004 }
1005
1006 pub fn cost(mut self, priority: f64) -> Self {
1008 self.cost_priority = Some(priority.clamp(0.0, 1.0));
1009 self
1010 }
1011
1012 pub fn hint(mut self, name: impl Into<String>) -> Self {
1014 self.hints.push(ModelHint::new(name));
1015 self
1016 }
1017}
1018
1019#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1021#[serde(rename_all = "camelCase")]
1022#[non_exhaustive]
1023pub enum IncludeContext {
1024 AllServers,
1026 ThisServer,
1028 #[default]
1030 None,
1031}
1032
1033#[derive(Debug, Clone, Serialize, Deserialize)]
1035pub struct SamplingMessage {
1036 pub role: ContentRole,
1038 pub content: SamplingContentOrArray,
1040 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1042 pub meta: Option<Value>,
1043}
1044
1045impl SamplingMessage {
1046 pub fn user(text: impl Into<String>) -> Self {
1048 Self {
1049 role: ContentRole::User,
1050 content: SamplingContentOrArray::Single(SamplingContent::Text {
1051 text: text.into(),
1052 annotations: None,
1053 meta: None,
1054 }),
1055 meta: None,
1056 }
1057 }
1058
1059 pub fn assistant(text: impl Into<String>) -> Self {
1061 Self {
1062 role: ContentRole::Assistant,
1063 content: SamplingContentOrArray::Single(SamplingContent::Text {
1064 text: text.into(),
1065 annotations: None,
1066 meta: None,
1067 }),
1068 meta: None,
1069 }
1070 }
1071}
1072
1073#[derive(Debug, Clone, Serialize, Deserialize)]
1078#[serde(rename_all = "camelCase")]
1079pub struct SamplingTool {
1080 pub name: String,
1082 #[serde(default, skip_serializing_if = "Option::is_none")]
1084 pub title: Option<String>,
1085 #[serde(skip_serializing_if = "Option::is_none")]
1087 pub description: Option<String>,
1088 pub input_schema: Value,
1090 #[serde(default, skip_serializing_if = "Option::is_none")]
1092 pub output_schema: Option<Value>,
1093 #[serde(default, skip_serializing_if = "Option::is_none")]
1095 pub icons: Option<Vec<ToolIcon>>,
1096 #[serde(default, skip_serializing_if = "Option::is_none")]
1098 pub annotations: Option<ToolAnnotations>,
1099 #[serde(default, skip_serializing_if = "Option::is_none")]
1101 pub execution: Option<ToolExecution>,
1102}
1103
1104#[derive(Debug, Clone, Serialize, Deserialize)]
1108pub struct ToolChoice {
1109 pub mode: String,
1111 #[serde(skip_serializing_if = "Option::is_none")]
1113 pub name: Option<String>,
1114}
1115
1116impl ToolChoice {
1117 pub fn auto() -> Self {
1119 Self {
1120 mode: "auto".to_string(),
1121 name: None,
1122 }
1123 }
1124
1125 pub fn required() -> Self {
1127 Self {
1128 mode: "required".to_string(),
1129 name: None,
1130 }
1131 }
1132
1133 pub fn none() -> Self {
1135 Self {
1136 mode: "none".to_string(),
1137 name: None,
1138 }
1139 }
1140
1141 pub fn tool(name: impl Into<String>) -> Self {
1143 Self {
1144 mode: "tool".to_string(),
1145 name: Some(name.into()),
1146 }
1147 }
1148}
1149
1150#[derive(Debug, Clone, Serialize, Deserialize)]
1152#[serde(tag = "type", rename_all = "lowercase")]
1153#[non_exhaustive]
1154pub enum SamplingContent {
1155 Text {
1157 text: String,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1161 annotations: Option<ContentAnnotations>,
1162 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1164 meta: Option<Value>,
1165 },
1166 Image {
1168 data: String,
1170 #[serde(rename = "mimeType")]
1172 mime_type: String,
1173 #[serde(default, skip_serializing_if = "Option::is_none")]
1175 annotations: Option<ContentAnnotations>,
1176 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1178 meta: Option<Value>,
1179 },
1180 Audio {
1182 data: String,
1184 #[serde(rename = "mimeType")]
1186 mime_type: String,
1187 #[serde(default, skip_serializing_if = "Option::is_none")]
1189 annotations: Option<ContentAnnotations>,
1190 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1192 meta: Option<Value>,
1193 },
1194 #[serde(rename = "tool_use")]
1196 ToolUse {
1197 id: String,
1199 name: String,
1201 input: Value,
1203 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1205 meta: Option<Value>,
1206 },
1207 #[serde(rename = "tool_result")]
1209 ToolResult {
1210 #[serde(rename = "toolUseId")]
1212 tool_use_id: String,
1213 content: Vec<SamplingContent>,
1215 #[serde(
1217 default,
1218 rename = "structuredContent",
1219 skip_serializing_if = "Option::is_none"
1220 )]
1221 structured_content: Option<Value>,
1222 #[serde(default, rename = "isError", skip_serializing_if = "Option::is_none")]
1224 is_error: Option<bool>,
1225 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1227 meta: Option<Value>,
1228 },
1229}
1230
1231impl SamplingContent {
1232 pub fn as_text(&self) -> Option<&str> {
1253 match self {
1254 SamplingContent::Text { text, .. } => Some(text),
1255 _ => None,
1256 }
1257 }
1258}
1259
1260#[derive(Debug, Clone, Serialize, Deserialize)]
1265#[serde(untagged)]
1266#[non_exhaustive]
1267pub enum SamplingContentOrArray {
1268 Single(SamplingContent),
1270 Array(Vec<SamplingContent>),
1272}
1273
1274impl SamplingContentOrArray {
1275 pub fn items(&self) -> Vec<&SamplingContent> {
1277 match self {
1278 Self::Single(c) => vec![c],
1279 Self::Array(arr) => arr.iter().collect(),
1280 }
1281 }
1282
1283 pub fn into_items(self) -> Vec<SamplingContent> {
1285 match self {
1286 Self::Single(c) => vec![c],
1287 Self::Array(arr) => arr,
1288 }
1289 }
1290}
1291
1292#[derive(Debug, Clone, Serialize, Deserialize)]
1294#[serde(rename_all = "camelCase")]
1295pub struct CreateMessageParams {
1296 pub messages: Vec<SamplingMessage>,
1298 pub max_tokens: u32,
1300 #[serde(default, skip_serializing_if = "Option::is_none")]
1302 pub system_prompt: Option<String>,
1303 #[serde(default, skip_serializing_if = "Option::is_none")]
1305 pub temperature: Option<f64>,
1306 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1308 pub stop_sequences: Vec<String>,
1309 #[serde(default, skip_serializing_if = "Option::is_none")]
1311 pub model_preferences: Option<ModelPreferences>,
1312 #[serde(default, skip_serializing_if = "Option::is_none")]
1314 pub include_context: Option<IncludeContext>,
1315 #[serde(default, skip_serializing_if = "Option::is_none")]
1317 pub metadata: Option<serde_json::Map<String, Value>>,
1318 #[serde(default, skip_serializing_if = "Option::is_none")]
1320 pub tools: Option<Vec<SamplingTool>>,
1321 #[serde(default, skip_serializing_if = "Option::is_none")]
1323 pub tool_choice: Option<ToolChoice>,
1324 #[serde(default, skip_serializing_if = "Option::is_none")]
1326 pub task: Option<TaskRequestParams>,
1327 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1329 pub meta: Option<Value>,
1330}
1331
1332impl CreateMessageParams {
1333 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1335 Self {
1336 messages,
1337 max_tokens,
1338 system_prompt: None,
1339 temperature: None,
1340 stop_sequences: Vec::new(),
1341 model_preferences: None,
1342 include_context: None,
1343 metadata: None,
1344 tools: None,
1345 tool_choice: None,
1346 task: None,
1347 meta: None,
1348 }
1349 }
1350
1351 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1353 self.system_prompt = Some(prompt.into());
1354 self
1355 }
1356
1357 pub fn temperature(mut self, temp: f64) -> Self {
1359 self.temperature = Some(temp.clamp(0.0, 1.0));
1360 self
1361 }
1362
1363 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1365 self.stop_sequences.push(seq.into());
1366 self
1367 }
1368
1369 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1371 self.model_preferences = Some(prefs);
1372 self
1373 }
1374
1375 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1377 self.include_context = Some(mode);
1378 self
1379 }
1380
1381 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1383 self.tools = Some(tools);
1384 self
1385 }
1386
1387 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1389 self.tool_choice = Some(choice);
1390 self
1391 }
1392}
1393
1394#[derive(Debug, Clone, Serialize, Deserialize)]
1396#[serde(rename_all = "camelCase")]
1397pub struct CreateMessageResult {
1398 pub content: SamplingContentOrArray,
1400 pub model: String,
1402 pub role: ContentRole,
1404 #[serde(default, skip_serializing_if = "Option::is_none")]
1406 pub stop_reason: Option<String>,
1407 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1409 pub meta: Option<Value>,
1410}
1411
1412impl CreateMessageResult {
1413 pub fn content_items(&self) -> Vec<&SamplingContent> {
1415 self.content.items()
1416 }
1417
1418 pub fn first_text(&self) -> Option<&str> {
1442 self.content.items().iter().find_map(|c| c.as_text())
1443 }
1444}
1445
1446#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1448#[serde(rename_all = "camelCase")]
1449pub struct Implementation {
1450 pub name: String,
1452 pub version: String,
1454 #[serde(skip_serializing_if = "Option::is_none")]
1456 pub title: Option<String>,
1457 #[serde(skip_serializing_if = "Option::is_none")]
1459 pub description: Option<String>,
1460 #[serde(skip_serializing_if = "Option::is_none")]
1462 pub icons: Option<Vec<ToolIcon>>,
1463 #[serde(skip_serializing_if = "Option::is_none")]
1465 pub website_url: Option<String>,
1466 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1468 pub meta: Option<Value>,
1469}
1470
1471#[derive(Debug, Clone, Serialize, Deserialize)]
1472#[serde(rename_all = "camelCase")]
1473pub struct InitializeResult {
1474 pub protocol_version: String,
1475 pub capabilities: ServerCapabilities,
1476 pub server_info: Implementation,
1477 #[serde(skip_serializing_if = "Option::is_none")]
1480 pub instructions: Option<String>,
1481 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1483 pub meta: Option<Value>,
1484}
1485
1486#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1487#[serde(rename_all = "camelCase")]
1488pub struct ServerCapabilities {
1489 #[serde(default, skip_serializing_if = "Option::is_none")]
1490 pub tools: Option<ToolsCapability>,
1491 #[serde(default, skip_serializing_if = "Option::is_none")]
1492 pub resources: Option<ResourcesCapability>,
1493 #[serde(default, skip_serializing_if = "Option::is_none")]
1494 pub prompts: Option<PromptsCapability>,
1495 #[serde(default, skip_serializing_if = "Option::is_none")]
1497 pub logging: Option<LoggingCapability>,
1498 #[serde(default, skip_serializing_if = "Option::is_none")]
1499 pub tasks: Option<TasksCapability>,
1500 #[serde(default, skip_serializing_if = "Option::is_none")]
1502 pub completions: Option<CompletionsCapability>,
1503 #[serde(default, skip_serializing_if = "Option::is_none")]
1505 pub experimental: Option<HashMap<String, serde_json::Value>>,
1506 #[serde(default, skip_serializing_if = "Option::is_none")]
1508 pub extensions: Option<HashMap<String, serde_json::Value>>,
1509}
1510
1511#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1513pub struct LoggingCapability {}
1514
1515#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1517#[serde(rename_all = "camelCase")]
1518pub struct TasksCapability {
1519 #[serde(default, skip_serializing_if = "Option::is_none")]
1521 pub list: Option<TasksListCapability>,
1522 #[serde(default, skip_serializing_if = "Option::is_none")]
1524 pub cancel: Option<TasksCancelCapability>,
1525 #[serde(default, skip_serializing_if = "Option::is_none")]
1527 pub requests: Option<TasksRequestsCapability>,
1528}
1529
1530#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1532pub struct TasksListCapability {}
1533
1534#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1536pub struct TasksCancelCapability {}
1537
1538#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1540#[serde(rename_all = "camelCase")]
1541pub struct TasksRequestsCapability {
1542 #[serde(default, skip_serializing_if = "Option::is_none")]
1544 pub tools: Option<TasksToolsRequestsCapability>,
1545}
1546
1547#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1549#[serde(rename_all = "camelCase")]
1550pub struct TasksToolsRequestsCapability {
1551 #[serde(default, skip_serializing_if = "Option::is_none")]
1553 pub call: Option<TasksToolsCallCapability>,
1554}
1555
1556#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1558pub struct TasksToolsCallCapability {}
1559
1560#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1561#[serde(rename_all = "camelCase")]
1562pub struct ToolsCapability {
1563 #[serde(default)]
1564 pub list_changed: bool,
1565}
1566
1567#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1568#[serde(rename_all = "camelCase")]
1569pub struct ResourcesCapability {
1570 #[serde(default)]
1571 pub subscribe: bool,
1572 #[serde(default)]
1573 pub list_changed: bool,
1574}
1575
1576#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1577#[serde(rename_all = "camelCase")]
1578pub struct PromptsCapability {
1579 #[serde(default)]
1580 pub list_changed: bool,
1581}
1582
1583#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1588pub struct ListToolsParams {
1589 #[serde(default, skip_serializing_if = "Option::is_none")]
1590 pub cursor: Option<String>,
1591 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1593 pub meta: Option<RequestMeta>,
1594}
1595
1596#[derive(Debug, Clone, Serialize, Deserialize)]
1597#[serde(rename_all = "camelCase")]
1598pub struct ListToolsResult {
1599 pub tools: Vec<ToolDefinition>,
1600 #[serde(default, skip_serializing_if = "Option::is_none")]
1601 pub next_cursor: Option<String>,
1602 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1604 pub meta: Option<Value>,
1605}
1606
1607#[derive(Debug, Clone, Serialize, Deserialize)]
1609#[serde(rename_all = "camelCase")]
1610pub struct ToolDefinition {
1611 pub name: String,
1612 #[serde(skip_serializing_if = "Option::is_none")]
1614 pub title: Option<String>,
1615 #[serde(skip_serializing_if = "Option::is_none")]
1616 pub description: Option<String>,
1617 pub input_schema: Value,
1618 #[serde(skip_serializing_if = "Option::is_none")]
1620 pub output_schema: Option<Value>,
1621 #[serde(skip_serializing_if = "Option::is_none")]
1623 pub icons: Option<Vec<ToolIcon>>,
1624 #[serde(skip_serializing_if = "Option::is_none")]
1627 pub annotations: Option<ToolAnnotations>,
1628 #[serde(skip_serializing_if = "Option::is_none")]
1630 pub execution: Option<ToolExecution>,
1631 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1633 pub meta: Option<Value>,
1634}
1635
1636#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1638#[serde(rename_all = "lowercase")]
1639#[non_exhaustive]
1640pub enum IconTheme {
1641 Light,
1643 Dark,
1645}
1646
1647#[derive(Debug, Clone, Serialize, Deserialize)]
1649#[serde(rename_all = "camelCase")]
1650pub struct ToolIcon {
1651 pub src: String,
1653 #[serde(skip_serializing_if = "Option::is_none")]
1655 pub mime_type: Option<String>,
1656 #[serde(skip_serializing_if = "Option::is_none")]
1658 pub sizes: Option<Vec<String>>,
1659 #[serde(skip_serializing_if = "Option::is_none")]
1661 pub theme: Option<IconTheme>,
1662}
1663
1664#[derive(Debug, Clone, Serialize, Deserialize)]
1667#[serde(rename_all = "camelCase")]
1668pub struct ToolAnnotations {
1669 #[serde(skip_serializing_if = "Option::is_none")]
1671 pub title: Option<String>,
1672 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1674 pub read_only_hint: bool,
1675 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1678 pub destructive_hint: bool,
1679 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1682 pub idempotent_hint: bool,
1683 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1685 pub open_world_hint: bool,
1686}
1687
1688impl Default for ToolAnnotations {
1689 fn default() -> Self {
1690 Self {
1691 title: None,
1692 read_only_hint: false,
1693 destructive_hint: true,
1694 idempotent_hint: false,
1695 open_world_hint: true,
1696 }
1697 }
1698}
1699
1700impl ToolAnnotations {
1701 pub fn is_read_only(&self) -> bool {
1703 self.read_only_hint
1704 }
1705
1706 pub fn is_destructive(&self) -> bool {
1708 self.destructive_hint
1709 }
1710
1711 pub fn is_idempotent(&self) -> bool {
1713 self.idempotent_hint
1714 }
1715
1716 pub fn is_open_world(&self) -> bool {
1718 self.open_world_hint
1719 }
1720}
1721
1722impl ToolDefinition {
1723 pub fn is_read_only(&self) -> bool {
1727 self.annotations.as_ref().is_some_and(|a| a.read_only_hint)
1728 }
1729
1730 pub fn is_destructive(&self) -> bool {
1734 self.annotations.as_ref().is_none_or(|a| a.destructive_hint)
1735 }
1736
1737 pub fn is_idempotent(&self) -> bool {
1741 self.annotations.as_ref().is_some_and(|a| a.idempotent_hint)
1742 }
1743
1744 pub fn is_open_world(&self) -> bool {
1748 self.annotations.as_ref().is_none_or(|a| a.open_world_hint)
1749 }
1750}
1751
1752fn default_true() -> bool {
1753 true
1754}
1755
1756fn is_true(v: &bool) -> bool {
1757 *v
1758}
1759
1760#[derive(Debug, Clone, Serialize, Deserialize)]
1761pub struct CallToolParams {
1762 pub name: String,
1763 #[serde(default)]
1764 pub arguments: Value,
1765 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1767 pub meta: Option<RequestMeta>,
1768 #[serde(default, skip_serializing_if = "Option::is_none")]
1770 pub task: Option<TaskRequestParams>,
1771}
1772
1773#[derive(Debug, Clone, Serialize, Deserialize)]
1794#[serde(rename_all = "camelCase")]
1795pub struct CallToolResult {
1796 pub content: Vec<Content>,
1798 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1800 pub is_error: bool,
1801 #[serde(default, skip_serializing_if = "Option::is_none")]
1803 pub structured_content: Option<Value>,
1804 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1806 pub meta: Option<Value>,
1807}
1808
1809impl CallToolResult {
1810 pub fn text(text: impl Into<String>) -> Self {
1814 Self {
1815 content: vec![Content::Text {
1816 text: text.into(),
1817 annotations: None,
1818 meta: None,
1819 }],
1820 is_error: false,
1821 structured_content: None,
1822 meta: None,
1823 }
1824 }
1825
1826 pub fn error(message: impl Into<String>) -> Self {
1831 Self {
1832 content: vec![Content::Text {
1833 text: message.into(),
1834 annotations: None,
1835 meta: None,
1836 }],
1837 is_error: true,
1838 structured_content: None,
1839 meta: None,
1840 }
1841 }
1842
1843 pub fn json(value: Value) -> Self {
1851 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1852 Self {
1853 content: vec![Content::Text {
1854 text,
1855 annotations: None,
1856 meta: None,
1857 }],
1858 is_error: false,
1859 structured_content: Some(value),
1860 meta: None,
1861 }
1862 }
1863
1864 pub fn from_serialize(
1896 value: &impl serde::Serialize,
1897 ) -> std::result::Result<Self, crate::error::Error> {
1898 let json_value = serde_json::to_value(value)
1899 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1900 Ok(Self::json(json_value))
1901 }
1902
1903 pub fn from_list<T: serde::Serialize>(
1930 key: &str,
1931 items: &[T],
1932 ) -> std::result::Result<Self, crate::error::Error> {
1933 Self::from_serialize(&serde_json::json!({ key: items, "count": items.len() }))
1934 }
1935
1936 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1951 Self {
1952 content: vec![Content::Image {
1953 data: data.into(),
1954 mime_type: mime_type.into(),
1955 annotations: None,
1956 meta: None,
1957 }],
1958 is_error: false,
1959 structured_content: None,
1960 meta: None,
1961 }
1962 }
1963
1964 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1979 Self {
1980 content: vec![Content::Audio {
1981 data: data.into(),
1982 mime_type: mime_type.into(),
1983 annotations: None,
1984 meta: None,
1985 }],
1986 is_error: false,
1987 structured_content: None,
1988 meta: None,
1989 }
1990 }
1991
1992 pub fn resource_link(uri: impl Into<String>, name: impl Into<String>) -> Self {
2009 Self {
2010 content: vec![Content::ResourceLink {
2011 uri: uri.into(),
2012 name: name.into(),
2013 title: None,
2014 description: None,
2015 mime_type: None,
2016 size: None,
2017 icons: None,
2018 annotations: None,
2019 meta: None,
2020 }],
2021 is_error: false,
2022 structured_content: None,
2023 meta: None,
2024 }
2025 }
2026
2027 pub fn resource_link_with_meta(
2029 uri: impl Into<String>,
2030 name: impl Into<String>,
2031 description: Option<String>,
2032 mime_type: Option<String>,
2033 ) -> Self {
2034 Self {
2035 content: vec![Content::ResourceLink {
2036 uri: uri.into(),
2037 name: name.into(),
2038 title: None,
2039 description,
2040 mime_type,
2041 size: None,
2042 icons: None,
2043 annotations: None,
2044 meta: None,
2045 }],
2046 is_error: false,
2047 structured_content: None,
2048 meta: None,
2049 }
2050 }
2051
2052 pub fn resource(resource: ResourceContent) -> Self {
2054 Self {
2055 content: vec![Content::Resource {
2056 resource,
2057 annotations: None,
2058 meta: None,
2059 }],
2060 is_error: false,
2061 structured_content: None,
2062 meta: None,
2063 }
2064 }
2065
2066 pub fn all_text(&self) -> String {
2080 self.content.iter().filter_map(|c| c.as_text()).collect()
2081 }
2082
2083 pub fn first_text(&self) -> Option<&str> {
2096 self.content.iter().find_map(|c| c.as_text())
2097 }
2098
2099 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2116 if let Some(ref sc) = self.structured_content {
2117 return Some(Ok(sc.clone()));
2118 }
2119 self.first_text().map(serde_json::from_str)
2120 }
2121
2122 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2142 if let Some(ref sc) = self.structured_content {
2143 return Some(serde_json::from_value(sc.clone()));
2144 }
2145 self.first_text().map(serde_json::from_str)
2146 }
2147}
2148
2149#[derive(Debug, Clone, Serialize, Deserialize)]
2154#[serde(tag = "type", rename_all = "snake_case")]
2155#[non_exhaustive]
2156pub enum Content {
2157 Text {
2159 text: String,
2161 #[serde(skip_serializing_if = "Option::is_none")]
2163 annotations: Option<ContentAnnotations>,
2164 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2166 meta: Option<Value>,
2167 },
2168 Image {
2170 data: String,
2172 #[serde(rename = "mimeType")]
2174 mime_type: String,
2175 #[serde(skip_serializing_if = "Option::is_none")]
2177 annotations: Option<ContentAnnotations>,
2178 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2180 meta: Option<Value>,
2181 },
2182 Audio {
2184 data: String,
2186 #[serde(rename = "mimeType")]
2188 mime_type: String,
2189 #[serde(skip_serializing_if = "Option::is_none")]
2191 annotations: Option<ContentAnnotations>,
2192 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2194 meta: Option<Value>,
2195 },
2196 Resource {
2198 resource: ResourceContent,
2200 #[serde(skip_serializing_if = "Option::is_none")]
2202 annotations: Option<ContentAnnotations>,
2203 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2205 meta: Option<Value>,
2206 },
2207 ResourceLink {
2209 uri: String,
2211 name: String,
2213 #[serde(default, skip_serializing_if = "Option::is_none")]
2215 title: Option<String>,
2216 #[serde(skip_serializing_if = "Option::is_none")]
2218 description: Option<String>,
2219 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
2221 mime_type: Option<String>,
2222 #[serde(default, skip_serializing_if = "Option::is_none")]
2224 size: Option<u64>,
2225 #[serde(default, skip_serializing_if = "Option::is_none")]
2227 icons: Option<Vec<ToolIcon>>,
2228 #[serde(skip_serializing_if = "Option::is_none")]
2229 annotations: Option<ContentAnnotations>,
2230 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2232 meta: Option<Value>,
2233 },
2234}
2235
2236#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2238pub struct ContentAnnotations {
2239 #[serde(skip_serializing_if = "Option::is_none")]
2241 pub audience: Option<Vec<ContentRole>>,
2242 #[serde(skip_serializing_if = "Option::is_none")]
2244 pub priority: Option<f64>,
2245 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
2247 pub last_modified: Option<String>,
2248}
2249
2250impl Content {
2251 pub fn text(text: impl Into<String>) -> Self {
2277 Content::Text {
2278 text: text.into(),
2279 annotations: None,
2280 meta: None,
2281 }
2282 }
2283
2284 pub fn as_text(&self) -> Option<&str> {
2297 match self {
2298 Content::Text { text, .. } => Some(text),
2299 _ => None,
2300 }
2301 }
2302}
2303
2304#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2308#[serde(rename_all = "lowercase")]
2309#[non_exhaustive]
2310pub enum ContentRole {
2311 User,
2313 Assistant,
2315}
2316
2317#[derive(Debug, Clone, Serialize, Deserialize)]
2321#[serde(rename_all = "camelCase")]
2322pub struct ResourceContent {
2323 pub uri: String,
2325 #[serde(skip_serializing_if = "Option::is_none")]
2327 pub mime_type: Option<String>,
2328 #[serde(skip_serializing_if = "Option::is_none")]
2330 pub text: Option<String>,
2331 #[serde(skip_serializing_if = "Option::is_none")]
2333 pub blob: Option<String>,
2334 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2336 pub meta: Option<Value>,
2337}
2338
2339#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2344pub struct ListResourcesParams {
2345 #[serde(default, skip_serializing_if = "Option::is_none")]
2346 pub cursor: Option<String>,
2347 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2349 pub meta: Option<RequestMeta>,
2350}
2351
2352#[derive(Debug, Clone, Serialize, Deserialize)]
2353#[serde(rename_all = "camelCase")]
2354pub struct ListResourcesResult {
2355 pub resources: Vec<ResourceDefinition>,
2356 #[serde(default, skip_serializing_if = "Option::is_none")]
2357 pub next_cursor: Option<String>,
2358 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2360 pub meta: Option<Value>,
2361}
2362
2363#[derive(Debug, Clone, Serialize, Deserialize)]
2364#[serde(rename_all = "camelCase")]
2365pub struct ResourceDefinition {
2366 pub uri: String,
2367 pub name: String,
2368 #[serde(skip_serializing_if = "Option::is_none")]
2370 pub title: Option<String>,
2371 #[serde(skip_serializing_if = "Option::is_none")]
2372 pub description: Option<String>,
2373 #[serde(skip_serializing_if = "Option::is_none")]
2374 pub mime_type: Option<String>,
2375 #[serde(skip_serializing_if = "Option::is_none")]
2377 pub icons: Option<Vec<ToolIcon>>,
2378 #[serde(skip_serializing_if = "Option::is_none")]
2380 pub size: Option<u64>,
2381 #[serde(skip_serializing_if = "Option::is_none")]
2383 pub annotations: Option<ContentAnnotations>,
2384 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2386 pub meta: Option<Value>,
2387}
2388
2389#[derive(Debug, Clone, Serialize, Deserialize)]
2390pub struct ReadResourceParams {
2391 pub uri: String,
2392 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2394 pub meta: Option<RequestMeta>,
2395}
2396
2397#[derive(Debug, Clone, Serialize, Deserialize)]
2398pub struct ReadResourceResult {
2399 pub contents: Vec<ResourceContent>,
2400 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2402 pub meta: Option<Value>,
2403}
2404
2405impl ReadResourceResult {
2406 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
2416 Self {
2417 contents: vec![ResourceContent {
2418 uri: uri.into(),
2419 mime_type: Some("text/plain".to_string()),
2420 text: Some(content.into()),
2421 blob: None,
2422 meta: None,
2423 }],
2424 meta: None,
2425 }
2426 }
2427
2428 pub fn text_with_mime(
2442 uri: impl Into<String>,
2443 content: impl Into<String>,
2444 mime_type: impl Into<String>,
2445 ) -> Self {
2446 Self {
2447 contents: vec![ResourceContent {
2448 uri: uri.into(),
2449 mime_type: Some(mime_type.into()),
2450 text: Some(content.into()),
2451 blob: None,
2452 meta: None,
2453 }],
2454 meta: None,
2455 }
2456 }
2457
2458 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
2472 let json_string =
2473 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
2474 Self {
2475 contents: vec![ResourceContent {
2476 uri: uri.into(),
2477 mime_type: Some("application/json".to_string()),
2478 text: Some(json_string),
2479 blob: None,
2480 meta: None,
2481 }],
2482 meta: None,
2483 }
2484 }
2485
2486 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
2497 use base64::Engine;
2498 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2499 Self {
2500 contents: vec![ResourceContent {
2501 uri: uri.into(),
2502 mime_type: Some("application/octet-stream".to_string()),
2503 text: None,
2504 blob: Some(encoded),
2505 meta: None,
2506 }],
2507 meta: None,
2508 }
2509 }
2510
2511 pub fn blob_with_mime(
2522 uri: impl Into<String>,
2523 bytes: &[u8],
2524 mime_type: impl Into<String>,
2525 ) -> Self {
2526 use base64::Engine;
2527 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2528 Self {
2529 contents: vec![ResourceContent {
2530 uri: uri.into(),
2531 mime_type: Some(mime_type.into()),
2532 text: None,
2533 blob: Some(encoded),
2534 meta: None,
2535 }],
2536 meta: None,
2537 }
2538 }
2539
2540 pub fn first_text(&self) -> Option<&str> {
2553 self.contents.first().and_then(|c| c.text.as_deref())
2554 }
2555
2556 pub fn first_uri(&self) -> Option<&str> {
2569 self.contents.first().map(|c| c.uri.as_str())
2570 }
2571
2572 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2587 self.first_text().map(serde_json::from_str)
2588 }
2589
2590 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2609 self.first_text().map(serde_json::from_str)
2610 }
2611}
2612
2613#[derive(Debug, Clone, Deserialize)]
2614pub struct SubscribeResourceParams {
2615 pub uri: String,
2616 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2618 pub meta: Option<RequestMeta>,
2619}
2620
2621#[derive(Debug, Clone, Deserialize)]
2622pub struct UnsubscribeResourceParams {
2623 pub uri: String,
2624 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2626 pub meta: Option<RequestMeta>,
2627}
2628
2629#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2631pub struct ListResourceTemplatesParams {
2632 #[serde(default)]
2634 pub cursor: Option<String>,
2635 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2637 pub meta: Option<RequestMeta>,
2638}
2639
2640#[derive(Debug, Clone, Serialize, Deserialize)]
2642#[serde(rename_all = "camelCase")]
2643pub struct ListResourceTemplatesResult {
2644 pub resource_templates: Vec<ResourceTemplateDefinition>,
2646 #[serde(skip_serializing_if = "Option::is_none")]
2648 pub next_cursor: Option<String>,
2649 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2651 pub meta: Option<Value>,
2652}
2653
2654#[derive(Debug, Clone, Serialize, Deserialize)]
2670#[serde(rename_all = "camelCase")]
2671pub struct ResourceTemplateDefinition {
2672 pub uri_template: String,
2674 pub name: String,
2676 #[serde(skip_serializing_if = "Option::is_none")]
2678 pub title: Option<String>,
2679 #[serde(skip_serializing_if = "Option::is_none")]
2681 pub description: Option<String>,
2682 #[serde(skip_serializing_if = "Option::is_none")]
2684 pub mime_type: Option<String>,
2685 #[serde(skip_serializing_if = "Option::is_none")]
2687 pub icons: Option<Vec<ToolIcon>>,
2688 #[serde(skip_serializing_if = "Option::is_none")]
2690 pub annotations: Option<ContentAnnotations>,
2691 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2693 pub arguments: Vec<PromptArgument>,
2694 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2696 pub meta: Option<Value>,
2697}
2698
2699#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2704pub struct ListPromptsParams {
2705 #[serde(default, skip_serializing_if = "Option::is_none")]
2706 pub cursor: Option<String>,
2707 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2709 pub meta: Option<RequestMeta>,
2710}
2711
2712#[derive(Debug, Clone, Serialize, Deserialize)]
2713#[serde(rename_all = "camelCase")]
2714pub struct ListPromptsResult {
2715 pub prompts: Vec<PromptDefinition>,
2716 #[serde(default, skip_serializing_if = "Option::is_none")]
2717 pub next_cursor: Option<String>,
2718 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2720 pub meta: Option<Value>,
2721}
2722
2723#[derive(Debug, Clone, Serialize, Deserialize)]
2724pub struct PromptDefinition {
2725 pub name: String,
2726 #[serde(skip_serializing_if = "Option::is_none")]
2728 pub title: Option<String>,
2729 #[serde(skip_serializing_if = "Option::is_none")]
2730 pub description: Option<String>,
2731 #[serde(skip_serializing_if = "Option::is_none")]
2733 pub icons: Option<Vec<ToolIcon>>,
2734 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2735 pub arguments: Vec<PromptArgument>,
2736 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2738 pub meta: Option<Value>,
2739}
2740
2741#[derive(Debug, Clone, Serialize, Deserialize)]
2742pub struct PromptArgument {
2743 pub name: String,
2744 #[serde(skip_serializing_if = "Option::is_none")]
2745 pub description: Option<String>,
2746 #[serde(default)]
2747 pub required: bool,
2748}
2749
2750#[derive(Debug, Clone, Serialize, Deserialize)]
2751pub struct GetPromptParams {
2752 pub name: String,
2753 #[serde(default)]
2754 pub arguments: std::collections::HashMap<String, String>,
2755 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2757 pub meta: Option<RequestMeta>,
2758}
2759
2760#[derive(Debug, Clone, Serialize, Deserialize)]
2761pub struct GetPromptResult {
2826 #[serde(default, skip_serializing_if = "Option::is_none")]
2827 pub description: Option<String>,
2828 pub messages: Vec<PromptMessage>,
2829 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2831 pub meta: Option<Value>,
2832}
2833
2834impl GetPromptResult {
2835 pub fn user_message(text: impl Into<String>) -> Self {
2845 Self {
2846 description: None,
2847 messages: vec![PromptMessage {
2848 role: PromptRole::User,
2849 content: Content::Text {
2850 text: text.into(),
2851 annotations: None,
2852 meta: None,
2853 },
2854 meta: None,
2855 }],
2856 meta: None,
2857 }
2858 }
2859
2860 pub fn user_message_with_description(
2873 text: impl Into<String>,
2874 description: impl Into<String>,
2875 ) -> Self {
2876 Self {
2877 description: Some(description.into()),
2878 messages: vec![PromptMessage {
2879 role: PromptRole::User,
2880 content: Content::Text {
2881 text: text.into(),
2882 annotations: None,
2883 meta: None,
2884 },
2885 meta: None,
2886 }],
2887 meta: None,
2888 }
2889 }
2890
2891 pub fn assistant_message(text: impl Into<String>) -> Self {
2901 Self {
2902 description: None,
2903 messages: vec![PromptMessage {
2904 role: PromptRole::Assistant,
2905 content: Content::Text {
2906 text: text.into(),
2907 annotations: None,
2908 meta: None,
2909 },
2910 meta: None,
2911 }],
2912 meta: None,
2913 }
2914 }
2915
2916 pub fn builder() -> GetPromptResultBuilder {
2931 GetPromptResultBuilder::new()
2932 }
2933
2934 pub fn first_message_text(&self) -> Option<&str> {
2948 self.messages.first().and_then(|m| m.content.as_text())
2949 }
2950
2951 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2966 self.first_message_text().map(serde_json::from_str)
2967 }
2968
2969 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2988 self.first_message_text().map(serde_json::from_str)
2989 }
2990}
2991
2992#[derive(Debug, Clone, Default)]
2994pub struct GetPromptResultBuilder {
2995 description: Option<String>,
2996 messages: Vec<PromptMessage>,
2997}
2998
2999impl GetPromptResultBuilder {
3000 pub fn new() -> Self {
3002 Self::default()
3003 }
3004
3005 pub fn description(mut self, description: impl Into<String>) -> Self {
3007 self.description = Some(description.into());
3008 self
3009 }
3010
3011 pub fn user(mut self, text: impl Into<String>) -> Self {
3013 self.messages.push(PromptMessage {
3014 role: PromptRole::User,
3015 content: Content::Text {
3016 text: text.into(),
3017 annotations: None,
3018 meta: None,
3019 },
3020 meta: None,
3021 });
3022 self
3023 }
3024
3025 pub fn assistant(mut self, text: impl Into<String>) -> Self {
3027 self.messages.push(PromptMessage {
3028 role: PromptRole::Assistant,
3029 content: Content::Text {
3030 text: text.into(),
3031 annotations: None,
3032 meta: None,
3033 },
3034 meta: None,
3035 });
3036 self
3037 }
3038
3039 pub fn build(self) -> GetPromptResult {
3041 GetPromptResult {
3042 description: self.description,
3043 messages: self.messages,
3044 meta: None,
3045 }
3046 }
3047}
3048
3049#[derive(Debug, Clone, Serialize, Deserialize)]
3050pub struct PromptMessage {
3051 pub role: PromptRole,
3052 pub content: Content,
3053 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3055 pub meta: Option<Value>,
3056}
3057
3058#[derive(Debug, Clone, Serialize, Deserialize)]
3059#[serde(rename_all = "lowercase")]
3060#[non_exhaustive]
3061pub enum PromptRole {
3062 User,
3063 Assistant,
3064}
3065
3066#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
3072#[serde(rename_all = "camelCase")]
3073#[non_exhaustive]
3074pub enum TaskSupportMode {
3075 Required,
3077 Optional,
3079 #[default]
3081 Forbidden,
3082}
3083
3084#[derive(Debug, Clone, Serialize, Deserialize)]
3086#[serde(rename_all = "camelCase")]
3087pub struct ToolExecution {
3088 #[serde(default, skip_serializing_if = "Option::is_none")]
3090 pub task_support: Option<TaskSupportMode>,
3091}
3092
3093#[derive(Debug, Clone, Serialize, Deserialize)]
3095#[serde(rename_all = "camelCase")]
3096pub struct TaskRequestParams {
3097 #[serde(default, skip_serializing_if = "Option::is_none")]
3099 pub ttl: Option<u64>,
3100}
3101
3102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3104#[serde(rename_all = "snake_case")]
3105#[non_exhaustive]
3106pub enum TaskStatus {
3107 Working,
3109 InputRequired,
3111 Completed,
3113 Failed,
3115 Cancelled,
3117}
3118
3119impl std::fmt::Display for TaskStatus {
3120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3121 match self {
3122 TaskStatus::Working => write!(f, "working"),
3123 TaskStatus::InputRequired => write!(f, "input_required"),
3124 TaskStatus::Completed => write!(f, "completed"),
3125 TaskStatus::Failed => write!(f, "failed"),
3126 TaskStatus::Cancelled => write!(f, "cancelled"),
3127 }
3128 }
3129}
3130
3131impl TaskStatus {
3132 pub fn is_terminal(&self) -> bool {
3134 matches!(
3135 self,
3136 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
3137 )
3138 }
3139}
3140
3141#[derive(Debug, Clone, Serialize, Deserialize)]
3143#[serde(rename_all = "camelCase")]
3144pub struct TaskObject {
3145 pub task_id: String,
3147 pub status: TaskStatus,
3149 #[serde(skip_serializing_if = "Option::is_none")]
3151 pub status_message: Option<String>,
3152 pub created_at: String,
3154 pub last_updated_at: String,
3156 pub ttl: Option<u64>,
3158 #[serde(skip_serializing_if = "Option::is_none")]
3160 pub poll_interval: Option<u64>,
3161 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3163 pub meta: Option<Value>,
3164}
3165
3166#[deprecated(note = "Use TaskObject instead")]
3168pub type TaskInfo = TaskObject;
3169
3170#[derive(Debug, Clone, Serialize, Deserialize)]
3172#[serde(rename_all = "camelCase")]
3173pub struct CreateTaskResult {
3174 pub task: TaskObject,
3176 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3178 pub meta: Option<Value>,
3179}
3180
3181#[derive(Debug, Clone, Default, Deserialize)]
3183#[serde(rename_all = "camelCase")]
3184pub struct ListTasksParams {
3185 #[serde(default)]
3187 pub status: Option<TaskStatus>,
3188 #[serde(default)]
3190 pub cursor: Option<String>,
3191 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3193 pub meta: Option<RequestMeta>,
3194}
3195
3196#[derive(Debug, Clone, Serialize)]
3198#[serde(rename_all = "camelCase")]
3199pub struct ListTasksResult {
3200 pub tasks: Vec<TaskObject>,
3202 #[serde(skip_serializing_if = "Option::is_none")]
3204 pub next_cursor: Option<String>,
3205}
3206
3207#[derive(Debug, Clone, Deserialize)]
3209#[serde(rename_all = "camelCase")]
3210pub struct GetTaskInfoParams {
3211 pub task_id: String,
3213 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3215 pub meta: Option<RequestMeta>,
3216}
3217
3218#[derive(Debug, Clone, Deserialize)]
3220#[serde(rename_all = "camelCase")]
3221pub struct GetTaskResultParams {
3222 pub task_id: String,
3224 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3226 pub meta: Option<RequestMeta>,
3227}
3228
3229#[derive(Debug, Clone, Deserialize)]
3231#[serde(rename_all = "camelCase")]
3232pub struct CancelTaskParams {
3233 pub task_id: String,
3235 #[serde(default)]
3237 pub reason: Option<String>,
3238 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3240 pub meta: Option<RequestMeta>,
3241}
3242
3243#[derive(Debug, Clone, Serialize, Deserialize)]
3248#[serde(rename_all = "camelCase")]
3249pub struct TaskStatusParams {
3250 pub task_id: String,
3252 pub status: TaskStatus,
3254 #[serde(skip_serializing_if = "Option::is_none")]
3256 pub status_message: Option<String>,
3257 pub created_at: String,
3259 pub last_updated_at: String,
3261 pub ttl: Option<u64>,
3263 #[serde(skip_serializing_if = "Option::is_none")]
3265 pub poll_interval: Option<u64>,
3266 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3268 pub meta: Option<Value>,
3269}
3270
3271pub type TaskStatusChangedParams = TaskStatusParams;
3273
3274#[derive(Debug, Clone, Serialize, Deserialize)]
3280#[serde(rename_all = "camelCase")]
3281pub struct ElicitFormParams {
3282 #[serde(default, skip_serializing_if = "Option::is_none")]
3284 pub mode: Option<ElicitMode>,
3285 pub message: String,
3287 pub requested_schema: ElicitFormSchema,
3289 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3291 pub meta: Option<RequestMeta>,
3292}
3293
3294#[derive(Debug, Clone, Serialize, Deserialize)]
3315#[serde(rename_all = "camelCase")]
3316pub struct ElicitUrlParams {
3317 #[serde(default, skip_serializing_if = "Option::is_none")]
3319 pub mode: Option<ElicitMode>,
3320 pub elicitation_id: String,
3322 pub message: String,
3324 pub url: String,
3326 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3328 pub meta: Option<RequestMeta>,
3329}
3330
3331#[derive(Debug, Clone, Serialize, Deserialize)]
3333#[serde(untagged)]
3334#[non_exhaustive]
3335pub enum ElicitRequestParams {
3336 Form(ElicitFormParams),
3337 Url(ElicitUrlParams),
3338}
3339
3340#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3342#[serde(rename_all = "lowercase")]
3343#[non_exhaustive]
3344pub enum ElicitMode {
3345 Form,
3347 Url,
3349}
3350
3351#[derive(Debug, Clone, Serialize, Deserialize)]
3391pub struct ElicitFormSchema {
3392 #[serde(rename = "type")]
3394 pub schema_type: String,
3395 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
3397 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3399 pub required: Vec<String>,
3400}
3401
3402impl ElicitFormSchema {
3403 pub fn new() -> Self {
3405 Self {
3406 schema_type: "object".to_string(),
3407 properties: std::collections::HashMap::new(),
3408 required: Vec::new(),
3409 }
3410 }
3411
3412 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3414 self.properties.insert(
3415 name.to_string(),
3416 PrimitiveSchemaDefinition::String(StringSchema {
3417 schema_type: "string".to_string(),
3418 title: None,
3419 description: description.map(|s| s.to_string()),
3420 format: None,
3421 pattern: None,
3422 min_length: None,
3423 max_length: None,
3424 default: None,
3425 }),
3426 );
3427 if required {
3428 self.required.push(name.to_string());
3429 }
3430 self
3431 }
3432
3433 pub fn string_field_with_default(
3435 mut self,
3436 name: &str,
3437 description: Option<&str>,
3438 required: bool,
3439 default: &str,
3440 ) -> Self {
3441 self.properties.insert(
3442 name.to_string(),
3443 PrimitiveSchemaDefinition::String(StringSchema {
3444 schema_type: "string".to_string(),
3445 title: None,
3446 description: description.map(|s| s.to_string()),
3447 format: None,
3448 pattern: None,
3449 min_length: None,
3450 max_length: None,
3451 default: Some(default.to_string()),
3452 }),
3453 );
3454 if required {
3455 self.required.push(name.to_string());
3456 }
3457 self
3458 }
3459
3460 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3462 self.properties.insert(
3463 name.to_string(),
3464 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3465 schema_type: "integer".to_string(),
3466 title: None,
3467 description: description.map(|s| s.to_string()),
3468 minimum: None,
3469 maximum: None,
3470 default: None,
3471 }),
3472 );
3473 if required {
3474 self.required.push(name.to_string());
3475 }
3476 self
3477 }
3478
3479 pub fn integer_field_with_default(
3481 mut self,
3482 name: &str,
3483 description: Option<&str>,
3484 required: bool,
3485 default: i64,
3486 ) -> Self {
3487 self.properties.insert(
3488 name.to_string(),
3489 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3490 schema_type: "integer".to_string(),
3491 title: None,
3492 description: description.map(|s| s.to_string()),
3493 minimum: None,
3494 maximum: None,
3495 default: Some(default),
3496 }),
3497 );
3498 if required {
3499 self.required.push(name.to_string());
3500 }
3501 self
3502 }
3503
3504 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3506 self.properties.insert(
3507 name.to_string(),
3508 PrimitiveSchemaDefinition::Number(NumberSchema {
3509 schema_type: "number".to_string(),
3510 title: None,
3511 description: description.map(|s| s.to_string()),
3512 minimum: None,
3513 maximum: None,
3514 default: None,
3515 }),
3516 );
3517 if required {
3518 self.required.push(name.to_string());
3519 }
3520 self
3521 }
3522
3523 pub fn number_field_with_default(
3525 mut self,
3526 name: &str,
3527 description: Option<&str>,
3528 required: bool,
3529 default: f64,
3530 ) -> Self {
3531 self.properties.insert(
3532 name.to_string(),
3533 PrimitiveSchemaDefinition::Number(NumberSchema {
3534 schema_type: "number".to_string(),
3535 title: None,
3536 description: description.map(|s| s.to_string()),
3537 minimum: None,
3538 maximum: None,
3539 default: Some(default),
3540 }),
3541 );
3542 if required {
3543 self.required.push(name.to_string());
3544 }
3545 self
3546 }
3547
3548 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3550 self.properties.insert(
3551 name.to_string(),
3552 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3553 schema_type: "boolean".to_string(),
3554 title: None,
3555 description: description.map(|s| s.to_string()),
3556 default: None,
3557 }),
3558 );
3559 if required {
3560 self.required.push(name.to_string());
3561 }
3562 self
3563 }
3564
3565 pub fn boolean_field_with_default(
3567 mut self,
3568 name: &str,
3569 description: Option<&str>,
3570 required: bool,
3571 default: bool,
3572 ) -> Self {
3573 self.properties.insert(
3574 name.to_string(),
3575 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3576 schema_type: "boolean".to_string(),
3577 title: None,
3578 description: description.map(|s| s.to_string()),
3579 default: Some(default),
3580 }),
3581 );
3582 if required {
3583 self.required.push(name.to_string());
3584 }
3585 self
3586 }
3587
3588 pub fn enum_field(
3590 mut self,
3591 name: &str,
3592 description: Option<&str>,
3593 options: Vec<String>,
3594 required: bool,
3595 ) -> Self {
3596 self.properties.insert(
3597 name.to_string(),
3598 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3599 schema_type: "string".to_string(),
3600 title: None,
3601 description: description.map(|s| s.to_string()),
3602 enum_values: options,
3603 default: None,
3604 }),
3605 );
3606 if required {
3607 self.required.push(name.to_string());
3608 }
3609 self
3610 }
3611
3612 pub fn enum_field_with_default(
3614 mut self,
3615 name: &str,
3616 description: Option<&str>,
3617 required: bool,
3618 options: &[&str],
3619 default: &str,
3620 ) -> Self {
3621 self.properties.insert(
3622 name.to_string(),
3623 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3624 schema_type: "string".to_string(),
3625 title: None,
3626 description: description.map(|s| s.to_string()),
3627 enum_values: options.iter().map(|s| s.to_string()).collect(),
3628 default: Some(default.to_string()),
3629 }),
3630 );
3631 if required {
3632 self.required.push(name.to_string());
3633 }
3634 self
3635 }
3636
3637 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
3641 self.properties
3642 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
3643 if required {
3644 self.required.push(name.to_string());
3645 }
3646 self
3647 }
3648}
3649
3650impl Default for ElicitFormSchema {
3651 fn default() -> Self {
3652 Self::new()
3653 }
3654}
3655
3656#[derive(Debug, Clone, Serialize, Deserialize)]
3658#[serde(untagged)]
3659#[non_exhaustive]
3660pub enum PrimitiveSchemaDefinition {
3661 String(StringSchema),
3663 Integer(IntegerSchema),
3665 Number(NumberSchema),
3667 Boolean(BooleanSchema),
3669 SingleSelectEnum(SingleSelectEnumSchema),
3671 MultiSelectEnum(MultiSelectEnumSchema),
3673 Raw(serde_json::Value),
3675}
3676
3677#[derive(Debug, Clone, Serialize, Deserialize)]
3679#[serde(rename_all = "camelCase")]
3680pub struct StringSchema {
3681 #[serde(rename = "type")]
3682 pub schema_type: String,
3683 #[serde(skip_serializing_if = "Option::is_none")]
3685 pub title: Option<String>,
3686 #[serde(skip_serializing_if = "Option::is_none")]
3687 pub description: Option<String>,
3688 #[serde(skip_serializing_if = "Option::is_none")]
3689 pub format: Option<String>,
3690 #[serde(skip_serializing_if = "Option::is_none")]
3692 pub pattern: Option<String>,
3693 #[serde(skip_serializing_if = "Option::is_none")]
3694 pub min_length: Option<u64>,
3695 #[serde(skip_serializing_if = "Option::is_none")]
3696 pub max_length: Option<u64>,
3697 #[serde(skip_serializing_if = "Option::is_none")]
3699 pub default: Option<String>,
3700}
3701
3702#[derive(Debug, Clone, Serialize, Deserialize)]
3704#[serde(rename_all = "camelCase")]
3705pub struct IntegerSchema {
3706 #[serde(rename = "type")]
3707 pub schema_type: String,
3708 #[serde(skip_serializing_if = "Option::is_none")]
3710 pub title: Option<String>,
3711 #[serde(skip_serializing_if = "Option::is_none")]
3712 pub description: Option<String>,
3713 #[serde(skip_serializing_if = "Option::is_none")]
3714 pub minimum: Option<i64>,
3715 #[serde(skip_serializing_if = "Option::is_none")]
3716 pub maximum: Option<i64>,
3717 #[serde(skip_serializing_if = "Option::is_none")]
3719 pub default: Option<i64>,
3720}
3721
3722#[derive(Debug, Clone, Serialize, Deserialize)]
3724#[serde(rename_all = "camelCase")]
3725pub struct NumberSchema {
3726 #[serde(rename = "type")]
3727 pub schema_type: String,
3728 #[serde(skip_serializing_if = "Option::is_none")]
3730 pub title: Option<String>,
3731 #[serde(skip_serializing_if = "Option::is_none")]
3732 pub description: Option<String>,
3733 #[serde(skip_serializing_if = "Option::is_none")]
3734 pub minimum: Option<f64>,
3735 #[serde(skip_serializing_if = "Option::is_none")]
3736 pub maximum: Option<f64>,
3737 #[serde(skip_serializing_if = "Option::is_none")]
3739 pub default: Option<f64>,
3740}
3741
3742#[derive(Debug, Clone, Serialize, Deserialize)]
3744#[serde(rename_all = "camelCase")]
3745pub struct BooleanSchema {
3746 #[serde(rename = "type")]
3747 pub schema_type: String,
3748 #[serde(skip_serializing_if = "Option::is_none")]
3750 pub title: Option<String>,
3751 #[serde(skip_serializing_if = "Option::is_none")]
3752 pub description: Option<String>,
3753 #[serde(skip_serializing_if = "Option::is_none")]
3755 pub default: Option<bool>,
3756}
3757
3758#[derive(Debug, Clone, Serialize, Deserialize)]
3760#[serde(rename_all = "camelCase")]
3761pub struct SingleSelectEnumSchema {
3762 #[serde(rename = "type")]
3763 pub schema_type: String,
3764 #[serde(skip_serializing_if = "Option::is_none")]
3766 pub title: Option<String>,
3767 #[serde(skip_serializing_if = "Option::is_none")]
3768 pub description: Option<String>,
3769 #[serde(rename = "enum")]
3770 pub enum_values: Vec<String>,
3771 #[serde(skip_serializing_if = "Option::is_none")]
3773 pub default: Option<String>,
3774}
3775
3776#[derive(Debug, Clone, Serialize, Deserialize)]
3778#[serde(rename_all = "camelCase")]
3779pub struct MultiSelectEnumSchema {
3780 #[serde(rename = "type")]
3781 pub schema_type: String,
3782 #[serde(skip_serializing_if = "Option::is_none")]
3784 pub title: Option<String>,
3785 #[serde(skip_serializing_if = "Option::is_none")]
3786 pub description: Option<String>,
3787 pub items: MultiSelectEnumItems,
3788 #[serde(skip_serializing_if = "Option::is_none")]
3789 pub unique_items: Option<bool>,
3790 #[serde(skip_serializing_if = "Option::is_none")]
3792 pub default: Option<Vec<String>>,
3793}
3794
3795#[derive(Debug, Clone, Serialize, Deserialize)]
3797pub struct MultiSelectEnumItems {
3798 #[serde(rename = "type")]
3799 pub schema_type: String,
3800 #[serde(rename = "enum")]
3801 pub enum_values: Vec<String>,
3802}
3803
3804#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3806#[serde(rename_all = "lowercase")]
3807#[non_exhaustive]
3808pub enum ElicitAction {
3809 Accept,
3811 Decline,
3813 Cancel,
3815}
3816
3817#[derive(Debug, Clone, Serialize, Deserialize)]
3819pub struct ElicitResult {
3820 pub action: ElicitAction,
3822 #[serde(default, skip_serializing_if = "Option::is_none")]
3824 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
3825 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3827 pub meta: Option<Value>,
3828}
3829
3830impl ElicitResult {
3831 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
3833 Self {
3834 action: ElicitAction::Accept,
3835 content: Some(content),
3836 meta: None,
3837 }
3838 }
3839
3840 pub fn decline() -> Self {
3842 Self {
3843 action: ElicitAction::Decline,
3844 content: None,
3845 meta: None,
3846 }
3847 }
3848
3849 pub fn cancel() -> Self {
3851 Self {
3852 action: ElicitAction::Cancel,
3853 content: None,
3854 meta: None,
3855 }
3856 }
3857}
3858
3859#[derive(Debug, Clone, Serialize, Deserialize)]
3861#[serde(untagged)]
3862#[non_exhaustive]
3863pub enum ElicitFieldValue {
3864 String(String),
3865 Number(f64),
3866 Integer(i64),
3867 Boolean(bool),
3868 StringArray(Vec<String>),
3869}
3870
3871#[derive(Debug, Clone, Serialize, Deserialize)]
3873#[serde(rename_all = "camelCase")]
3874pub struct ElicitationCompleteParams {
3875 pub elicitation_id: String,
3877 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3879 pub meta: Option<Value>,
3880}
3881
3882#[derive(Debug, Clone, Default, Serialize)]
3887pub struct EmptyResult {}
3888
3889impl McpRequest {
3894 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
3896 let params = req
3897 .params
3898 .clone()
3899 .unwrap_or(Value::Object(Default::default()));
3900
3901 match req.method.as_str() {
3902 "initialize" => {
3903 let p: InitializeParams = serde_json::from_value(params)?;
3904 Ok(McpRequest::Initialize(p))
3905 }
3906 "tools/list" => {
3907 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
3908 Ok(McpRequest::ListTools(p))
3909 }
3910 "tools/call" => {
3911 let p: CallToolParams = serde_json::from_value(params)?;
3912 Ok(McpRequest::CallTool(p))
3913 }
3914 "resources/list" => {
3915 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
3916 Ok(McpRequest::ListResources(p))
3917 }
3918 "resources/templates/list" => {
3919 let p: ListResourceTemplatesParams =
3920 serde_json::from_value(params).unwrap_or_default();
3921 Ok(McpRequest::ListResourceTemplates(p))
3922 }
3923 "resources/read" => {
3924 let p: ReadResourceParams = serde_json::from_value(params)?;
3925 Ok(McpRequest::ReadResource(p))
3926 }
3927 "resources/subscribe" => {
3928 let p: SubscribeResourceParams = serde_json::from_value(params)?;
3929 Ok(McpRequest::SubscribeResource(p))
3930 }
3931 "resources/unsubscribe" => {
3932 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
3933 Ok(McpRequest::UnsubscribeResource(p))
3934 }
3935 "prompts/list" => {
3936 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
3937 Ok(McpRequest::ListPrompts(p))
3938 }
3939 "prompts/get" => {
3940 let p: GetPromptParams = serde_json::from_value(params)?;
3941 Ok(McpRequest::GetPrompt(p))
3942 }
3943 "tasks/list" => {
3944 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
3945 Ok(McpRequest::ListTasks(p))
3946 }
3947 "tasks/get" => {
3948 let p: GetTaskInfoParams = serde_json::from_value(params)?;
3949 Ok(McpRequest::GetTaskInfo(p))
3950 }
3951 "tasks/result" => {
3952 let p: GetTaskResultParams = serde_json::from_value(params)?;
3953 Ok(McpRequest::GetTaskResult(p))
3954 }
3955 "tasks/cancel" => {
3956 let p: CancelTaskParams = serde_json::from_value(params)?;
3957 Ok(McpRequest::CancelTask(p))
3958 }
3959 "ping" => Ok(McpRequest::Ping),
3960 "logging/setLevel" => {
3961 let p: SetLogLevelParams = serde_json::from_value(params)?;
3962 Ok(McpRequest::SetLoggingLevel(p))
3963 }
3964 "completion/complete" => {
3965 let p: CompleteParams = serde_json::from_value(params)?;
3966 Ok(McpRequest::Complete(p))
3967 }
3968 method => Ok(McpRequest::Unknown {
3969 method: method.to_string(),
3970 params: req.params.clone(),
3971 }),
3972 }
3973 }
3974}
3975
3976impl McpNotification {
3977 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
3979 let params = notif
3980 .params
3981 .clone()
3982 .unwrap_or(Value::Object(Default::default()));
3983
3984 match notif.method.as_str() {
3985 notifications::INITIALIZED => Ok(McpNotification::Initialized),
3986 notifications::CANCELLED => {
3987 let p: CancelledParams = serde_json::from_value(params)?;
3988 Ok(McpNotification::Cancelled(p))
3989 }
3990 notifications::PROGRESS => {
3991 let p: ProgressParams = serde_json::from_value(params)?;
3992 Ok(McpNotification::Progress(p))
3993 }
3994 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3995 method => Ok(McpNotification::Unknown {
3996 method: method.to_string(),
3997 params: notif.params.clone(),
3998 }),
3999 }
4000 }
4001}
4002
4003#[cfg(test)]
4004mod tests {
4005 use super::*;
4006
4007 #[test]
4008 fn test_content_text_constructor() {
4009 let content = Content::text("hello world");
4010 assert_eq!(content.as_text(), Some("hello world"));
4011
4012 match &content {
4014 Content::Text {
4015 text, annotations, ..
4016 } => {
4017 assert_eq!(text, "hello world");
4018 assert!(annotations.is_none());
4019 }
4020 _ => panic!("expected Content::Text"),
4021 }
4022
4023 let content = Content::text(String::from("owned"));
4025 assert_eq!(content.as_text(), Some("owned"));
4026 }
4027
4028 #[test]
4029 fn test_elicit_form_schema_builder() {
4030 let schema = ElicitFormSchema::new()
4031 .string_field("name", Some("Your name"), true)
4032 .number_field("age", Some("Your age"), false)
4033 .boolean_field("agree", Some("Do you agree?"), true)
4034 .enum_field(
4035 "color",
4036 Some("Favorite color"),
4037 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
4038 false,
4039 );
4040
4041 assert_eq!(schema.schema_type, "object");
4042 assert_eq!(schema.properties.len(), 4);
4043 assert_eq!(schema.required.len(), 2);
4044 assert!(schema.required.contains(&"name".to_string()));
4045 assert!(schema.required.contains(&"agree".to_string()));
4046 }
4047
4048 #[test]
4049 fn test_elicit_form_schema_serialization() {
4050 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
4051
4052 let json = serde_json::to_value(&schema).unwrap();
4053 assert_eq!(json["type"], "object");
4054 assert!(json["properties"]["username"]["type"] == "string");
4055 assert!(
4056 json["required"]
4057 .as_array()
4058 .unwrap()
4059 .contains(&serde_json::json!("username"))
4060 );
4061 }
4062
4063 #[test]
4064 fn test_elicit_result_accept() {
4065 let mut content = std::collections::HashMap::new();
4066 content.insert(
4067 "name".to_string(),
4068 ElicitFieldValue::String("Alice".to_string()),
4069 );
4070 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
4071
4072 let result = ElicitResult::accept(content);
4073 assert_eq!(result.action, ElicitAction::Accept);
4074 assert!(result.content.is_some());
4075 }
4076
4077 #[test]
4078 fn test_elicit_result_decline() {
4079 let result = ElicitResult::decline();
4080 assert_eq!(result.action, ElicitAction::Decline);
4081 assert!(result.content.is_none());
4082 }
4083
4084 #[test]
4085 fn test_elicit_result_cancel() {
4086 let result = ElicitResult::cancel();
4087 assert_eq!(result.action, ElicitAction::Cancel);
4088 assert!(result.content.is_none());
4089 }
4090
4091 #[test]
4092 fn test_elicit_mode_serialization() {
4093 assert_eq!(
4094 serde_json::to_string(&ElicitMode::Form).unwrap(),
4095 "\"form\""
4096 );
4097 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
4098 }
4099
4100 #[test]
4101 fn test_elicit_action_serialization() {
4102 assert_eq!(
4103 serde_json::to_string(&ElicitAction::Accept).unwrap(),
4104 "\"accept\""
4105 );
4106 assert_eq!(
4107 serde_json::to_string(&ElicitAction::Decline).unwrap(),
4108 "\"decline\""
4109 );
4110 assert_eq!(
4111 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
4112 "\"cancel\""
4113 );
4114 }
4115
4116 #[test]
4117 fn test_elicitation_capability() {
4118 let cap = ElicitationCapability {
4119 form: Some(ElicitationFormCapability {}),
4120 url: None,
4121 };
4122
4123 let json = serde_json::to_value(&cap).unwrap();
4124 assert!(json["form"].is_object());
4125 assert!(json.get("url").is_none());
4126 }
4127
4128 #[test]
4129 fn test_client_capabilities_with_elicitation() {
4130 let caps = ClientCapabilities {
4131 roots: None,
4132 sampling: None,
4133 elicitation: Some(ElicitationCapability {
4134 form: Some(ElicitationFormCapability {}),
4135 url: Some(ElicitationUrlCapability {}),
4136 }),
4137 tasks: None,
4138 experimental: None,
4139 extensions: None,
4140 };
4141
4142 let json = serde_json::to_value(&caps).unwrap();
4143 assert!(json["elicitation"]["form"].is_object());
4144 assert!(json["elicitation"]["url"].is_object());
4145 }
4146
4147 #[test]
4148 fn test_elicit_url_params() {
4149 let params = ElicitUrlParams {
4150 mode: Some(ElicitMode::Url),
4151 elicitation_id: "abc123".to_string(),
4152 message: "Please authorize".to_string(),
4153 url: "https://example.com/auth".to_string(),
4154 meta: None,
4155 };
4156
4157 let json = serde_json::to_value(¶ms).unwrap();
4158 assert_eq!(json["mode"], "url");
4159 assert_eq!(json["elicitationId"], "abc123");
4160 assert_eq!(json["message"], "Please authorize");
4161 assert_eq!(json["url"], "https://example.com/auth");
4162 }
4163
4164 #[test]
4165 fn test_elicitation_complete_params() {
4166 let params = ElicitationCompleteParams {
4167 elicitation_id: "xyz789".to_string(),
4168 meta: None,
4169 };
4170
4171 let json = serde_json::to_value(¶ms).unwrap();
4172 assert_eq!(json["elicitationId"], "xyz789");
4173 }
4174
4175 #[test]
4176 fn test_root_new() {
4177 let root = Root::new("file:///home/user/project");
4178 assert_eq!(root.uri, "file:///home/user/project");
4179 assert!(root.name.is_none());
4180 }
4181
4182 #[test]
4183 fn test_root_with_name() {
4184 let root = Root::with_name("file:///home/user/project", "My Project");
4185 assert_eq!(root.uri, "file:///home/user/project");
4186 assert_eq!(root.name.as_deref(), Some("My Project"));
4187 }
4188
4189 #[test]
4190 fn test_root_serialization() {
4191 let root = Root::with_name("file:///workspace", "Workspace");
4192 let json = serde_json::to_value(&root).unwrap();
4193 assert_eq!(json["uri"], "file:///workspace");
4194 assert_eq!(json["name"], "Workspace");
4195 }
4196
4197 #[test]
4198 fn test_root_serialization_without_name() {
4199 let root = Root::new("file:///workspace");
4200 let json = serde_json::to_value(&root).unwrap();
4201 assert_eq!(json["uri"], "file:///workspace");
4202 assert!(json.get("name").is_none());
4203 }
4204
4205 #[test]
4206 fn test_root_deserialization() {
4207 let json = serde_json::json!({
4208 "uri": "file:///home/user",
4209 "name": "Home"
4210 });
4211 let root: Root = serde_json::from_value(json).unwrap();
4212 assert_eq!(root.uri, "file:///home/user");
4213 assert_eq!(root.name.as_deref(), Some("Home"));
4214 }
4215
4216 #[test]
4217 fn test_list_roots_result() {
4218 let result = ListRootsResult {
4219 roots: vec![
4220 Root::new("file:///project1"),
4221 Root::with_name("file:///project2", "Project 2"),
4222 ],
4223 meta: None,
4224 };
4225
4226 let json = serde_json::to_value(&result).unwrap();
4227 let roots = json["roots"].as_array().unwrap();
4228 assert_eq!(roots.len(), 2);
4229 assert_eq!(roots[0]["uri"], "file:///project1");
4230 assert_eq!(roots[1]["name"], "Project 2");
4231 }
4232
4233 #[test]
4234 fn test_roots_capability_serialization() {
4235 let cap = RootsCapability { list_changed: true };
4236 let json = serde_json::to_value(&cap).unwrap();
4237 assert_eq!(json["listChanged"], true);
4238 }
4239
4240 #[test]
4241 fn test_client_capabilities_with_roots() {
4242 let caps = ClientCapabilities {
4243 roots: Some(RootsCapability { list_changed: true }),
4244 sampling: None,
4245 elicitation: None,
4246 tasks: None,
4247 experimental: None,
4248 extensions: None,
4249 };
4250
4251 let json = serde_json::to_value(&caps).unwrap();
4252 assert_eq!(json["roots"]["listChanged"], true);
4253 }
4254
4255 #[test]
4256 fn test_roots_list_changed_notification_parsing() {
4257 let notif = JsonRpcNotification {
4258 jsonrpc: "2.0".to_string(),
4259 method: notifications::ROOTS_LIST_CHANGED.to_string(),
4260 params: None,
4261 };
4262
4263 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
4264 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
4265 }
4266
4267 #[test]
4272 fn test_prompt_reference() {
4273 let ref_ = PromptReference::new("my-prompt");
4274 assert_eq!(ref_.ref_type, "ref/prompt");
4275 assert_eq!(ref_.name, "my-prompt");
4276
4277 let json = serde_json::to_value(&ref_).unwrap();
4278 assert_eq!(json["type"], "ref/prompt");
4279 assert_eq!(json["name"], "my-prompt");
4280 }
4281
4282 #[test]
4283 fn test_resource_reference() {
4284 let ref_ = ResourceReference::new("file:///path/to/file");
4285 assert_eq!(ref_.ref_type, "ref/resource");
4286 assert_eq!(ref_.uri, "file:///path/to/file");
4287
4288 let json = serde_json::to_value(&ref_).unwrap();
4289 assert_eq!(json["type"], "ref/resource");
4290 assert_eq!(json["uri"], "file:///path/to/file");
4291 }
4292
4293 #[test]
4294 fn test_completion_reference_prompt() {
4295 let ref_ = CompletionReference::prompt("test-prompt");
4296 let json = serde_json::to_value(&ref_).unwrap();
4297 assert_eq!(json["type"], "ref/prompt");
4298 assert_eq!(json["name"], "test-prompt");
4299 }
4300
4301 #[test]
4302 fn test_completion_reference_resource() {
4303 let ref_ = CompletionReference::resource("file:///test");
4304 let json = serde_json::to_value(&ref_).unwrap();
4305 assert_eq!(json["type"], "ref/resource");
4306 assert_eq!(json["uri"], "file:///test");
4307 }
4308
4309 #[test]
4310 fn test_completion_argument() {
4311 let arg = CompletionArgument::new("query", "SELECT * FROM");
4312 assert_eq!(arg.name, "query");
4313 assert_eq!(arg.value, "SELECT * FROM");
4314 }
4315
4316 #[test]
4317 fn test_complete_params_serialization() {
4318 let params = CompleteParams {
4319 reference: CompletionReference::prompt("sql-prompt"),
4320 argument: CompletionArgument::new("query", "SEL"),
4321 context: None,
4322 meta: None,
4323 };
4324
4325 let json = serde_json::to_value(¶ms).unwrap();
4326 assert_eq!(json["ref"]["type"], "ref/prompt");
4327 assert_eq!(json["ref"]["name"], "sql-prompt");
4328 assert_eq!(json["argument"]["name"], "query");
4329 assert_eq!(json["argument"]["value"], "SEL");
4330 assert!(json.get("context").is_none()); }
4332
4333 #[test]
4334 fn test_completion_new() {
4335 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
4336 assert_eq!(completion.values.len(), 2);
4337 assert!(completion.total.is_none());
4338 assert!(completion.has_more.is_none());
4339 }
4340
4341 #[test]
4342 fn test_completion_with_pagination() {
4343 let completion =
4344 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
4345 assert_eq!(completion.values.len(), 2);
4346 assert_eq!(completion.total, Some(100));
4347 assert_eq!(completion.has_more, Some(true));
4348 }
4349
4350 #[test]
4351 fn test_complete_result() {
4352 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
4353 let json = serde_json::to_value(&result).unwrap();
4354 assert!(json["completion"]["values"].is_array());
4355 assert_eq!(json["completion"]["values"][0], "option1");
4356 }
4357
4358 #[test]
4363 fn test_model_hint() {
4364 let hint = ModelHint::new("claude-3-opus");
4365 assert_eq!(hint.name, Some("claude-3-opus".to_string()));
4366 }
4367
4368 #[test]
4369 fn test_model_preferences_builder() {
4370 let prefs = ModelPreferences::new()
4371 .speed(0.8)
4372 .intelligence(0.9)
4373 .cost(0.5)
4374 .hint("gpt-4")
4375 .hint("claude-3");
4376
4377 assert_eq!(prefs.speed_priority, Some(0.8));
4378 assert_eq!(prefs.intelligence_priority, Some(0.9));
4379 assert_eq!(prefs.cost_priority, Some(0.5));
4380 assert_eq!(prefs.hints.len(), 2);
4381 }
4382
4383 #[test]
4384 fn test_model_preferences_clamping() {
4385 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
4386
4387 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
4390
4391 #[test]
4392 fn test_include_context_serialization() {
4393 assert_eq!(
4394 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
4395 "\"allServers\""
4396 );
4397 assert_eq!(
4398 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
4399 "\"thisServer\""
4400 );
4401 assert_eq!(
4402 serde_json::to_string(&IncludeContext::None).unwrap(),
4403 "\"none\""
4404 );
4405 }
4406
4407 #[test]
4408 fn test_sampling_message_user() {
4409 let msg = SamplingMessage::user("Hello, how are you?");
4410 assert_eq!(msg.role, ContentRole::User);
4411 assert!(
4412 matches!(msg.content, SamplingContentOrArray::Single(SamplingContent::Text { ref text, .. }) if text == "Hello, how are you?")
4413 );
4414 }
4415
4416 #[test]
4417 fn test_sampling_message_assistant() {
4418 let msg = SamplingMessage::assistant("I'm doing well!");
4419 assert_eq!(msg.role, ContentRole::Assistant);
4420 }
4421
4422 #[test]
4423 fn test_sampling_content_text_serialization() {
4424 let content = SamplingContent::Text {
4425 text: "Hello".to_string(),
4426 annotations: None,
4427 meta: None,
4428 };
4429 let json = serde_json::to_value(&content).unwrap();
4430 assert_eq!(json["type"], "text");
4431 assert_eq!(json["text"], "Hello");
4432 }
4433
4434 #[test]
4435 fn test_sampling_content_image_serialization() {
4436 let content = SamplingContent::Image {
4437 data: "base64data".to_string(),
4438 mime_type: "image/png".to_string(),
4439 annotations: None,
4440 meta: None,
4441 };
4442 let json = serde_json::to_value(&content).unwrap();
4443 assert_eq!(json["type"], "image");
4444 assert_eq!(json["data"], "base64data");
4445 assert_eq!(json["mimeType"], "image/png");
4446 }
4447
4448 #[test]
4449 fn test_create_message_params() {
4450 let params = CreateMessageParams::new(
4451 vec![
4452 SamplingMessage::user("What is 2+2?"),
4453 SamplingMessage::assistant("4"),
4454 SamplingMessage::user("And 3+3?"),
4455 ],
4456 100,
4457 )
4458 .system_prompt("You are a math tutor")
4459 .temperature(0.7)
4460 .stop_sequence("END")
4461 .include_context(IncludeContext::ThisServer);
4462
4463 assert_eq!(params.messages.len(), 3);
4464 assert_eq!(params.max_tokens, 100);
4465 assert_eq!(
4466 params.system_prompt.as_deref(),
4467 Some("You are a math tutor")
4468 );
4469 assert_eq!(params.temperature, Some(0.7));
4470 assert_eq!(params.stop_sequences.len(), 1);
4471 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
4472 }
4473
4474 #[test]
4475 fn test_create_message_params_serialization() {
4476 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
4477
4478 let json = serde_json::to_value(¶ms).unwrap();
4479 assert!(json["messages"].is_array());
4480 assert_eq!(json["maxTokens"], 50);
4481 }
4482
4483 #[test]
4484 fn test_create_message_result_deserialization() {
4485 let json = serde_json::json!({
4486 "content": {
4487 "type": "text",
4488 "text": "The answer is 42"
4489 },
4490 "model": "claude-3-opus",
4491 "role": "assistant",
4492 "stopReason": "end_turn"
4493 });
4494
4495 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
4496 assert_eq!(result.model, "claude-3-opus");
4497 assert_eq!(result.role, ContentRole::Assistant);
4498 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
4499 }
4500
4501 #[test]
4502 fn test_completions_capability_serialization() {
4503 let cap = CompletionsCapability {};
4504 let json = serde_json::to_value(&cap).unwrap();
4505 assert!(json.is_object());
4506 }
4507
4508 #[test]
4509 fn test_server_capabilities_with_completions() {
4510 let caps = ServerCapabilities {
4511 completions: Some(CompletionsCapability {}),
4512 ..Default::default()
4513 };
4514
4515 let json = serde_json::to_value(&caps).unwrap();
4516 assert!(json["completions"].is_object());
4517 }
4518
4519 #[test]
4520 fn test_content_resource_link_serialization() {
4521 let content = Content::ResourceLink {
4522 uri: "file:///test.txt".to_string(),
4523 name: "test.txt".to_string(),
4524 title: None,
4525 description: Some("A test file".to_string()),
4526 mime_type: Some("text/plain".to_string()),
4527 size: None,
4528 icons: None,
4529 annotations: None,
4530 meta: None,
4531 };
4532 let json = serde_json::to_value(&content).unwrap();
4533 assert_eq!(json["type"], "resource_link");
4534 assert_eq!(json["uri"], "file:///test.txt");
4535 assert_eq!(json["name"], "test.txt");
4536 assert_eq!(json["description"], "A test file");
4537 assert_eq!(json["mimeType"], "text/plain");
4538 }
4539
4540 #[test]
4541 fn test_call_tool_result_resource_link() {
4542 let result = CallToolResult::resource_link("file:///output.json", "output.json");
4543 assert_eq!(result.content.len(), 1);
4544 assert!(!result.is_error);
4545 match &result.content[0] {
4546 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
4547 _ => panic!("Expected ResourceLink content"),
4548 }
4549 }
4550
4551 #[test]
4552 fn test_call_tool_result_image() {
4553 let result = CallToolResult::image("base64data", "image/png");
4554 assert_eq!(result.content.len(), 1);
4555 match &result.content[0] {
4556 Content::Image {
4557 data, mime_type, ..
4558 } => {
4559 assert_eq!(data, "base64data");
4560 assert_eq!(mime_type, "image/png");
4561 }
4562 _ => panic!("Expected Image content"),
4563 }
4564 }
4565
4566 #[test]
4567 fn test_call_tool_result_audio() {
4568 let result = CallToolResult::audio("audiodata", "audio/wav");
4569 assert_eq!(result.content.len(), 1);
4570 match &result.content[0] {
4571 Content::Audio {
4572 data, mime_type, ..
4573 } => {
4574 assert_eq!(data, "audiodata");
4575 assert_eq!(mime_type, "audio/wav");
4576 }
4577 _ => panic!("Expected Audio content"),
4578 }
4579 }
4580
4581 #[test]
4582 fn test_sampling_tool_serialization() {
4583 let tool = SamplingTool {
4584 name: "get_weather".to_string(),
4585 title: None,
4586 description: Some("Get current weather".to_string()),
4587 input_schema: serde_json::json!({
4588 "type": "object",
4589 "properties": {
4590 "location": { "type": "string" }
4591 }
4592 }),
4593 output_schema: None,
4594 icons: None,
4595 annotations: None,
4596 execution: None,
4597 };
4598 let json = serde_json::to_value(&tool).unwrap();
4599 assert_eq!(json["name"], "get_weather");
4600 assert_eq!(json["description"], "Get current weather");
4601 assert!(json["inputSchema"]["properties"]["location"].is_object());
4602 }
4603
4604 #[test]
4605 fn test_tool_choice_modes() {
4606 let auto = ToolChoice::auto();
4607 assert_eq!(auto.mode, "auto");
4608 assert!(auto.name.is_none());
4609
4610 let required = ToolChoice::required();
4611 assert_eq!(required.mode, "required");
4612
4613 let none = ToolChoice::none();
4614 assert_eq!(none.mode, "none");
4615
4616 let tool = ToolChoice::tool("get_weather");
4617 assert_eq!(tool.mode, "tool");
4618 assert_eq!(tool.name.as_deref(), Some("get_weather"));
4619
4620 let json = serde_json::to_value(&auto).unwrap();
4622 assert_eq!(json["mode"], "auto");
4623 assert!(json.get("name").is_none());
4624
4625 let json = serde_json::to_value(&tool).unwrap();
4626 assert_eq!(json["mode"], "tool");
4627 assert_eq!(json["name"], "get_weather");
4628 }
4629
4630 #[test]
4631 fn test_sampling_content_tool_use() {
4632 let content = SamplingContent::ToolUse {
4633 id: "tool_123".to_string(),
4634 name: "get_weather".to_string(),
4635 input: serde_json::json!({"location": "San Francisco"}),
4636 meta: None,
4637 };
4638 let json = serde_json::to_value(&content).unwrap();
4639 assert_eq!(json["type"], "tool_use");
4640 assert_eq!(json["id"], "tool_123");
4641 assert_eq!(json["name"], "get_weather");
4642 assert_eq!(json["input"]["location"], "San Francisco");
4643 }
4644
4645 #[test]
4646 fn test_sampling_content_tool_result() {
4647 let content = SamplingContent::ToolResult {
4648 tool_use_id: "tool_123".to_string(),
4649 content: vec![SamplingContent::Text {
4650 text: "72F, sunny".to_string(),
4651 annotations: None,
4652 meta: None,
4653 }],
4654 structured_content: None,
4655 is_error: None,
4656 meta: None,
4657 };
4658 let json = serde_json::to_value(&content).unwrap();
4659 assert_eq!(json["type"], "tool_result");
4660 assert_eq!(json["toolUseId"], "tool_123");
4661 assert_eq!(json["content"][0]["type"], "text");
4662 }
4663
4664 #[test]
4665 fn test_sampling_content_or_array_single() {
4666 let json = serde_json::json!({
4667 "type": "text",
4668 "text": "Hello"
4669 });
4670 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4671 let items = content.items();
4672 assert_eq!(items.len(), 1);
4673 match items[0] {
4674 SamplingContent::Text { text, .. } => assert_eq!(text, "Hello"),
4675 _ => panic!("Expected text content"),
4676 }
4677 }
4678
4679 #[test]
4680 fn test_sampling_content_or_array_multiple() {
4681 let json = serde_json::json!([
4682 { "type": "text", "text": "Hello" },
4683 { "type": "text", "text": "World" }
4684 ]);
4685 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4686 let items = content.items();
4687 assert_eq!(items.len(), 2);
4688 }
4689
4690 #[test]
4691 fn test_create_message_params_with_tools() {
4692 let tool = SamplingTool {
4693 name: "calculator".to_string(),
4694 title: None,
4695 description: Some("Do math".to_string()),
4696 input_schema: serde_json::json!({"type": "object"}),
4697 output_schema: None,
4698 icons: None,
4699 annotations: None,
4700 execution: None,
4701 };
4702 let params = CreateMessageParams::new(vec![], 100)
4703 .tools(vec![tool])
4704 .tool_choice(ToolChoice::auto());
4705
4706 let json = serde_json::to_value(¶ms).unwrap();
4707 assert!(json["tools"].is_array());
4708 assert_eq!(json["tools"][0]["name"], "calculator");
4709 assert_eq!(json["toolChoice"]["mode"], "auto");
4710 }
4711
4712 #[test]
4713 fn test_create_message_result_content_items() {
4714 let result = CreateMessageResult {
4715 content: SamplingContentOrArray::Array(vec![
4716 SamplingContent::Text {
4717 text: "First".to_string(),
4718 annotations: None,
4719 meta: None,
4720 },
4721 SamplingContent::Text {
4722 text: "Second".to_string(),
4723 annotations: None,
4724 meta: None,
4725 },
4726 ]),
4727 model: "test".to_string(),
4728 role: ContentRole::Assistant,
4729 stop_reason: None,
4730 meta: None,
4731 };
4732 let items = result.content_items();
4733 assert_eq!(items.len(), 2);
4734 }
4735
4736 #[test]
4737 fn test_sampling_content_as_text() {
4738 let text_content = SamplingContent::Text {
4739 text: "Hello".to_string(),
4740 annotations: None,
4741 meta: None,
4742 };
4743 assert_eq!(text_content.as_text(), Some("Hello"));
4744
4745 let image_content = SamplingContent::Image {
4746 data: "base64data".to_string(),
4747 mime_type: "image/png".to_string(),
4748 annotations: None,
4749 meta: None,
4750 };
4751 assert_eq!(image_content.as_text(), None);
4752
4753 let audio_content = SamplingContent::Audio {
4754 data: "base64audio".to_string(),
4755 mime_type: "audio/wav".to_string(),
4756 annotations: None,
4757 meta: None,
4758 };
4759 assert_eq!(audio_content.as_text(), None);
4760 }
4761
4762 #[test]
4763 fn test_create_message_result_first_text_single() {
4764 let result = CreateMessageResult {
4765 content: SamplingContentOrArray::Single(SamplingContent::Text {
4766 text: "Hello, world!".to_string(),
4767 annotations: None,
4768 meta: None,
4769 }),
4770 model: "test".to_string(),
4771 role: ContentRole::Assistant,
4772 stop_reason: None,
4773 meta: None,
4774 };
4775 assert_eq!(result.first_text(), Some("Hello, world!"));
4776 }
4777
4778 #[test]
4779 fn test_create_message_result_first_text_array() {
4780 let result = CreateMessageResult {
4781 content: SamplingContentOrArray::Array(vec![
4782 SamplingContent::Text {
4783 text: "First".to_string(),
4784 annotations: None,
4785 meta: None,
4786 },
4787 SamplingContent::Text {
4788 text: "Second".to_string(),
4789 annotations: None,
4790 meta: None,
4791 },
4792 ]),
4793 model: "test".to_string(),
4794 role: ContentRole::Assistant,
4795 stop_reason: None,
4796 meta: None,
4797 };
4798 assert_eq!(result.first_text(), Some("First"));
4799 }
4800
4801 #[test]
4802 fn test_create_message_result_first_text_skips_non_text() {
4803 let result = CreateMessageResult {
4804 content: SamplingContentOrArray::Array(vec![
4805 SamplingContent::Image {
4806 data: "base64data".to_string(),
4807 mime_type: "image/png".to_string(),
4808 annotations: None,
4809 meta: None,
4810 },
4811 SamplingContent::Text {
4812 text: "After image".to_string(),
4813 annotations: None,
4814 meta: None,
4815 },
4816 ]),
4817 model: "test".to_string(),
4818 role: ContentRole::Assistant,
4819 stop_reason: None,
4820 meta: None,
4821 };
4822 assert_eq!(result.first_text(), Some("After image"));
4823 }
4824
4825 #[test]
4826 fn test_create_message_result_first_text_none() {
4827 let result = CreateMessageResult {
4828 content: SamplingContentOrArray::Single(SamplingContent::Image {
4829 data: "base64data".to_string(),
4830 mime_type: "image/png".to_string(),
4831 annotations: None,
4832 meta: None,
4833 }),
4834 model: "test".to_string(),
4835 role: ContentRole::Assistant,
4836 stop_reason: None,
4837 meta: None,
4838 };
4839 assert_eq!(result.first_text(), None);
4840 }
4841
4842 #[test]
4843 fn test_tool_annotations_accessors() {
4844 let annotations = ToolAnnotations {
4845 read_only_hint: true,
4846 destructive_hint: false,
4847 idempotent_hint: true,
4848 open_world_hint: false,
4849 ..Default::default()
4850 };
4851
4852 assert!(annotations.is_read_only());
4853 assert!(!annotations.is_destructive());
4854 assert!(annotations.is_idempotent());
4855 assert!(!annotations.is_open_world());
4856 }
4857
4858 #[test]
4859 fn test_tool_annotations_defaults() {
4860 let annotations = ToolAnnotations::default();
4862
4863 assert!(!annotations.is_read_only());
4864 assert!(annotations.is_destructive());
4865 assert!(!annotations.is_idempotent());
4866 assert!(annotations.is_open_world());
4867 }
4868
4869 #[test]
4870 fn test_tool_annotations_serde_defaults() {
4871 let annotations: ToolAnnotations = serde_json::from_str("{}").unwrap();
4874
4875 assert!(!annotations.is_read_only());
4876 assert!(annotations.is_destructive());
4877 assert!(!annotations.is_idempotent());
4878 assert!(annotations.is_open_world());
4879 }
4880
4881 #[test]
4882 fn test_tool_definition_accessors_with_annotations() {
4883 let def = ToolDefinition {
4884 name: "test".to_string(),
4885 title: None,
4886 description: None,
4887 input_schema: serde_json::json!({"type": "object"}),
4888 output_schema: None,
4889 icons: None,
4890 annotations: Some(ToolAnnotations {
4891 read_only_hint: true,
4892 idempotent_hint: true,
4893 destructive_hint: false,
4894 open_world_hint: false,
4895 ..Default::default()
4896 }),
4897 execution: None,
4898 meta: None,
4899 };
4900
4901 assert!(def.is_read_only());
4902 assert!(!def.is_destructive());
4903 assert!(def.is_idempotent());
4904 assert!(!def.is_open_world());
4905 }
4906
4907 #[test]
4908 fn test_tool_definition_accessors_without_annotations() {
4909 let def = ToolDefinition {
4910 name: "test".to_string(),
4911 title: None,
4912 description: None,
4913 input_schema: serde_json::json!({"type": "object"}),
4914 output_schema: None,
4915 icons: None,
4916 annotations: None,
4917 execution: None,
4918 meta: None,
4919 };
4920
4921 assert!(!def.is_read_only());
4923 assert!(def.is_destructive());
4924 assert!(!def.is_idempotent());
4925 assert!(def.is_open_world());
4926 }
4927
4928 #[test]
4929 fn test_call_tool_result_from_list() {
4930 #[derive(serde::Serialize)]
4931 struct Item {
4932 name: String,
4933 }
4934
4935 let items = vec![
4936 Item {
4937 name: "a".to_string(),
4938 },
4939 Item {
4940 name: "b".to_string(),
4941 },
4942 Item {
4943 name: "c".to_string(),
4944 },
4945 ];
4946
4947 let result = CallToolResult::from_list("items", &items).unwrap();
4948 assert!(!result.is_error);
4949
4950 let structured = result.structured_content.unwrap();
4951 assert_eq!(structured["count"], 3);
4952 assert_eq!(structured["items"].as_array().unwrap().len(), 3);
4953 assert_eq!(structured["items"][0]["name"], "a");
4954 }
4955
4956 #[test]
4957 fn test_call_tool_result_from_list_empty() {
4958 let items: Vec<String> = vec![];
4959 let result = CallToolResult::from_list("results", &items).unwrap();
4960 assert!(!result.is_error);
4961
4962 let structured = result.structured_content.unwrap();
4963 assert_eq!(structured["count"], 0);
4964 assert_eq!(structured["results"].as_array().unwrap().len(), 0);
4965 }
4966
4967 #[test]
4972 fn test_call_tool_result_as_json() {
4973 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4974 let value = result.as_json().unwrap().unwrap();
4975 assert_eq!(value["key"], "value");
4976 }
4977
4978 #[test]
4979 fn test_call_tool_result_as_json_from_text() {
4980 let result = CallToolResult::text(r#"{"key": "value"}"#);
4981 let value = result.as_json().unwrap().unwrap();
4982 assert_eq!(value["key"], "value");
4983 }
4984
4985 #[test]
4986 fn test_call_tool_result_as_json_none() {
4987 let result = CallToolResult::text("not json");
4988 let parsed = result.as_json().unwrap();
4989 assert!(parsed.is_err());
4990 }
4991
4992 #[test]
4993 fn test_call_tool_result_deserialize() {
4994 #[derive(Debug, serde::Deserialize, PartialEq)]
4995 struct Output {
4996 key: String,
4997 }
4998
4999 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
5000 let output: Output = result.deserialize().unwrap().unwrap();
5001 assert_eq!(output.key, "value");
5002 }
5003
5004 #[test]
5005 fn test_call_tool_result_as_json_empty() {
5006 let result = CallToolResult {
5007 content: vec![],
5008 is_error: false,
5009 structured_content: None,
5010 meta: None,
5011 };
5012 assert!(result.as_json().is_none());
5013 }
5014
5015 #[test]
5016 fn test_call_tool_result_deserialize_from_text() {
5017 #[derive(Debug, serde::Deserialize, PartialEq)]
5018 struct Output {
5019 key: String,
5020 }
5021
5022 let result = CallToolResult::text(r#"{"key": "from_text"}"#);
5023 let output: Output = result.deserialize().unwrap().unwrap();
5024 assert_eq!(output.key, "from_text");
5025 }
5026
5027 #[test]
5028 fn test_read_resource_result_as_json() {
5029 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5030 let value = result.as_json().unwrap().unwrap();
5031 assert_eq!(value["port"], 8080);
5032 }
5033
5034 #[test]
5035 fn test_read_resource_result_deserialize() {
5036 #[derive(Debug, serde::Deserialize, PartialEq)]
5037 struct Config {
5038 port: u16,
5039 }
5040
5041 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5042 let config: Config = result.deserialize().unwrap().unwrap();
5043 assert_eq!(config.port, 8080);
5044 }
5045
5046 #[test]
5047 fn test_get_prompt_result_as_json() {
5048 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5049 let value = result.as_json().unwrap().unwrap();
5050 assert_eq!(value["action"], "analyze");
5051 }
5052
5053 #[test]
5054 fn test_get_prompt_result_deserialize() {
5055 #[derive(Debug, serde::Deserialize, PartialEq)]
5056 struct Params {
5057 action: String,
5058 }
5059
5060 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5061 let params: Params = result.deserialize().unwrap().unwrap();
5062 assert_eq!(params.action, "analyze");
5063 }
5064
5065 #[test]
5066 fn test_get_prompt_result_as_json_empty() {
5067 let result = GetPromptResult {
5068 description: None,
5069 messages: vec![],
5070 meta: None,
5071 };
5072 assert!(result.as_json().is_none());
5073 }
5074}