1#![expect(deprecated)]
4use std::{
5 borrow::Cow,
6 ops::{Deref, DerefMut},
7 sync::Arc,
8};
9mod annotated;
10mod capabilities;
11mod content;
12mod elicitation_schema;
13mod extension;
14mod meta;
15mod mrtr;
16mod prompt;
17#[cfg(feature = "request-state")]
18mod request_state;
19mod resource;
20mod serde_impl;
21mod task;
22mod tool;
23pub use annotated::*;
24pub use capabilities::*;
25pub use content::*;
26pub use elicitation_schema::*;
27pub use extension::*;
28pub use meta::*;
29pub use mrtr::*;
30pub use prompt::*;
31#[cfg(feature = "request-state")]
32pub use request_state::*;
33pub use resource::*;
34use serde::{Deserialize, Serialize, de::DeserializeOwned};
35use serde_json::Value;
36pub use task::*;
37pub use tool::*;
38
39pub type JsonObject<F = Value> = serde_json::Map<String, F>;
44
45pub fn object(value: serde_json::Value) -> JsonObject {
50 debug_assert!(value.is_object());
51 match value {
52 serde_json::Value::Object(map) => map,
53 _ => JsonObject::default(),
54 }
55}
56
57#[cfg(feature = "macros")]
59#[macro_export]
60macro_rules! object {
61 ({$($tt:tt)*}) => {
62 $crate::model::object(serde_json::json! {
63 {$($tt)*}
64 })
65 };
66}
67
68#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
72#[serde(deny_unknown_fields)]
73#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
74#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
75pub struct EmptyObject {}
76
77pub trait ConstString: Default {
78 const VALUE: &str;
79 fn as_str(&self) -> &'static str {
80 Self::VALUE
81 }
82}
83#[macro_export]
84macro_rules! const_string {
85 ($name:ident = $value:literal) => {
86 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
87 #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
88 pub struct $name;
89
90 impl ConstString for $name {
91 const VALUE: &str = $value;
92 }
93
94 impl serde::Serialize for $name {
95 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
96 where
97 S: serde::Serializer,
98 {
99 $value.serialize(serializer)
100 }
101 }
102
103 impl<'de> serde::Deserialize<'de> for $name {
104 fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
105 where
106 D: serde::Deserializer<'de>,
107 {
108 let s: String = serde::Deserialize::deserialize(deserializer)?;
109 if s == $value {
110 Ok($name)
111 } else {
112 Err(serde::de::Error::custom(format!(concat!(
113 "expect const string value \"",
114 $value,
115 "\""
116 ))))
117 }
118 }
119 }
120
121 #[cfg(feature = "schemars")]
122 impl schemars::JsonSchema for $name {
123 fn schema_name() -> Cow<'static, str> {
124 Cow::Borrowed(stringify!($name))
125 }
126
127 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
128 use serde_json::{Map, json};
129
130 let mut schema_map = Map::new();
131 schema_map.insert("type".to_string(), json!("string"));
132 schema_map.insert("format".to_string(), json!("const"));
133 schema_map.insert("const".to_string(), json!($value));
134
135 schemars::Schema::from(schema_map)
136 }
137 }
138 };
139}
140
141const_string!(JsonRpcVersion2_0 = "2.0");
142
143#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
152#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
153pub struct ProtocolVersion(Cow<'static, str>);
154
155impl Default for ProtocolVersion {
156 fn default() -> Self {
157 Self::LATEST
158 }
159}
160
161impl std::fmt::Display for ProtocolVersion {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 self.0.fmt(f)
164 }
165}
166
167impl ProtocolVersion {
168 pub const V_2026_07_28: Self = Self(Cow::Borrowed("2026-07-28"));
169 pub const V_2025_11_25: Self = Self(Cow::Borrowed("2025-11-25"));
170 pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
171 pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
172 pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
173 pub const LATEST: Self = Self::V_2025_11_25;
174
175 pub const STANDARD_HEADERS: Self = Self::V_2026_07_28;
177
178 pub const KNOWN_VERSIONS: &[Self] = &[
180 Self::V_2024_11_05,
181 Self::V_2025_03_26,
182 Self::V_2025_06_18,
183 Self::V_2025_11_25,
184 Self::V_2026_07_28,
185 ];
186
187 pub fn as_str(&self) -> &str {
189 &self.0
190 }
191}
192
193impl Serialize for ProtocolVersion {
194 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
195 where
196 S: serde::Serializer,
197 {
198 self.0.serialize(serializer)
199 }
200}
201
202impl<'de> Deserialize<'de> for ProtocolVersion {
203 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204 where
205 D: serde::Deserializer<'de>,
206 {
207 let s: String = Deserialize::deserialize(deserializer)?;
208 #[allow(clippy::single_match)]
209 match s.as_str() {
210 "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
211 "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
212 "2025-06-18" => return Ok(ProtocolVersion::V_2025_06_18),
213 "2025-11-25" => return Ok(ProtocolVersion::V_2025_11_25),
214 "2026-07-28" => return Ok(ProtocolVersion::V_2026_07_28),
215 _ => {}
216 }
217 Ok(ProtocolVersion(Cow::Owned(s)))
218 }
219}
220
221#[derive(Debug, Clone, Eq, PartialEq, Hash)]
226#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
227pub enum NumberOrString {
228 Number(i64),
230 String(Arc<str>),
232}
233
234impl NumberOrString {
235 pub fn into_json_value(self) -> Value {
236 match self {
237 NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
238 NumberOrString::String(s) => Value::String(s.to_string()),
239 }
240 }
241}
242
243impl std::fmt::Display for NumberOrString {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 match self {
246 NumberOrString::Number(n) => n.fmt(f),
247 NumberOrString::String(s) => s.fmt(f),
248 }
249 }
250}
251
252impl Serialize for NumberOrString {
253 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
254 where
255 S: serde::Serializer,
256 {
257 match self {
258 NumberOrString::Number(n) => n.serialize(serializer),
259 NumberOrString::String(s) => s.serialize(serializer),
260 }
261 }
262}
263
264impl<'de> Deserialize<'de> for NumberOrString {
265 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
266 where
267 D: serde::Deserializer<'de>,
268 {
269 let value: Value = Deserialize::deserialize(deserializer)?;
270 match value {
271 Value::Number(n) => {
272 if let Some(i) = n.as_i64() {
273 Ok(NumberOrString::Number(i))
274 } else if let Some(u) = n.as_u64() {
275 if u <= i64::MAX as u64 {
277 Ok(NumberOrString::Number(u as i64))
278 } else {
279 Err(serde::de::Error::custom("Number too large for i64"))
280 }
281 } else {
282 Err(serde::de::Error::custom("Expected an integer"))
283 }
284 }
285 Value::String(s) => Ok(NumberOrString::String(s.into())),
286 _ => Err(serde::de::Error::custom("Expect number or string")),
287 }
288 }
289}
290
291#[cfg(feature = "schemars")]
292impl schemars::JsonSchema for NumberOrString {
293 fn schema_name() -> Cow<'static, str> {
294 Cow::Borrowed("NumberOrString")
295 }
296
297 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
298 use serde_json::{Map, json};
299
300 let mut number_schema = Map::new();
301 number_schema.insert("type".to_string(), json!("number"));
302
303 let mut string_schema = Map::new();
304 string_schema.insert("type".to_string(), json!("string"));
305
306 let mut schema_map = Map::new();
307 schema_map.insert("oneOf".to_string(), json!([number_schema, string_schema]));
308
309 schemars::Schema::from(schema_map)
310 }
311}
312
313pub type RequestId = NumberOrString;
315
316#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
321#[serde(transparent)]
322#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
323#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
324pub struct ProgressToken(pub NumberOrString);
325
326#[derive(Debug, Clone, Default)]
337#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
338#[non_exhaustive]
339pub struct Request<M = String, P = JsonObject> {
340 pub method: M,
341 pub params: P,
342 #[cfg_attr(feature = "schemars", schemars(skip))]
347 pub extensions: Extensions,
348}
349
350impl<M: Default, P> Request<M, P> {
351 pub fn new(params: P) -> Self {
352 Self {
353 method: Default::default(),
354 params,
355 extensions: Extensions::default(),
356 }
357 }
358}
359
360impl<M, P> GetExtensions for Request<M, P> {
361 fn extensions(&self) -> &Extensions {
362 &self.extensions
363 }
364 fn extensions_mut(&mut self) -> &mut Extensions {
365 &mut self.extensions
366 }
367}
368
369#[derive(Debug, Clone, Default)]
370#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
371#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
372pub struct RequestOptionalParam<M = String, P = JsonObject> {
373 pub method: M,
374 pub params: Option<P>,
376 #[cfg_attr(feature = "schemars", schemars(skip))]
381 pub extensions: Extensions,
382}
383
384impl<M: Default, P> RequestOptionalParam<M, P> {
385 pub fn with_param(params: P) -> Self {
386 Self {
387 method: Default::default(),
388 params: Some(params),
389 extensions: Extensions::default(),
390 }
391 }
392}
393
394#[derive(Debug, Clone, Default)]
395#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
396#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
397pub struct RequestNoParam<M = String> {
398 pub method: M,
399 #[cfg_attr(feature = "schemars", schemars(skip))]
404 pub extensions: Extensions,
405}
406
407impl<M> GetExtensions for RequestNoParam<M> {
408 fn extensions(&self) -> &Extensions {
409 &self.extensions
410 }
411 fn extensions_mut(&mut self) -> &mut Extensions {
412 &mut self.extensions
413 }
414}
415#[derive(Debug, Clone, Default)]
416#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
417#[non_exhaustive]
418pub struct Notification<M = String, P = JsonObject> {
419 pub method: M,
420 pub params: P,
421 #[cfg_attr(feature = "schemars", schemars(skip))]
426 pub extensions: Extensions,
427}
428
429impl<M: Default, P> Notification<M, P> {
430 pub fn new(params: P) -> Self {
431 Self {
432 method: Default::default(),
433 params,
434 extensions: Extensions::default(),
435 }
436 }
437}
438
439#[derive(Debug, Clone, Default)]
440#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
441#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
442pub struct NotificationNoParam<M = String> {
443 pub method: M,
444 #[cfg_attr(feature = "schemars", schemars(skip))]
449 pub extensions: Extensions,
450}
451
452#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
453#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
454#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
455pub struct JsonRpcRequest<R = Request> {
456 pub jsonrpc: JsonRpcVersion2_0,
457 pub id: RequestId,
458 #[serde(flatten)]
459 pub request: R,
460}
461
462impl<R> JsonRpcRequest<R> {
463 pub fn new(id: RequestId, request: R) -> Self {
465 Self {
466 jsonrpc: JsonRpcVersion2_0,
467 id,
468 request,
469 }
470 }
471}
472
473type DefaultResponse = JsonObject;
474#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
475#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
476#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
477pub struct JsonRpcResponse<R = JsonObject> {
478 pub jsonrpc: JsonRpcVersion2_0,
479 pub id: RequestId,
480 pub result: R,
481}
482
483#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
484#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
485#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
486pub struct JsonRpcError {
487 pub jsonrpc: JsonRpcVersion2_0,
488 #[serde(default, skip_serializing_if = "Option::is_none")]
492 pub id: Option<RequestId>,
493 pub error: ErrorData,
494}
495
496impl JsonRpcError {
497 pub fn new(id: Option<RequestId>, error: ErrorData) -> Self {
499 Self {
500 jsonrpc: JsonRpcVersion2_0,
501 id,
502 error,
503 }
504 }
505}
506
507#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
508#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
509#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
510pub struct JsonRpcNotification<N = Notification> {
511 pub jsonrpc: JsonRpcVersion2_0,
512 #[serde(flatten)]
513 pub notification: N,
514}
515
516#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
521#[serde(transparent)]
522#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
523#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
524pub struct ErrorCode(pub i32);
525
526impl ErrorCode {
527 pub const UNSUPPORTED_PROTOCOL_VERSION: Self = Self(-32022);
529 pub const MISSING_REQUIRED_CLIENT_CAPABILITY: Self = Self(-32021);
531 pub const HEADER_MISMATCH: Self = Self(-32020);
532 pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
533 pub const INVALID_REQUEST: Self = Self(-32600);
534 pub const METHOD_NOT_FOUND: Self = Self(-32601);
535 pub const INVALID_PARAMS: Self = Self(-32602);
536 pub const INTERNAL_ERROR: Self = Self(-32603);
537 pub const PARSE_ERROR: Self = Self(-32700);
538}
539
540#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
545#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
546#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
547pub struct ErrorData {
548 pub code: ErrorCode,
550
551 pub message: Cow<'static, str>,
553
554 #[serde(skip_serializing_if = "Option::is_none")]
557 pub data: Option<Value>,
558}
559
560impl ErrorData {
561 pub fn new(
562 code: ErrorCode,
563 message: impl Into<Cow<'static, str>>,
564 data: Option<Value>,
565 ) -> Self {
566 Self {
567 code,
568 message: message.into(),
569 data,
570 }
571 }
572 pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
575 Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
576 }
577 pub fn header_mismatch(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
578 Self::new(ErrorCode::HEADER_MISMATCH, message, data)
579 }
580 pub fn unsupported_protocol_version(
582 requested: ProtocolVersion,
583 supported: &[ProtocolVersion],
584 ) -> Self {
585 Self::new(
586 ErrorCode::UNSUPPORTED_PROTOCOL_VERSION,
587 "Unsupported protocol version",
588 Some(serde_json::json!({
589 "requested": requested,
590 "supported": supported,
591 })),
592 )
593 }
594 pub fn missing_required_client_capability(required: ClientCapabilities) -> Self {
596 Self::new(
597 ErrorCode::MISSING_REQUIRED_CLIENT_CAPABILITY,
598 "Missing required client capability",
599 Some(serde_json::json!({
600 "requiredCapabilities": required,
601 })),
602 )
603 }
604 pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
605 Self::new(ErrorCode::PARSE_ERROR, message, data)
606 }
607 pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
608 Self::new(ErrorCode::INVALID_REQUEST, message, data)
609 }
610 pub fn method_not_found<M: ConstString>() -> Self {
611 Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
612 }
613 pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
614 Self::new(ErrorCode::INVALID_PARAMS, message, data)
615 }
616 pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
617 Self::new(ErrorCode::INTERNAL_ERROR, message, data)
618 }
619}
620
621#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
627#[serde(untagged)]
628#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
629#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
630pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
631 Request(JsonRpcRequest<Req>),
633 Response(JsonRpcResponse<Resp>),
635 Notification(JsonRpcNotification<Noti>),
637 Error(JsonRpcError),
639}
640
641impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
642 #[inline]
643 pub const fn request(request: Req, id: RequestId) -> Self {
644 JsonRpcMessage::Request(JsonRpcRequest {
645 jsonrpc: JsonRpcVersion2_0,
646 id,
647 request,
648 })
649 }
650 #[inline]
651 pub const fn response(response: Resp, id: RequestId) -> Self {
652 JsonRpcMessage::Response(JsonRpcResponse {
653 jsonrpc: JsonRpcVersion2_0,
654 id,
655 result: response,
656 })
657 }
658 #[inline]
659 pub const fn error(error: ErrorData, id: Option<RequestId>) -> Self {
660 JsonRpcMessage::Error(JsonRpcError {
661 jsonrpc: JsonRpcVersion2_0,
662 id,
663 error,
664 })
665 }
666 #[inline]
667 pub const fn notification(notification: Not) -> Self {
668 JsonRpcMessage::Notification(JsonRpcNotification {
669 jsonrpc: JsonRpcVersion2_0,
670 notification,
671 })
672 }
673 pub fn into_request(self) -> Option<(Req, RequestId)> {
674 match self {
675 JsonRpcMessage::Request(r) => Some((r.request, r.id)),
676 _ => None,
677 }
678 }
679 pub fn into_response(self) -> Option<(Resp, RequestId)> {
680 match self {
681 JsonRpcMessage::Response(r) => Some((r.result, r.id)),
682 _ => None,
683 }
684 }
685 pub fn into_notification(self) -> Option<Not> {
686 match self {
687 JsonRpcMessage::Notification(n) => Some(n.notification),
688 _ => None,
689 }
690 }
691 pub fn into_error(self) -> Option<(ErrorData, Option<RequestId>)> {
692 match self {
693 JsonRpcMessage::Error(e) => Some((e.error, e.id)),
694 _ => None,
695 }
696 }
697 pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, Option<RequestId>)> {
698 match self {
699 JsonRpcMessage::Response(r) => Some((Ok(r.result), Some(r.id))),
700 JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),
701
702 _ => None,
703 }
704 }
705}
706
707pub type EmptyResult = EmptyObject;
714
715impl From<()> for EmptyResult {
716 fn from(_value: ()) -> Self {
717 EmptyResult {}
718 }
719}
720
721impl From<EmptyResult> for () {
722 fn from(_value: EmptyResult) {}
723}
724
725#[derive(Debug, Clone, PartialEq, Eq)]
733#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
734pub struct ResultType(Cow<'static, str>);
735
736impl ResultType {
737 pub const COMPLETE: Self = Self(Cow::Borrowed("complete"));
738 pub const INPUT_REQUIRED: Self = Self(Cow::Borrowed("input_required"));
739
740 pub fn as_str(&self) -> &str {
741 &self.0
742 }
743
744 pub fn is_input_required(&self) -> bool {
746 self.0 == "input_required"
747 }
748
749 pub fn is_complete(&self) -> bool {
751 self.0 == "complete"
752 }
753}
754
755impl Default for ResultType {
756 fn default() -> Self {
757 Self::COMPLETE
758 }
759}
760
761impl Serialize for ResultType {
762 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
763 where
764 S: serde::Serializer,
765 {
766 self.0.serialize(serializer)
767 }
768}
769
770impl<'de> Deserialize<'de> for ResultType {
771 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
772 where
773 D: serde::Deserializer<'de>,
774 {
775 let s: String = Deserialize::deserialize(deserializer)?;
776 match s.as_str() {
777 "complete" => Ok(Self::COMPLETE),
778 "input_required" => Ok(Self::INPUT_REQUIRED),
779 _ => Ok(Self(Cow::Owned(s))),
780 }
781 }
782}
783
784impl std::fmt::Display for ResultType {
785 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
786 self.0.fmt(f)
787 }
788}
789
790#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
792#[serde(transparent)]
793#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
794#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
795pub struct CustomResult(pub Value);
796
797impl CustomResult {
798 pub fn new(result: Value) -> Self {
799 Self(result)
800 }
801
802 pub fn result_as<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
804 serde_json::from_value(self.0.clone())
805 }
806}
807
808#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
809#[serde(rename_all = "camelCase")]
810#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
811#[non_exhaustive]
812pub struct CancelledNotificationParam {
813 #[serde(skip_serializing_if = "Option::is_none")]
814 pub request_id: Option<RequestId>,
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub reason: Option<String>,
817 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
818 pub meta: Option<NotificationMetaObject>,
819}
820
821impl CancelledNotificationParam {
822 pub fn new(request_id: Option<RequestId>, reason: Option<String>) -> Self {
823 Self {
824 request_id,
825 reason,
826 meta: None,
827 }
828 }
829}
830
831const_string!(CancelledNotificationMethod = "notifications/cancelled");
832
833pub type CancelledNotification =
842 Notification<CancelledNotificationMethod, CancelledNotificationParam>;
843
844#[derive(Debug, Clone)]
849#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
850#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
851pub struct CustomNotification {
852 pub method: String,
853 pub params: Option<Value>,
854 #[cfg_attr(feature = "schemars", schemars(skip))]
859 pub extensions: Extensions,
860}
861
862impl CustomNotification {
863 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
864 Self {
865 method: method.into(),
866 params,
867 extensions: Extensions::default(),
868 }
869 }
870
871 pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
873 self.params
874 .as_ref()
875 .map(|params| serde_json::from_value(params.clone()))
876 .transpose()
877 }
878}
879
880#[derive(Debug, Clone)]
885#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
886#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
887pub struct CustomRequest {
888 pub method: String,
889 pub params: Option<Value>,
890 #[cfg_attr(feature = "schemars", schemars(skip))]
895 pub extensions: Extensions,
896}
897
898impl CustomRequest {
899 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
900 Self {
901 method: method.into(),
902 params,
903 extensions: Extensions::default(),
904 }
905 }
906
907 pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
909 self.params
910 .as_ref()
911 .map(|params| serde_json::from_value(params.clone()))
912 .transpose()
913 }
914}
915
916const_string!(InitializeResultMethod = "initialize");
917pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParams>;
920
921const_string!(InitializedNotificationMethod = "notifications/initialized");
922pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;
924
925#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
930#[serde(rename_all = "camelCase")]
931#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
932#[non_exhaustive]
933pub struct InitializeRequestParams {
934 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
936 pub meta: Option<RequestMetaObject>,
937 pub protocol_version: ProtocolVersion,
939 pub capabilities: ClientCapabilities,
941 pub client_info: Implementation,
943}
944
945impl InitializeRequestParams {
946 pub fn new(capabilities: ClientCapabilities, client_info: Implementation) -> Self {
948 Self {
949 meta: None,
950 protocol_version: ProtocolVersion::default(),
951 capabilities,
952 client_info,
953 }
954 }
955
956 pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
957 self.protocol_version = protocol_version;
958 self
959 }
960}
961
962impl RequestParamsMeta for InitializeRequestParams {
963 fn meta(&self) -> Option<&RequestMetaObject> {
964 self.meta.as_ref()
965 }
966 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
967 &mut self.meta
968 }
969}
970
971#[deprecated(since = "0.13.0", note = "Use InitializeRequestParams instead")]
973pub type InitializeRequestParam = InitializeRequestParams;
974
975#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
980#[serde(rename_all = "camelCase")]
981#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
982#[non_exhaustive]
983pub struct InitializeResult {
984 pub protocol_version: ProtocolVersion,
986 pub capabilities: ServerCapabilities,
988 pub server_info: Implementation,
990 #[serde(skip_serializing_if = "Option::is_none")]
992 pub instructions: Option<String>,
993 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
994 pub meta: Option<MetaObject>,
995}
996
997impl InitializeResult {
998 pub fn new(capabilities: ServerCapabilities) -> Self {
1000 Self {
1001 protocol_version: ProtocolVersion::default(),
1002 capabilities,
1003 server_info: Implementation::from_build_env(),
1004 instructions: None,
1005 meta: None,
1006 }
1007 }
1008
1009 pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
1011 self.instructions = Some(instructions.into());
1012 self
1013 }
1014
1015 pub fn with_server_info(mut self, server_info: Implementation) -> Self {
1017 self.server_info = server_info;
1018 self
1019 }
1020
1021 pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
1023 self.protocol_version = protocol_version;
1024 self
1025 }
1026}
1027
1028pub type ServerInfo = InitializeResult;
1029pub type ClientInfo = InitializeRequestParams;
1030
1031const_string!(DiscoverRequestMethod = "server/discover");
1032
1033#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
1035#[serde(deny_unknown_fields)]
1036#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1037pub struct DiscoverRequestParams {}
1038
1039#[cfg(feature = "schemars")]
1040#[derive(schemars::JsonSchema)]
1041#[expect(dead_code, reason = "schema-only representation of request parameters")]
1042struct DiscoverRequestParamsSchema {
1043 #[schemars(rename = "_meta")]
1044 meta: RequestMetaObject,
1045}
1046
1047#[cfg(feature = "schemars")]
1048impl schemars::JsonSchema for DiscoverRequestParams {
1049 fn schema_name() -> Cow<'static, str> {
1050 Cow::Borrowed("DiscoverRequestParams")
1051 }
1052
1053 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
1054 DiscoverRequestParamsSchema::json_schema(generator)
1055 }
1056}
1057
1058pub type DiscoverRequest = Request<DiscoverRequestMethod, DiscoverRequestParams>;
1060
1061#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1063#[serde(rename_all = "camelCase")]
1064#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1065#[non_exhaustive]
1066pub struct DiscoverResult {
1067 pub result_type: ResultType,
1069 pub supported_versions: Vec<ProtocolVersion>,
1071 pub capabilities: ServerCapabilities,
1073 pub server_info: Implementation,
1075 #[serde(skip_serializing_if = "Option::is_none")]
1077 pub instructions: Option<String>,
1078 pub ttl_ms: u64,
1080 pub cache_scope: CacheScope,
1082 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1084 pub meta: Option<MetaObject>,
1085}
1086
1087impl DiscoverResult {
1088 pub fn new(
1090 supported_versions: Vec<ProtocolVersion>,
1091 capabilities: ServerCapabilities,
1092 server_info: Implementation,
1093 ) -> Self {
1094 Self {
1095 result_type: ResultType::COMPLETE,
1096 supported_versions,
1097 capabilities,
1098 server_info,
1099 instructions: None,
1100 ttl_ms: 0,
1101 cache_scope: CacheScope::Private,
1102 meta: None,
1103 }
1104 }
1105
1106 pub fn from_server_info(
1108 supported_versions: Vec<ProtocolVersion>,
1109 server_info: ServerInfo,
1110 ) -> Self {
1111 let ServerInfo {
1112 capabilities,
1113 server_info,
1114 instructions,
1115 meta,
1116 ..
1117 } = server_info;
1118 let mut result = Self::new(supported_versions, capabilities, server_info);
1119 result.instructions = instructions;
1120 result.meta = meta;
1121 result
1122 }
1123
1124 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1126 self.ttl_ms = ttl_ms;
1127 self
1128 }
1129
1130 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1132 self.cache_scope = cache_scope;
1133 self
1134 }
1135}
1136
1137#[allow(clippy::derivable_impls)]
1138impl Default for ServerInfo {
1139 fn default() -> Self {
1140 ServerInfo {
1141 protocol_version: ProtocolVersion::default(),
1142 capabilities: ServerCapabilities::default(),
1143 server_info: Implementation::from_build_env(),
1144 instructions: None,
1145 meta: None,
1146 }
1147 }
1148}
1149
1150#[allow(clippy::derivable_impls)]
1151impl Default for ClientInfo {
1152 fn default() -> Self {
1153 ClientInfo {
1154 meta: None,
1155 protocol_version: ProtocolVersion::default(),
1156 capabilities: ClientCapabilities::default(),
1157 client_info: Implementation::from_build_env(),
1158 }
1159 }
1160}
1161
1162#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
1164#[serde(rename_all = "lowercase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1166#[non_exhaustive]
1167pub enum IconTheme {
1168 Light,
1170 Dark,
1172}
1173
1174#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1184#[serde(rename_all = "camelCase")]
1185#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1186#[non_exhaustive]
1187pub struct Icon {
1188 pub src: String,
1190 #[serde(skip_serializing_if = "Option::is_none")]
1192 pub mime_type: Option<String>,
1193 #[serde(skip_serializing_if = "Option::is_none")]
1195 pub sizes: Option<Vec<String>>,
1196 #[serde(skip_serializing_if = "Option::is_none")]
1199 pub theme: Option<IconTheme>,
1200}
1201
1202impl Icon {
1203 pub fn new(src: impl Into<String>) -> Self {
1205 Self {
1206 src: src.into(),
1207 mime_type: None,
1208 sizes: None,
1209 theme: None,
1210 }
1211 }
1212
1213 pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
1215 self.mime_type = Some(mime_type.into());
1216 self
1217 }
1218
1219 pub fn with_sizes(mut self, sizes: Vec<String>) -> Self {
1221 self.sizes = Some(sizes);
1222 self
1223 }
1224
1225 pub fn with_theme(mut self, theme: IconTheme) -> Self {
1227 self.theme = Some(theme);
1228 self
1229 }
1230}
1231
1232#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1233#[serde(rename_all = "camelCase")]
1234#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1235#[non_exhaustive]
1236pub struct Implementation {
1237 pub name: String,
1238 #[serde(skip_serializing_if = "Option::is_none")]
1239 pub title: Option<String>,
1240 pub version: String,
1241 #[serde(skip_serializing_if = "Option::is_none")]
1242 pub description: Option<String>,
1243 #[serde(skip_serializing_if = "Option::is_none")]
1244 pub icons: Option<Vec<Icon>>,
1245 #[serde(skip_serializing_if = "Option::is_none")]
1246 pub website_url: Option<String>,
1247}
1248
1249impl Default for Implementation {
1250 fn default() -> Self {
1251 Self::from_build_env()
1252 }
1253}
1254
1255impl Implementation {
1256 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
1258 Self {
1259 name: name.into(),
1260 title: None,
1261 version: version.into(),
1262 description: None,
1263 icons: None,
1264 website_url: None,
1265 }
1266 }
1267
1268 pub fn from_build_env() -> Self {
1269 Implementation {
1270 name: env!("CARGO_CRATE_NAME").to_owned(),
1271 title: None,
1272 version: env!("CARGO_PKG_VERSION").to_owned(),
1273 description: None,
1274 icons: None,
1275 website_url: None,
1276 }
1277 }
1278
1279 pub fn with_title(mut self, title: impl Into<String>) -> Self {
1281 self.title = Some(title.into());
1282 self
1283 }
1284
1285 pub fn with_description(mut self, description: impl Into<String>) -> Self {
1287 self.description = Some(description.into());
1288 self
1289 }
1290
1291 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1293 self.icons = Some(icons);
1294 self
1295 }
1296
1297 pub fn with_website_url(mut self, website_url: impl Into<String>) -> Self {
1299 self.website_url = Some(website_url.into());
1300 self
1301 }
1302}
1303
1304#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1305#[serde(rename_all = "camelCase")]
1306#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1307#[non_exhaustive]
1308pub struct PaginatedRequestParams {
1309 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1311 pub meta: Option<RequestMetaObject>,
1312 #[serde(skip_serializing_if = "Option::is_none")]
1313 pub cursor: Option<String>,
1314}
1315
1316impl PaginatedRequestParams {
1317 pub fn with_cursor(mut self, cursor: Option<String>) -> Self {
1318 self.cursor = cursor;
1319 self
1320 }
1321}
1322
1323impl RequestParamsMeta for PaginatedRequestParams {
1324 fn meta(&self) -> Option<&RequestMetaObject> {
1325 self.meta.as_ref()
1326 }
1327 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1328 &mut self.meta
1329 }
1330}
1331
1332#[deprecated(since = "0.13.0", note = "Use PaginatedRequestParams instead")]
1334pub type PaginatedRequestParam = PaginatedRequestParams;
1335const_string!(PingRequestMethod = "ping");
1340pub type PingRequest = RequestNoParam<PingRequestMethod>;
1341
1342const_string!(ProgressNotificationMethod = "notifications/progress");
1343#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1344#[serde(rename_all = "camelCase")]
1345#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1346#[non_exhaustive]
1347pub struct ProgressNotificationParam {
1348 pub progress_token: ProgressToken,
1349 pub progress: f64,
1351 #[serde(skip_serializing_if = "Option::is_none")]
1353 pub total: Option<f64>,
1354 #[serde(skip_serializing_if = "Option::is_none")]
1356 pub message: Option<String>,
1357 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1358 pub meta: Option<NotificationMetaObject>,
1359}
1360
1361impl ProgressNotificationParam {
1362 pub fn new(progress_token: ProgressToken, progress: f64) -> Self {
1364 Self {
1365 progress_token,
1366 progress,
1367 total: None,
1368 message: None,
1369 meta: None,
1370 }
1371 }
1372
1373 pub fn with_total(mut self, total: f64) -> Self {
1375 self.total = Some(total);
1376 self
1377 }
1378
1379 pub fn with_message(mut self, message: impl Into<String>) -> Self {
1381 self.message = Some(message.into());
1382 self
1383 }
1384}
1385
1386pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;
1387
1388pub type Cursor = String;
1389
1390#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1394#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1395#[serde(rename_all = "lowercase")]
1396#[non_exhaustive]
1397pub enum CacheScope {
1398 #[default]
1400 Public,
1401 Private,
1403}
1404
1405fn deserialize_ttl_ms<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
1411where
1412 D: serde::Deserializer<'de>,
1413{
1414 let value = Option::<i64>::deserialize(deserializer)?;
1415 Ok(value.map(|ttl_ms| ttl_ms.max(0) as u64))
1416}
1417
1418macro_rules! paginated_result {
1419 ($t:ident {
1420 $i_item: ident: $t_item: ty
1421 }) => {
1422 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1423 #[serde(rename_all = "camelCase")]
1424 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1425 #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1426 pub struct $t {
1427 #[serde(default)]
1429 pub result_type: ResultType,
1430 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1431 pub meta: Option<MetaObject>,
1432 #[serde(default, skip_serializing_if = "Option::is_none")]
1433 pub next_cursor: Option<Cursor>,
1434 #[serde(
1438 default,
1439 deserialize_with = "deserialize_ttl_ms",
1440 skip_serializing_if = "Option::is_none"
1441 )]
1442 pub ttl_ms: Option<u64>,
1443 #[serde(default, skip_serializing_if = "Option::is_none")]
1447 pub cache_scope: Option<CacheScope>,
1448 pub $i_item: $t_item,
1449 }
1450
1451 impl $t {
1452 pub fn with_all_items(items: $t_item) -> Self {
1453 Self {
1454 result_type: ResultType::default(),
1455 meta: None,
1456 next_cursor: None,
1457 ttl_ms: None,
1458 cache_scope: None,
1459 $i_item: items,
1460 }
1461 }
1462
1463 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1465 self.ttl_ms = Some(ttl_ms);
1466 self
1467 }
1468
1469 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1471 self.cache_scope = Some(cache_scope);
1472 self
1473 }
1474 }
1475 };
1476}
1477
1478const_string!(ListResourcesRequestMethod = "resources/list");
1483pub type ListResourcesRequest =
1485 RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParams>;
1486
1487paginated_result!(ListResourcesResult {
1488 resources: Vec<Resource>
1489});
1490
1491const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
1492pub type ListResourceTemplatesRequest =
1494 RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParams>;
1495
1496paginated_result!(ListResourceTemplatesResult {
1497 resource_templates: Vec<ResourceTemplate>
1498});
1499
1500const_string!(ReadResourceRequestMethod = "resources/read");
1501#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1503#[serde(rename_all = "camelCase")]
1504#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1505#[non_exhaustive]
1506pub struct ReadResourceRequestParams {
1507 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1509 pub meta: Option<RequestMetaObject>,
1510 pub uri: String,
1512 #[serde(skip_serializing_if = "Option::is_none")]
1515 pub input_responses: Option<InputResponses>,
1516 #[serde(skip_serializing_if = "Option::is_none")]
1518 pub request_state: Option<String>,
1519}
1520
1521impl ReadResourceRequestParams {
1522 pub fn new(uri: impl Into<String>) -> Self {
1524 Self {
1525 meta: None,
1526 uri: uri.into(),
1527 input_responses: None,
1528 request_state: None,
1529 }
1530 }
1531
1532 pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
1534 self.meta = Some(meta);
1535 self
1536 }
1537
1538 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
1540 self.input_responses = Some(input_responses);
1541 self
1542 }
1543
1544 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
1546 self.request_state = Some(request_state.into());
1547 self
1548 }
1549}
1550
1551impl RequestParamsMeta for ReadResourceRequestParams {
1552 fn meta(&self) -> Option<&RequestMetaObject> {
1553 self.meta.as_ref()
1554 }
1555 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1556 &mut self.meta
1557 }
1558}
1559
1560#[deprecated(since = "0.13.0", note = "Use ReadResourceRequestParams instead")]
1562pub type ReadResourceRequestParam = ReadResourceRequestParams;
1563
1564#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1566#[serde(rename_all = "camelCase")]
1567#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1568#[non_exhaustive]
1569pub struct ReadResourceResult {
1570 #[serde(default)]
1572 pub result_type: ResultType,
1573 #[serde(
1577 default,
1578 deserialize_with = "deserialize_ttl_ms",
1579 skip_serializing_if = "Option::is_none"
1580 )]
1581 pub ttl_ms: Option<u64>,
1582 #[serde(default, skip_serializing_if = "Option::is_none")]
1586 pub cache_scope: Option<CacheScope>,
1587 pub contents: Vec<ResourceContents>,
1589 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1590 pub meta: Option<MetaObject>,
1591}
1592
1593impl ReadResourceResult {
1594 pub fn new(contents: Vec<ResourceContents>) -> Self {
1596 Self {
1597 result_type: ResultType::default(),
1598 ttl_ms: None,
1599 cache_scope: None,
1600 contents,
1601 meta: None,
1602 }
1603 }
1604
1605 pub fn with_ttl_ms(mut self, ttl_ms: u64) -> Self {
1607 self.ttl_ms = Some(ttl_ms);
1608 self
1609 }
1610
1611 pub fn with_cache_scope(mut self, cache_scope: CacheScope) -> Self {
1613 self.cache_scope = Some(cache_scope);
1614 self
1615 }
1616}
1617
1618pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParams>;
1620
1621const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
1622pub type ResourceListChangedNotification =
1624 NotificationNoParam<ResourceListChangedNotificationMethod>;
1625
1626const_string!(SubscribeRequestMethod = "resources/subscribe");
1627#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1629#[serde(rename_all = "camelCase")]
1630#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1631#[non_exhaustive]
1632pub struct SubscribeRequestParams {
1633 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1635 pub meta: Option<RequestMetaObject>,
1636 pub uri: String,
1638}
1639
1640impl SubscribeRequestParams {
1641 pub fn new(uri: impl Into<String>) -> Self {
1643 Self {
1644 meta: None,
1645 uri: uri.into(),
1646 }
1647 }
1648}
1649
1650impl RequestParamsMeta for SubscribeRequestParams {
1651 fn meta(&self) -> Option<&RequestMetaObject> {
1652 self.meta.as_ref()
1653 }
1654 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1655 &mut self.meta
1656 }
1657}
1658
1659#[deprecated(since = "0.13.0", note = "Use SubscribeRequestParams instead")]
1661pub type SubscribeRequestParam = SubscribeRequestParams;
1662
1663pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParams>;
1665
1666const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
1667#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1669#[serde(rename_all = "camelCase")]
1670#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1671#[non_exhaustive]
1672pub struct UnsubscribeRequestParams {
1673 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1675 pub meta: Option<RequestMetaObject>,
1676 pub uri: String,
1678}
1679
1680impl UnsubscribeRequestParams {
1681 pub fn new(uri: impl Into<String>) -> Self {
1683 Self {
1684 meta: None,
1685 uri: uri.into(),
1686 }
1687 }
1688}
1689
1690impl RequestParamsMeta for UnsubscribeRequestParams {
1691 fn meta(&self) -> Option<&RequestMetaObject> {
1692 self.meta.as_ref()
1693 }
1694 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1695 &mut self.meta
1696 }
1697}
1698
1699#[deprecated(since = "0.13.0", note = "Use UnsubscribeRequestParams instead")]
1701pub type UnsubscribeRequestParam = UnsubscribeRequestParams;
1702
1703pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParams>;
1705
1706const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
1707#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1709#[serde(rename_all = "camelCase")]
1710#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1711#[non_exhaustive]
1712pub struct ResourceUpdatedNotificationParam {
1713 pub uri: String,
1715 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1716 pub meta: Option<NotificationMetaObject>,
1717}
1718
1719impl ResourceUpdatedNotificationParam {
1720 pub fn new(uri: impl Into<String>) -> Self {
1722 Self {
1723 uri: uri.into(),
1724 meta: None,
1725 }
1726 }
1727}
1728
1729pub type ResourceUpdatedNotification =
1731 Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;
1732
1733const_string!(ListPromptsRequestMethod = "prompts/list");
1738pub type ListPromptsRequest =
1740 RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParams>;
1741
1742paginated_result!(ListPromptsResult {
1743 prompts: Vec<Prompt>
1744});
1745
1746const_string!(GetPromptRequestMethod = "prompts/get");
1747#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
1749#[serde(rename_all = "camelCase")]
1750#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1751#[non_exhaustive]
1752pub struct GetPromptRequestParams {
1753 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1755 pub meta: Option<RequestMetaObject>,
1756 pub name: String,
1757 #[serde(skip_serializing_if = "Option::is_none")]
1758 pub arguments: Option<JsonObject>,
1759 #[serde(skip_serializing_if = "Option::is_none")]
1762 pub input_responses: Option<InputResponses>,
1763 #[serde(skip_serializing_if = "Option::is_none")]
1765 pub request_state: Option<String>,
1766}
1767
1768impl GetPromptRequestParams {
1769 pub fn new(name: impl Into<String>) -> Self {
1771 Self {
1772 meta: None,
1773 name: name.into(),
1774 arguments: None,
1775 input_responses: None,
1776 request_state: None,
1777 }
1778 }
1779
1780 pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
1782 self.arguments = Some(arguments);
1783 self
1784 }
1785
1786 pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
1788 self.meta = Some(meta);
1789 self
1790 }
1791
1792 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
1794 self.input_responses = Some(input_responses);
1795 self
1796 }
1797
1798 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
1800 self.request_state = Some(request_state.into());
1801 self
1802 }
1803}
1804
1805impl RequestParamsMeta for GetPromptRequestParams {
1806 fn meta(&self) -> Option<&RequestMetaObject> {
1807 self.meta.as_ref()
1808 }
1809 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1810 &mut self.meta
1811 }
1812}
1813
1814#[deprecated(since = "0.13.0", note = "Use GetPromptRequestParams instead")]
1816pub type GetPromptRequestParam = GetPromptRequestParams;
1817
1818pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParams>;
1820
1821const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
1822pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;
1824
1825const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
1826pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;
1828
1829#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
1835#[serde(rename_all = "lowercase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1837#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
1838#[deprecated(
1839 since = "2.0.0",
1840 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1841)]
1842pub enum LoggingLevel {
1843 Debug,
1844 Info,
1845 Notice,
1846 Warning,
1847 Error,
1848 Critical,
1849 Alert,
1850 Emergency,
1851}
1852
1853const_string!(SetLevelRequestMethod = "logging/setLevel");
1854#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1856#[serde(rename_all = "camelCase")]
1857#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1858#[non_exhaustive]
1859#[deprecated(
1860 since = "2.0.0",
1861 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1862)]
1863pub struct SetLevelRequestParams {
1864 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1866 pub meta: Option<RequestMetaObject>,
1867 pub level: LoggingLevel,
1869}
1870
1871impl SetLevelRequestParams {
1872 pub fn new(level: LoggingLevel) -> Self {
1874 Self { meta: None, level }
1875 }
1876}
1877
1878impl RequestParamsMeta for SetLevelRequestParams {
1879 fn meta(&self) -> Option<&RequestMetaObject> {
1880 self.meta.as_ref()
1881 }
1882 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
1883 &mut self.meta
1884 }
1885}
1886
1887#[deprecated(since = "0.13.0", note = "Use SetLevelRequestParams instead")]
1889pub type SetLevelRequestParam = SetLevelRequestParams;
1890
1891#[deprecated(
1893 since = "2.0.0",
1894 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1895)]
1896pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParams>;
1897
1898const_string!(LoggingMessageNotificationMethod = "notifications/message");
1899#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1901#[serde(rename_all = "camelCase")]
1902#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1903#[non_exhaustive]
1904#[deprecated(
1905 since = "2.0.0",
1906 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1907)]
1908pub struct LoggingMessageNotificationParam {
1909 pub level: LoggingLevel,
1911 #[serde(skip_serializing_if = "Option::is_none")]
1913 pub logger: Option<String>,
1914 pub data: Value,
1916 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1917 pub meta: Option<NotificationMetaObject>,
1918}
1919
1920impl LoggingMessageNotificationParam {
1921 pub fn new(level: LoggingLevel, data: Value) -> Self {
1923 Self {
1924 level,
1925 logger: None,
1926 data,
1927 meta: None,
1928 }
1929 }
1930
1931 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
1933 self.logger = Some(logger.into());
1934 self
1935 }
1936}
1937
1938#[deprecated(
1940 since = "2.0.0",
1941 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1942)]
1943pub type LoggingMessageNotification =
1944 Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;
1945
1946const_string!(CreateMessageRequestMethod = "sampling/createMessage");
1951#[deprecated(
1952 since = "2.0.0",
1953 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1954)]
1955pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParams>;
1956
1957#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1962#[serde(rename_all = "camelCase")]
1963#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1964#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
1965pub enum Role {
1966 User,
1968 Assistant,
1970}
1971
1972#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1974#[serde(rename_all = "lowercase")]
1975#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1976#[non_exhaustive]
1977pub enum ToolChoiceMode {
1978 #[default]
1980 Auto,
1981 Required,
1983 None,
1985}
1986
1987#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1989#[serde(rename_all = "camelCase")]
1990#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1991#[non_exhaustive]
1992#[deprecated(
1993 since = "2.0.0",
1994 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
1995)]
1996pub struct ToolChoice {
1997 #[serde(skip_serializing_if = "Option::is_none")]
1998 pub mode: Option<ToolChoiceMode>,
1999}
2000
2001impl ToolChoice {
2002 pub fn auto() -> Self {
2003 Self {
2004 mode: Some(ToolChoiceMode::Auto),
2005 }
2006 }
2007
2008 pub fn required() -> Self {
2009 Self {
2010 mode: Some(ToolChoiceMode::Required),
2011 }
2012 }
2013
2014 pub fn none() -> Self {
2015 Self {
2016 mode: Some(ToolChoiceMode::None),
2017 }
2018 }
2019}
2020
2021#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2023#[serde(untagged)]
2024#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2025#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
2026pub enum SamplingContent<T> {
2027 Single(T),
2028 Multiple(Vec<T>),
2029}
2030
2031impl<T> SamplingContent<T> {
2032 pub fn into_vec(self) -> Vec<T> {
2034 match self {
2035 SamplingContent::Single(item) => vec![item],
2036 SamplingContent::Multiple(items) => items,
2037 }
2038 }
2039
2040 pub fn is_empty(&self) -> bool {
2042 match self {
2043 SamplingContent::Single(_) => false,
2044 SamplingContent::Multiple(items) => items.is_empty(),
2045 }
2046 }
2047
2048 pub fn len(&self) -> usize {
2050 match self {
2051 SamplingContent::Single(_) => 1,
2052 SamplingContent::Multiple(items) => items.len(),
2053 }
2054 }
2055}
2056
2057impl<T> Default for SamplingContent<T> {
2058 fn default() -> Self {
2059 SamplingContent::Multiple(Vec::new())
2060 }
2061}
2062
2063impl<T> SamplingContent<T> {
2064 pub fn first(&self) -> Option<&T> {
2066 match self {
2067 SamplingContent::Single(item) => Some(item),
2068 SamplingContent::Multiple(items) => items.first(),
2069 }
2070 }
2071
2072 pub fn iter(&self) -> impl Iterator<Item = &T> {
2074 let items: Vec<&T> = match self {
2075 SamplingContent::Single(item) => vec![item],
2076 SamplingContent::Multiple(items) => items.iter().collect(),
2077 };
2078 items.into_iter()
2079 }
2080}
2081
2082impl SamplingMessageContentBlock {
2083 pub fn as_text(&self) -> Option<&TextContent> {
2085 match self {
2086 SamplingMessageContentBlock::Text(text) => Some(text),
2087 _ => None,
2088 }
2089 }
2090
2091 pub fn as_tool_use(&self) -> Option<&ToolUseContent> {
2093 match self {
2094 SamplingMessageContentBlock::ToolUse(tool_use) => Some(tool_use),
2095 _ => None,
2096 }
2097 }
2098
2099 pub fn as_tool_result(&self) -> Option<&ToolResultContent> {
2101 match self {
2102 SamplingMessageContentBlock::ToolResult(tool_result) => Some(tool_result),
2103 _ => None,
2104 }
2105 }
2106}
2107
2108impl<T> From<T> for SamplingContent<T> {
2109 fn from(item: T) -> Self {
2110 SamplingContent::Single(item)
2111 }
2112}
2113
2114impl<T> From<Vec<T>> for SamplingContent<T> {
2115 fn from(items: Vec<T>) -> Self {
2116 SamplingContent::Multiple(items)
2117 }
2118}
2119
2120#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2126#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2127#[non_exhaustive]
2128#[deprecated(
2129 since = "2.0.0",
2130 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2131)]
2132pub struct SamplingMessage {
2133 pub role: Role,
2135 pub content: SamplingContent<SamplingMessageContentBlock>,
2137 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2138 pub meta: Option<MetaObject>,
2139}
2140
2141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2143#[serde(tag = "type", rename_all = "snake_case")]
2144#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2145#[non_exhaustive]
2146#[deprecated(
2147 since = "2.0.0",
2148 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2149)]
2150pub enum SamplingMessageContentBlock {
2151 Text(TextContent),
2152 Image(ImageContent),
2153 Audio(AudioContent),
2154 ToolUse(ToolUseContent),
2156 ToolResult(ToolResultContent),
2158}
2159
2160#[deprecated(since = "2.0.0", note = "Renamed to SamplingMessageContentBlock")]
2161pub type SamplingMessageContent = SamplingMessageContentBlock;
2162
2163impl SamplingMessageContentBlock {
2164 pub fn text(text: impl Into<String>) -> Self {
2166 Self::Text(TextContent::new(text))
2167 }
2168
2169 pub fn tool_use(id: impl Into<String>, name: impl Into<String>, input: JsonObject) -> Self {
2170 Self::ToolUse(ToolUseContent::new(id, name, input))
2171 }
2172
2173 pub fn tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2174 Self::ToolResult(ToolResultContent::new(tool_use_id, content))
2175 }
2176}
2177
2178impl SamplingMessage {
2179 pub fn new(role: Role, content: impl Into<SamplingMessageContentBlock>) -> Self {
2180 Self {
2181 role,
2182 content: SamplingContent::Single(content.into()),
2183 meta: None,
2184 }
2185 }
2186
2187 pub fn new_multiple(role: Role, contents: Vec<SamplingMessageContentBlock>) -> Self {
2188 Self {
2189 role,
2190 content: SamplingContent::Multiple(contents),
2191 meta: None,
2192 }
2193 }
2194
2195 pub fn user_text(text: impl Into<String>) -> Self {
2196 Self::new(Role::User, SamplingMessageContentBlock::text(text))
2197 }
2198
2199 pub fn assistant_text(text: impl Into<String>) -> Self {
2200 Self::new(Role::Assistant, SamplingMessageContentBlock::text(text))
2201 }
2202
2203 pub fn user_tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
2204 Self::new(
2205 Role::User,
2206 SamplingMessageContentBlock::tool_result(tool_use_id, content),
2207 )
2208 }
2209
2210 pub fn assistant_tool_use(
2211 id: impl Into<String>,
2212 name: impl Into<String>,
2213 input: JsonObject,
2214 ) -> Self {
2215 Self::new(
2216 Role::Assistant,
2217 SamplingMessageContentBlock::tool_use(id, name, input),
2218 )
2219 }
2220}
2221
2222impl From<TextContent> for SamplingMessageContentBlock {
2223 fn from(text: TextContent) -> Self {
2224 SamplingMessageContentBlock::Text(text)
2225 }
2226}
2227
2228impl From<String> for SamplingMessageContentBlock {
2230 fn from(text: String) -> Self {
2231 SamplingMessageContentBlock::text(text)
2232 }
2233}
2234
2235impl From<&str> for SamplingMessageContentBlock {
2236 fn from(text: &str) -> Self {
2237 SamplingMessageContentBlock::text(text)
2238 }
2239}
2240
2241impl TryFrom<ContentBlock> for SamplingMessageContentBlock {
2242 type Error = &'static str;
2243
2244 fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2245 match content {
2246 ContentBlock::Text(text) => Ok(SamplingMessageContentBlock::Text(text)),
2247 ContentBlock::Image(image) => Ok(SamplingMessageContentBlock::Image(image)),
2248 ContentBlock::Audio(audio) => Ok(SamplingMessageContentBlock::Audio(audio)),
2249 ContentBlock::Resource(_) => {
2250 Err("Resource content is not supported in sampling messages")
2251 }
2252 ContentBlock::ResourceLink(_) => {
2253 Err("ResourceLink content is not supported in sampling messages")
2254 }
2255 }
2256 }
2257}
2258
2259impl TryFrom<ContentBlock> for SamplingContent<SamplingMessageContentBlock> {
2260 type Error = &'static str;
2261
2262 fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
2263 Ok(SamplingContent::Single(content.try_into()?))
2264 }
2265}
2266
2267#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2272#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2273#[non_exhaustive]
2274pub enum ContextInclusion {
2275 #[serde(rename = "allServers")]
2277 AllServers,
2278 #[serde(rename = "none")]
2280 None,
2281 #[serde(rename = "thisServer")]
2283 ThisServer,
2284}
2285
2286#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
2295#[serde(rename_all = "camelCase")]
2296#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2297#[non_exhaustive]
2298#[deprecated(
2299 since = "2.0.0",
2300 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2301)]
2302pub struct CreateMessageRequestParams {
2303 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2305 pub meta: Option<RequestMetaObject>,
2306 #[serde(skip_serializing_if = "Option::is_none")]
2308 pub task: Option<TaskMetadata>,
2309 pub messages: Vec<SamplingMessage>,
2311 #[serde(skip_serializing_if = "Option::is_none")]
2313 pub model_preferences: Option<ModelPreferences>,
2314 #[serde(skip_serializing_if = "Option::is_none")]
2316 pub system_prompt: Option<String>,
2317 #[serde(skip_serializing_if = "Option::is_none")]
2319 pub include_context: Option<ContextInclusion>,
2320 #[serde(skip_serializing_if = "Option::is_none")]
2322 pub temperature: Option<f32>,
2323 pub max_tokens: u32,
2325 #[serde(skip_serializing_if = "Option::is_none")]
2327 pub stop_sequences: Option<Vec<String>>,
2328 #[serde(skip_serializing_if = "Option::is_none")]
2330 pub metadata: Option<Value>,
2331 #[serde(skip_serializing_if = "Option::is_none")]
2333 pub tools: Option<Vec<Tool>>,
2334 #[serde(skip_serializing_if = "Option::is_none")]
2336 pub tool_choice: Option<ToolChoice>,
2337}
2338
2339impl RequestParamsMeta for CreateMessageRequestParams {
2340 fn meta(&self) -> Option<&RequestMetaObject> {
2341 self.meta.as_ref()
2342 }
2343 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2344 &mut self.meta
2345 }
2346}
2347
2348impl TaskAugmentedRequestParamsMeta for CreateMessageRequestParams {
2349 fn task(&self) -> Option<&TaskMetadata> {
2350 self.task.as_ref()
2351 }
2352 fn task_mut(&mut self) -> &mut Option<TaskMetadata> {
2353 &mut self.task
2354 }
2355}
2356
2357impl CreateMessageRequestParams {
2358 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
2360 Self {
2361 meta: None,
2362 task: None,
2363 messages,
2364 model_preferences: None,
2365 system_prompt: None,
2366 include_context: None,
2367 temperature: None,
2368 max_tokens,
2369 stop_sequences: None,
2370 metadata: None,
2371 tools: None,
2372 tool_choice: None,
2373 }
2374 }
2375
2376 pub fn with_model_preferences(mut self, model_preferences: ModelPreferences) -> Self {
2378 self.model_preferences = Some(model_preferences);
2379 self
2380 }
2381
2382 pub fn with_system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
2384 self.system_prompt = Some(system_prompt.into());
2385 self
2386 }
2387
2388 pub fn with_include_context(mut self, include_context: ContextInclusion) -> Self {
2390 self.include_context = Some(include_context);
2391 self
2392 }
2393
2394 pub fn with_temperature(mut self, temperature: f32) -> Self {
2396 self.temperature = Some(temperature);
2397 self
2398 }
2399
2400 pub fn with_stop_sequences(mut self, stop_sequences: Vec<String>) -> Self {
2402 self.stop_sequences = Some(stop_sequences);
2403 self
2404 }
2405
2406 pub fn with_metadata(mut self, metadata: Value) -> Self {
2408 self.metadata = Some(metadata);
2409 self
2410 }
2411
2412 pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
2414 self.tools = Some(tools);
2415 self
2416 }
2417
2418 pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
2420 self.tool_choice = Some(tool_choice);
2421 self
2422 }
2423
2424 pub fn validate(&self) -> Result<(), String> {
2432 for msg in &self.messages {
2433 for content in msg.content.iter() {
2434 match content {
2436 SamplingMessageContentBlock::ToolUse(_) if msg.role != Role::Assistant => {
2437 return Err("ToolUse content is only allowed in assistant messages".into());
2438 }
2439 SamplingMessageContentBlock::ToolResult(_) if msg.role != Role::User => {
2440 return Err("ToolResult content is only allowed in user messages".into());
2441 }
2442 _ => {}
2443 }
2444 }
2445
2446 let contents: Vec<_> = msg.content.iter().collect();
2448 let has_tool_result = contents
2449 .iter()
2450 .any(|c| matches!(c, SamplingMessageContentBlock::ToolResult(_)));
2451 if has_tool_result
2452 && contents
2453 .iter()
2454 .any(|c| !matches!(c, SamplingMessageContentBlock::ToolResult(_)))
2455 {
2456 return Err(
2457 "SamplingMessage with tool result content MUST NOT contain other content types"
2458 .into(),
2459 );
2460 }
2461 }
2462
2463 self.validate_tool_use_result_balance()?;
2465
2466 Ok(())
2467 }
2468
2469 fn validate_tool_use_result_balance(&self) -> Result<(), String> {
2470 let mut pending_tool_use_ids: Vec<String> = Vec::new();
2471 for msg in &self.messages {
2472 if msg.role == Role::Assistant {
2473 for content in msg.content.iter() {
2474 if let SamplingMessageContentBlock::ToolUse(tu) = content {
2475 pending_tool_use_ids.push(tu.id.clone());
2476 }
2477 }
2478 } else if msg.role == Role::User {
2479 for content in msg.content.iter() {
2480 if let SamplingMessageContentBlock::ToolResult(tr) = content {
2481 if !pending_tool_use_ids.contains(&tr.tool_use_id) {
2482 return Err(format!(
2483 "ToolResult with toolUseId '{}' has no matching ToolUse",
2484 tr.tool_use_id
2485 ));
2486 }
2487 pending_tool_use_ids.retain(|id| id != &tr.tool_use_id);
2488 }
2489 }
2490 }
2491 }
2492 if !pending_tool_use_ids.is_empty() {
2493 return Err(format!(
2494 "ToolUse with id(s) {:?} not balanced with ToolResult",
2495 pending_tool_use_ids
2496 ));
2497 }
2498 Ok(())
2499 }
2500}
2501
2502#[deprecated(since = "0.13.0", note = "Use CreateMessageRequestParams instead")]
2504pub type CreateMessageRequestParam = CreateMessageRequestParams;
2505
2506#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2512#[serde(rename_all = "camelCase")]
2513#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2514#[non_exhaustive]
2515#[deprecated(
2516 since = "2.0.0",
2517 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2518)]
2519pub struct ModelPreferences {
2520 #[serde(skip_serializing_if = "Option::is_none")]
2522 pub hints: Option<Vec<ModelHint>>,
2523 #[serde(skip_serializing_if = "Option::is_none")]
2525 pub cost_priority: Option<f32>,
2526 #[serde(skip_serializing_if = "Option::is_none")]
2528 pub speed_priority: Option<f32>,
2529 #[serde(skip_serializing_if = "Option::is_none")]
2531 pub intelligence_priority: Option<f32>,
2532}
2533
2534impl ModelPreferences {
2535 pub fn new() -> Self {
2537 Self {
2538 hints: None,
2539 cost_priority: None,
2540 speed_priority: None,
2541 intelligence_priority: None,
2542 }
2543 }
2544
2545 pub fn with_hints(mut self, hints: Vec<ModelHint>) -> Self {
2547 self.hints = Some(hints);
2548 self
2549 }
2550
2551 pub fn with_cost_priority(mut self, cost_priority: f32) -> Self {
2553 self.cost_priority = Some(cost_priority);
2554 self
2555 }
2556
2557 pub fn with_speed_priority(mut self, speed_priority: f32) -> Self {
2559 self.speed_priority = Some(speed_priority);
2560 self
2561 }
2562
2563 pub fn with_intelligence_priority(mut self, intelligence_priority: f32) -> Self {
2565 self.intelligence_priority = Some(intelligence_priority);
2566 self
2567 }
2568}
2569
2570impl Default for ModelPreferences {
2571 fn default() -> Self {
2572 Self::new()
2573 }
2574}
2575
2576#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
2581#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2582#[non_exhaustive]
2583#[deprecated(
2584 since = "2.0.0",
2585 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2586)]
2587pub struct ModelHint {
2588 #[serde(skip_serializing_if = "Option::is_none")]
2590 pub name: Option<String>,
2591}
2592
2593impl ModelHint {
2594 pub fn new(name: impl Into<String>) -> Self {
2596 Self {
2597 name: Some(name.into()),
2598 }
2599 }
2600}
2601
2602#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
2611#[serde(rename_all = "camelCase")]
2612#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2613#[non_exhaustive]
2614pub struct CompletionContext {
2615 #[serde(skip_serializing_if = "Option::is_none")]
2617 pub arguments: Option<std::collections::HashMap<String, String>>,
2618}
2619
2620impl CompletionContext {
2621 pub fn new() -> Self {
2623 Self::default()
2624 }
2625
2626 pub fn with_arguments(arguments: std::collections::HashMap<String, String>) -> Self {
2628 Self {
2629 arguments: Some(arguments),
2630 }
2631 }
2632
2633 pub fn get_argument(&self, name: &str) -> Option<&String> {
2635 self.arguments.as_ref()?.get(name)
2636 }
2637
2638 pub fn has_arguments(&self) -> bool {
2640 self.arguments.as_ref().is_some_and(|args| !args.is_empty())
2641 }
2642
2643 pub fn argument_names(&self) -> impl Iterator<Item = &str> {
2645 self.arguments
2646 .as_ref()
2647 .into_iter()
2648 .flat_map(|args| args.keys())
2649 .map(|k| k.as_str())
2650 }
2651}
2652
2653#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2654#[serde(rename_all = "camelCase")]
2655#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2656#[non_exhaustive]
2657pub struct CompleteRequestParams {
2658 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2660 pub meta: Option<RequestMetaObject>,
2661 pub r#ref: Reference,
2662 pub argument: ArgumentInfo,
2663 #[serde(skip_serializing_if = "Option::is_none")]
2665 pub context: Option<CompletionContext>,
2666}
2667
2668impl CompleteRequestParams {
2669 pub fn new(r#ref: Reference, argument: ArgumentInfo) -> Self {
2671 Self {
2672 meta: None,
2673 r#ref,
2674 argument,
2675 context: None,
2676 }
2677 }
2678
2679 pub fn with_context(mut self, context: CompletionContext) -> Self {
2681 self.context = Some(context);
2682 self
2683 }
2684}
2685
2686impl RequestParamsMeta for CompleteRequestParams {
2687 fn meta(&self) -> Option<&RequestMetaObject> {
2688 self.meta.as_ref()
2689 }
2690 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
2691 &mut self.meta
2692 }
2693}
2694
2695#[deprecated(since = "0.13.0", note = "Use CompleteRequestParams instead")]
2697pub type CompleteRequestParam = CompleteRequestParams;
2698
2699pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParams>;
2700
2701#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
2702#[serde(rename_all = "camelCase")]
2703#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2704#[non_exhaustive]
2705pub struct CompletionInfo {
2706 pub values: Vec<String>,
2707 #[serde(skip_serializing_if = "Option::is_none")]
2708 pub total: Option<u32>,
2709 #[serde(skip_serializing_if = "Option::is_none")]
2710 pub has_more: Option<bool>,
2711}
2712
2713impl CompletionInfo {
2714 pub const MAX_VALUES: usize = 100;
2716
2717 pub fn new(values: Vec<String>) -> Result<Self, String> {
2719 if values.len() > Self::MAX_VALUES {
2720 return Err(format!(
2721 "Too many completion values: {} (max: {})",
2722 values.len(),
2723 Self::MAX_VALUES
2724 ));
2725 }
2726 Ok(Self {
2727 values,
2728 total: None,
2729 has_more: None,
2730 })
2731 }
2732
2733 pub fn with_all_values(values: Vec<String>) -> Result<Self, String> {
2735 let completion = Self::new(values)?;
2736 Ok(Self {
2737 total: Some(completion.values.len() as u32),
2738 has_more: Some(false),
2739 ..completion
2740 })
2741 }
2742
2743 pub fn with_pagination(
2745 values: Vec<String>,
2746 total: Option<u32>,
2747 has_more: bool,
2748 ) -> Result<Self, String> {
2749 let completion = Self::new(values)?;
2750 Ok(Self {
2751 total,
2752 has_more: Some(has_more),
2753 ..completion
2754 })
2755 }
2756
2757 pub fn has_more_results(&self) -> bool {
2759 self.has_more.unwrap_or(false)
2760 }
2761
2762 pub fn total_available(&self) -> Option<u32> {
2764 self.total
2765 }
2766
2767 pub fn validate(&self) -> Result<(), String> {
2769 if self.values.len() > Self::MAX_VALUES {
2770 return Err(format!(
2771 "Too many completion values: {} (max: {})",
2772 self.values.len(),
2773 Self::MAX_VALUES
2774 ));
2775 }
2776 Ok(())
2777 }
2778}
2779
2780#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
2781#[serde(rename_all = "camelCase")]
2782#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2783#[non_exhaustive]
2784pub struct CompleteResult {
2785 #[serde(default)]
2787 pub result_type: ResultType,
2788 pub completion: CompletionInfo,
2789 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2790 pub meta: Option<MetaObject>,
2791}
2792
2793impl CompleteResult {
2794 pub fn new(completion: CompletionInfo) -> Self {
2796 Self {
2797 result_type: ResultType::default(),
2798 completion,
2799 meta: None,
2800 }
2801 }
2802}
2803
2804#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2805#[serde(tag = "type")]
2806#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2807#[non_exhaustive]
2808pub enum Reference {
2809 #[serde(rename = "ref/resource")]
2810 Resource(ResourceTemplateReference),
2811 #[serde(rename = "ref/prompt")]
2812 Prompt(PromptReference),
2813}
2814
2815impl Reference {
2816 pub fn for_prompt(name: impl Into<String>) -> Self {
2818 Self::Prompt(PromptReference {
2822 name: name.into(),
2823 title: None,
2824 })
2825 }
2826
2827 pub fn for_resource(uri: impl Into<String>) -> Self {
2829 Self::Resource(ResourceTemplateReference { uri: uri.into() })
2830 }
2831
2832 pub fn reference_type(&self) -> &'static str {
2834 match self {
2835 Self::Prompt(_) => "ref/prompt",
2836 Self::Resource(_) => "ref/resource",
2837 }
2838 }
2839
2840 pub fn as_prompt_name(&self) -> Option<&str> {
2842 match self {
2843 Self::Prompt(prompt_ref) => Some(&prompt_ref.name),
2844 _ => None,
2845 }
2846 }
2847
2848 pub fn as_resource_uri(&self) -> Option<&str> {
2850 match self {
2851 Self::Resource(resource_ref) => Some(&resource_ref.uri),
2852 _ => None,
2853 }
2854 }
2855}
2856
2857#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2858#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2859#[non_exhaustive]
2860pub struct ResourceTemplateReference {
2861 pub uri: String,
2862}
2863
2864impl ResourceTemplateReference {
2865 pub fn new(uri: impl Into<String>) -> Self {
2866 Self { uri: uri.into() }
2867 }
2868}
2869
2870#[deprecated(since = "2.0.0", note = "Renamed to ResourceTemplateReference")]
2871pub type ResourceReference = ResourceTemplateReference;
2872
2873#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2874#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2875#[non_exhaustive]
2876pub struct PromptReference {
2877 pub name: String,
2878 #[serde(skip_serializing_if = "Option::is_none")]
2879 pub title: Option<String>,
2880}
2881
2882impl PromptReference {
2883 pub fn new(name: impl Into<String>) -> Self {
2885 Self {
2886 name: name.into(),
2887 title: None,
2888 }
2889 }
2890
2891 pub fn with_title(mut self, title: impl Into<String>) -> Self {
2893 self.title = Some(title.into());
2894 self
2895 }
2896}
2897
2898const_string!(CompleteRequestMethod = "completion/complete");
2899#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2900#[serde(rename_all = "camelCase")]
2901#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2902#[non_exhaustive]
2903pub struct ArgumentInfo {
2904 pub name: String,
2905 pub value: String,
2906}
2907
2908impl ArgumentInfo {
2909 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2910 Self {
2911 name: name.into(),
2912 value: value.into(),
2913 }
2914 }
2915}
2916
2917#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2922#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2923#[non_exhaustive]
2924#[deprecated(
2925 since = "2.0.0",
2926 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2927)]
2928pub struct Root {
2929 pub uri: String,
2930 #[serde(skip_serializing_if = "Option::is_none")]
2931 pub name: Option<String>,
2932 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2933 pub meta: Option<MetaObject>,
2934}
2935
2936impl Root {
2937 pub fn new(uri: impl Into<String>) -> Self {
2939 Self {
2940 uri: uri.into(),
2941 name: None,
2942 meta: None,
2943 }
2944 }
2945
2946 pub fn with_name(mut self, name: impl Into<String>) -> Self {
2948 self.name = Some(name.into());
2949 self
2950 }
2951
2952 pub fn with_meta(mut self, meta: MetaObject) -> Self {
2954 self.meta = Some(meta);
2955 self
2956 }
2957}
2958
2959const_string!(ListRootsRequestMethod = "roots/list");
2960#[deprecated(
2961 since = "2.0.0",
2962 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2963)]
2964pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;
2965
2966#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
2967#[serde(rename_all = "camelCase")]
2968#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2969#[non_exhaustive]
2970#[deprecated(
2971 since = "2.0.0",
2972 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
2973)]
2974pub struct ListRootsResult {
2975 pub roots: Vec<Root>,
2976 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
2977 pub meta: Option<MetaObject>,
2978}
2979
2980impl ListRootsResult {
2981 pub fn new(roots: Vec<Root>) -> Self {
2983 Self { roots, meta: None }
2984 }
2985
2986 pub fn with_meta(mut self, meta: MetaObject) -> Self {
2988 self.meta = Some(meta);
2989 self
2990 }
2991}
2992
2993const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
2994pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
2995
2996const_string!(ElicitationCreateRequestMethod = "elicitation/create");
3003const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
3004
3005#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
3012#[serde(rename_all = "lowercase")]
3013#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3014#[non_exhaustive]
3015pub enum ElicitationAction {
3016 Accept,
3018 Decline,
3020 Cancel,
3022}
3023
3024#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3027#[serde(tag = "mode")]
3028#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3029enum CreateElicitationRequestParamDeserializeHelper {
3030 #[serde(rename = "form", rename_all = "camelCase")]
3031 FormElicitationParam {
3032 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3033 meta: Option<RequestMetaObject>,
3034 message: String,
3035 requested_schema: ElicitationSchema,
3036 },
3037 #[serde(rename = "url", rename_all = "camelCase")]
3038 UrlElicitationParam {
3039 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3040 meta: Option<RequestMetaObject>,
3041 message: String,
3042 url: String,
3043 elicitation_id: String,
3044 },
3045 #[serde(untagged, rename_all = "camelCase")]
3046 FormElicitationParamBackwardsCompat {
3047 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3048 meta: Option<RequestMetaObject>,
3049 message: String,
3050 requested_schema: ElicitationSchema,
3051 },
3052}
3053
3054impl TryFrom<CreateElicitationRequestParamDeserializeHelper> for ElicitRequestParams {
3055 type Error = serde_json::Error;
3056
3057 fn try_from(
3058 value: CreateElicitationRequestParamDeserializeHelper,
3059 ) -> Result<Self, Self::Error> {
3060 match value {
3061 CreateElicitationRequestParamDeserializeHelper::FormElicitationParam {
3062 meta,
3063 message,
3064 requested_schema,
3065 }
3066 | CreateElicitationRequestParamDeserializeHelper::FormElicitationParamBackwardsCompat {
3067 meta,
3068 message,
3069 requested_schema,
3070 } => Ok(ElicitRequestParams::FormElicitationParams {
3071 meta,
3072 message,
3073 requested_schema,
3074 }),
3075 CreateElicitationRequestParamDeserializeHelper::UrlElicitationParam {
3076 meta,
3077 message,
3078 url,
3079 elicitation_id,
3080 } => Ok(ElicitRequestParams::UrlElicitationParams {
3081 meta,
3082 message,
3083 url,
3084 elicitation_id,
3085 }),
3086 }
3087 }
3088}
3089
3090#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3121#[serde(
3122 tag = "mode",
3123 try_from = "CreateElicitationRequestParamDeserializeHelper"
3124)]
3125#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3126#[non_exhaustive]
3127pub enum ElicitRequestParams {
3128 #[serde(rename = "form", rename_all = "camelCase")]
3129 FormElicitationParams {
3130 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3132 meta: Option<RequestMetaObject>,
3133 message: String,
3137
3138 requested_schema: ElicitationSchema,
3142 },
3143 #[serde(rename = "url", rename_all = "camelCase")]
3144 UrlElicitationParams {
3145 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3147 meta: Option<RequestMetaObject>,
3148 message: String,
3152
3153 url: String,
3156 elicitation_id: String,
3158 },
3159}
3160
3161impl RequestParamsMeta for ElicitRequestParams {
3162 fn meta(&self) -> Option<&RequestMetaObject> {
3163 match self {
3164 ElicitRequestParams::FormElicitationParams { meta, .. } => meta.as_ref(),
3165 ElicitRequestParams::UrlElicitationParams { meta, .. } => meta.as_ref(),
3166 }
3167 }
3168 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3169 match self {
3170 ElicitRequestParams::FormElicitationParams { meta, .. } => meta,
3171 ElicitRequestParams::UrlElicitationParams { meta, .. } => meta,
3172 }
3173 }
3174}
3175
3176#[deprecated(since = "0.13.0", note = "Use ElicitRequestParams instead")]
3178pub type CreateElicitationRequestParam = ElicitRequestParams;
3179
3180#[deprecated(since = "2.0.0", note = "Renamed to ElicitRequestParams")]
3181pub type CreateElicitationRequestParams = ElicitRequestParams;
3182
3183#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3188#[serde(rename_all = "camelCase")]
3189#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3190#[non_exhaustive]
3191pub struct ElicitResult {
3192 pub action: ElicitationAction,
3194
3195 #[serde(skip_serializing_if = "Option::is_none")]
3199 pub content: Option<Value>,
3200
3201 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3203 pub meta: Option<MetaObject>,
3204}
3205
3206impl ElicitResult {
3207 pub fn new(action: ElicitationAction) -> Self {
3209 Self {
3210 action,
3211 content: None,
3212 meta: None,
3213 }
3214 }
3215
3216 pub fn with_content(mut self, content: Value) -> Self {
3218 self.content = Some(content);
3219 self
3220 }
3221
3222 pub fn with_meta(mut self, meta: MetaObject) -> Self {
3224 self.meta = Some(meta);
3225 self
3226 }
3227}
3228
3229#[deprecated(since = "2.0.0", note = "Renamed to ElicitResult")]
3230pub type CreateElicitationResult = ElicitResult;
3231
3232pub type ElicitRequest = Request<ElicitationCreateRequestMethod, ElicitRequestParams>;
3234
3235#[deprecated(since = "2.0.0", note = "Renamed to ElicitRequest")]
3236pub type CreateElicitationRequest = ElicitRequest;
3237
3238#[derive(Default, Debug, Serialize, Clone, PartialEq)]
3247#[serde(rename_all = "camelCase")]
3248#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3249#[non_exhaustive]
3250pub struct CallToolResult {
3251 #[serde(default)]
3253 pub result_type: ResultType,
3254 #[serde(default)]
3256 pub content: Vec<ContentBlock>,
3257 #[serde(skip_serializing_if = "Option::is_none")]
3259 pub structured_content: Option<Value>,
3260 #[serde(skip_serializing_if = "Option::is_none")]
3262 pub is_error: Option<bool>,
3263 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3265 pub meta: Option<MetaObject>,
3266}
3267
3268impl<'de> Deserialize<'de> for CallToolResult {
3274 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3275 where
3276 D: serde::Deserializer<'de>,
3277 {
3278 #[derive(Deserialize)]
3279 #[serde(rename_all = "camelCase")]
3280 struct Helper {
3281 #[serde(default)]
3282 result_type: ResultType,
3283 content: Option<Vec<ContentBlock>>,
3284 structured_content: Option<Value>,
3285 is_error: Option<bool>,
3286 #[serde(rename = "_meta")]
3287 meta: Option<MetaObject>,
3288 }
3289
3290 let helper = Helper::deserialize(deserializer)?;
3291
3292 if helper.content.is_none()
3293 && helper.structured_content.is_none()
3294 && helper.is_error.is_none()
3295 && helper.meta.is_none()
3296 {
3297 return Err(serde::de::Error::custom(
3298 "expected at least one known CallToolResult field \
3299 (content, structuredContent, isError, or _meta)",
3300 ));
3301 }
3302
3303 Ok(CallToolResult {
3304 result_type: helper.result_type,
3305 content: helper.content.unwrap_or_default(),
3306 structured_content: helper.structured_content,
3307 is_error: helper.is_error,
3308 meta: helper.meta,
3309 })
3310 }
3311}
3312
3313impl CallToolResult {
3314 pub fn success(content: Vec<ContentBlock>) -> Self {
3316 CallToolResult {
3317 result_type: ResultType::default(),
3318 content,
3319 structured_content: None,
3320 is_error: Some(false),
3321 meta: None,
3322 }
3323 }
3324
3325 pub fn error(content: Vec<ContentBlock>) -> Self {
3374 CallToolResult {
3375 result_type: ResultType::default(),
3376 content,
3377 structured_content: None,
3378 is_error: Some(true),
3379 meta: None,
3380 }
3381 }
3382 pub fn structured(value: Value) -> Self {
3397 CallToolResult {
3398 result_type: ResultType::default(),
3399 content: vec![ContentBlock::text(value.to_string())],
3400 structured_content: Some(value),
3401 is_error: Some(false),
3402 meta: None,
3403 }
3404 }
3405 pub fn structured_error(value: Value) -> Self {
3424 CallToolResult {
3425 result_type: ResultType::default(),
3426 content: vec![ContentBlock::text(value.to_string())],
3427 structured_content: Some(value),
3428 is_error: Some(true),
3429 meta: None,
3430 }
3431 }
3432
3433 pub fn with_meta(mut self, meta: Option<MetaObject>) -> Self {
3435 self.meta = meta;
3436 self
3437 }
3438
3439 pub fn into_typed<T>(self) -> Result<T, serde_json::Error>
3446 where
3447 T: DeserializeOwned,
3448 {
3449 let raw_text = match (self.structured_content, &self.content.first()) {
3450 (Some(value), _) => return serde_json::from_value(value),
3451 (None, Some(contents)) => {
3452 if let Some(text) = contents.as_text() {
3453 let text = &text.text;
3454 Some(text)
3455 } else {
3456 None
3457 }
3458 }
3459 (None, None) => None,
3460 };
3461 if let Some(text) = raw_text {
3462 return serde_json::from_str(text);
3463 }
3464 serde_json::from_value(serde_json::Value::Null)
3465 }
3466}
3467
3468const_string!(ListToolsRequestMethod = "tools/list");
3469pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParams>;
3471
3472paginated_result!(
3473 ListToolsResult {
3474 tools: Vec<Tool>
3475 }
3476);
3477
3478const_string!(CallToolRequestMethod = "tools/call");
3479#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
3487#[serde(rename_all = "camelCase")]
3488#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3489#[non_exhaustive]
3490pub struct CallToolRequestParams {
3491 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3493 pub meta: Option<RequestMetaObject>,
3494 pub name: Cow<'static, str>,
3496 #[serde(skip_serializing_if = "Option::is_none")]
3498 pub arguments: Option<JsonObject>,
3499 #[serde(skip_serializing_if = "Option::is_none")]
3501 pub task: Option<TaskMetadata>,
3502 #[serde(skip_serializing_if = "Option::is_none")]
3505 pub input_responses: Option<InputResponses>,
3506 #[serde(skip_serializing_if = "Option::is_none")]
3509 pub request_state: Option<String>,
3510}
3511
3512impl CallToolRequestParams {
3513 pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
3515 Self {
3516 meta: None,
3517 name: name.into(),
3518 arguments: None,
3519 task: None,
3520 input_responses: None,
3521 request_state: None,
3522 }
3523 }
3524
3525 pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
3527 self.arguments = Some(arguments);
3528 self
3529 }
3530
3531 pub fn with_task(mut self, task: TaskMetadata) -> Self {
3533 self.task = Some(task);
3534 self
3535 }
3536
3537 pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
3539 self.input_responses = Some(input_responses);
3540 self
3541 }
3542
3543 pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
3545 self.request_state = Some(request_state.into());
3546 self
3547 }
3548}
3549
3550impl RequestParamsMeta for CallToolRequestParams {
3551 fn meta(&self) -> Option<&RequestMetaObject> {
3552 self.meta.as_ref()
3553 }
3554 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3555 &mut self.meta
3556 }
3557}
3558
3559impl TaskAugmentedRequestParamsMeta for CallToolRequestParams {
3560 fn task(&self) -> Option<&TaskMetadata> {
3561 self.task.as_ref()
3562 }
3563 fn task_mut(&mut self) -> &mut Option<TaskMetadata> {
3564 &mut self.task
3565 }
3566}
3567
3568#[deprecated(since = "0.13.0", note = "Use CallToolRequestParams instead")]
3570pub type CallToolRequestParam = CallToolRequestParams;
3571
3572pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParams>;
3574
3575#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3581#[serde(rename_all = "camelCase")]
3582#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3583#[non_exhaustive]
3584#[deprecated(
3585 since = "2.0.0",
3586 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
3587)]
3588pub struct CreateMessageResult {
3589 pub model: String,
3591 #[serde(skip_serializing_if = "Option::is_none")]
3593 pub stop_reason: Option<String>,
3594 #[serde(flatten)]
3596 pub message: SamplingMessage,
3597}
3598
3599impl CreateMessageResult {
3600 pub fn new(message: SamplingMessage, model: String) -> Self {
3602 Self {
3603 message,
3604 model,
3605 stop_reason: None,
3606 }
3607 }
3608
3609 pub const STOP_REASON_END_TURN: &str = "endTurn";
3610 pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
3611 pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
3612 pub const STOP_REASON_TOOL_USE: &str = "toolUse";
3613
3614 pub fn with_stop_reason(mut self, stop_reason: impl Into<String>) -> Self {
3616 self.stop_reason = Some(stop_reason.into());
3617 self
3618 }
3619
3620 pub fn with_model(mut self, model: impl Into<String>) -> Self {
3622 self.model = model.into();
3623 self
3624 }
3625
3626 pub fn validate(&self) -> Result<(), String> {
3628 if self.message.role != Role::Assistant {
3629 return Err("CreateMessageResult role must be 'assistant'".into());
3630 }
3631 Ok(())
3632 }
3633}
3634
3635#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
3636#[serde(rename_all = "camelCase")]
3637#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3638#[non_exhaustive]
3639pub struct GetPromptResult {
3640 #[serde(default)]
3642 pub result_type: ResultType,
3643 #[serde(skip_serializing_if = "Option::is_none")]
3644 pub description: Option<String>,
3645 pub messages: Vec<PromptMessage>,
3646 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3647 pub meta: Option<MetaObject>,
3648}
3649
3650impl GetPromptResult {
3651 pub fn new(messages: Vec<PromptMessage>) -> Self {
3653 Self {
3654 result_type: ResultType::default(),
3655 description: None,
3656 messages,
3657 meta: None,
3658 }
3659 }
3660
3661 pub fn with_description<D: Into<String>>(mut self, description: D) -> Self {
3663 self.description = Some(description.into());
3664 self
3665 }
3666}
3667
3668const_string!(GetTaskMethod = "tasks/get");
3673pub type GetTaskRequest = Request<GetTaskMethod, GetTaskParams>;
3674
3675#[deprecated(since = "2.0.0", note = "Renamed to GetTaskMethod")]
3676pub type GetTaskInfoMethod = GetTaskMethod;
3677#[deprecated(since = "2.0.0", note = "Renamed to GetTaskRequest")]
3678pub type GetTaskInfoRequest = GetTaskRequest;
3679
3680#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3681#[serde(rename_all = "camelCase")]
3682#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3683#[non_exhaustive]
3684pub struct GetTaskParams {
3685 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3687 pub meta: Option<RequestMetaObject>,
3688 pub task_id: String,
3689}
3690
3691impl GetTaskParams {
3692 pub fn new(task_id: impl Into<String>) -> Self {
3693 Self {
3694 meta: None,
3695 task_id: task_id.into(),
3696 }
3697 }
3698}
3699
3700impl RequestParamsMeta for GetTaskParams {
3701 fn meta(&self) -> Option<&RequestMetaObject> {
3702 self.meta.as_ref()
3703 }
3704 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3705 &mut self.meta
3706 }
3707}
3708
3709#[deprecated(since = "2.0.0", note = "Renamed to GetTaskParams")]
3710pub type GetTaskInfoParams = GetTaskParams;
3711
3712#[deprecated(since = "0.13.0", note = "Use GetTaskParams instead")]
3713pub type GetTaskInfoParam = GetTaskParams;
3714
3715const_string!(ListTasksMethod = "tasks/list");
3716pub type ListTasksRequest = RequestOptionalParam<ListTasksMethod, PaginatedRequestParams>;
3717
3718const_string!(GetTaskPayloadMethod = "tasks/result");
3719pub type GetTaskPayloadRequest = Request<GetTaskPayloadMethod, GetTaskPayloadParams>;
3720
3721#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadMethod")]
3722pub type GetTaskResultMethod = GetTaskPayloadMethod;
3723#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadRequest")]
3724pub type GetTaskResultRequest = GetTaskPayloadRequest;
3725
3726#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3727#[serde(rename_all = "camelCase")]
3728#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3729#[non_exhaustive]
3730pub struct GetTaskPayloadParams {
3731 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3733 pub meta: Option<RequestMetaObject>,
3734 pub task_id: String,
3735}
3736
3737impl GetTaskPayloadParams {
3738 pub fn new(task_id: impl Into<String>) -> Self {
3739 Self {
3740 meta: None,
3741 task_id: task_id.into(),
3742 }
3743 }
3744}
3745
3746impl RequestParamsMeta for GetTaskPayloadParams {
3747 fn meta(&self) -> Option<&RequestMetaObject> {
3748 self.meta.as_ref()
3749 }
3750 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3751 &mut self.meta
3752 }
3753}
3754
3755#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadParams")]
3756pub type GetTaskResultParams = GetTaskPayloadParams;
3757#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadParams")]
3758pub type GetTaskResultParam = GetTaskPayloadParams;
3759
3760const_string!(CancelTaskMethod = "tasks/cancel");
3761pub type CancelTaskRequest = Request<CancelTaskMethod, CancelTaskParams>;
3762
3763#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
3764#[serde(rename_all = "camelCase")]
3765#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3766#[non_exhaustive]
3767pub struct CancelTaskParams {
3768 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3770 pub meta: Option<RequestMetaObject>,
3771 pub task_id: String,
3772}
3773
3774impl CancelTaskParams {
3775 pub fn new(task_id: impl Into<String>) -> Self {
3776 Self {
3777 meta: None,
3778 task_id: task_id.into(),
3779 }
3780 }
3781}
3782
3783impl RequestParamsMeta for CancelTaskParams {
3784 fn meta(&self) -> Option<&RequestMetaObject> {
3785 self.meta.as_ref()
3786 }
3787 fn meta_mut(&mut self) -> &mut Option<RequestMetaObject> {
3788 &mut self.meta
3789 }
3790}
3791
3792#[deprecated(since = "0.13.0", note = "Use CancelTaskParams instead")]
3794pub type CancelTaskParam = CancelTaskParams;
3795
3796const_string!(TaskStatusNotificationMethod = "notifications/tasks/status");
3800
3801#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
3805#[serde(rename_all = "camelCase")]
3806#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3807#[non_exhaustive]
3808pub struct TaskStatusNotificationParam {
3809 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3810 pub meta: Option<NotificationMetaObject>,
3811 #[serde(flatten)]
3812 pub task: crate::model::Task,
3813}
3814
3815impl TaskStatusNotificationParam {
3816 pub fn new(task: crate::model::Task) -> Self {
3817 Self { meta: None, task }
3818 }
3819
3820 pub fn with_meta(mut self, meta: NotificationMetaObject) -> Self {
3821 self.meta = Some(meta);
3822 self
3823 }
3824}
3825
3826impl From<crate::model::Task> for TaskStatusNotificationParam {
3827 fn from(task: crate::model::Task) -> Self {
3828 Self::new(task)
3829 }
3830}
3831
3832impl Deref for TaskStatusNotificationParam {
3833 type Target = crate::model::Task;
3834
3835 fn deref(&self) -> &Self::Target {
3836 &self.task
3837 }
3838}
3839
3840impl DerefMut for TaskStatusNotificationParam {
3841 fn deref_mut(&mut self) -> &mut Self::Target {
3842 &mut self.task
3843 }
3844}
3845
3846pub type TaskStatusNotification =
3847 Notification<TaskStatusNotificationMethod, TaskStatusNotificationParam>;
3848#[deprecated(since = "0.15.0", note = "Use GetTaskResult instead")]
3850pub type GetTaskInfoResult = GetTaskResult;
3851
3852#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
3853#[serde(rename_all = "camelCase")]
3854#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3855#[non_exhaustive]
3856pub struct ListTasksResult {
3857 pub tasks: Vec<crate::model::Task>,
3858 #[serde(skip_serializing_if = "Option::is_none")]
3859 pub next_cursor: Option<String>,
3860 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
3861 pub meta: Option<MetaObject>,
3862}
3863
3864impl ListTasksResult {
3865 pub fn new(tasks: Vec<crate::model::Task>) -> Self {
3866 Self {
3867 tasks,
3868 next_cursor: None,
3869 meta: None,
3870 }
3871 }
3872}
3873
3874macro_rules! ts_union {
3879 (
3880 export type $U:ident =
3881 $($rest:tt)*
3882 ) => {
3883 ts_union!(@declare $U { $($rest)* });
3884 ts_union!(@impl_from $U { $($rest)* });
3885 };
3886 (@declare $U:ident { $($variant:tt)* }) => {
3887 ts_union!(@declare_variant $U { } {$($variant)*} );
3888 };
3889 (@declare_variant $U:ident { $($declared:tt)* } {$(|)? box $V:ident $($rest:tt)*}) => {
3890 ts_union!(@declare_variant $U { $($declared)* $V(Box<$V>), } {$($rest)*});
3891 };
3892 (@declare_variant $U:ident { $($declared:tt)* } {$(|)? $V:ident $($rest:tt)*}) => {
3893 ts_union!(@declare_variant $U { $($declared)* $V($V), } {$($rest)*});
3894 };
3895 (@declare_variant $U:ident { $($declared:tt)* } { ; }) => {
3896 ts_union!(@declare_end $U { $($declared)* } );
3897 };
3898 (@declare_end $U:ident { $($declared:tt)* }) => {
3899 #[derive(Debug, Serialize, Deserialize, Clone)]
3900 #[serde(untagged)]
3901 #[allow(clippy::large_enum_variant)]
3902 #[non_exhaustive]
3903 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3904 pub enum $U {
3905 $($declared)*
3906 }
3907 };
3908 (@impl_from $U: ident {$(|)? box $V:ident $($rest:tt)*}) => {
3909 impl From<$V> for $U {
3910 fn from(value: $V) -> Self {
3911 $U::$V(Box::new(value))
3912 }
3913 }
3914 ts_union!(@impl_from $U {$($rest)*});
3915 };
3916 (@impl_from $U: ident {$(|)? $V:ident $($rest:tt)*}) => {
3917 impl From<$V> for $U {
3918 fn from(value: $V) -> Self {
3919 $U::$V(value)
3920 }
3921 }
3922 ts_union!(@impl_from $U {$($rest)*});
3923 };
3924 (@impl_from $U: ident { ; }) => {};
3925 (@impl_from $U: ident { }) => {};
3926}
3927
3928ts_union!(
3929 export type ClientRequest =
3930 | PingRequest
3931 | InitializeRequest
3932 | DiscoverRequest
3933 | CompleteRequest
3934 | SetLevelRequest
3935 | GetPromptRequest
3936 | ListPromptsRequest
3937 | ListResourcesRequest
3938 | ListResourceTemplatesRequest
3939 | ReadResourceRequest
3940 | SubscribeRequest
3941 | UnsubscribeRequest
3942 | CallToolRequest
3943 | ListToolsRequest
3944 | GetTaskRequest
3945 | ListTasksRequest
3946 | GetTaskPayloadRequest
3947 | CancelTaskRequest
3948 | CustomRequest;
3949);
3950
3951impl ClientRequest {
3952 pub fn method(&self) -> &str {
3953 match &self {
3954 ClientRequest::PingRequest(r) => r.method.as_str(),
3955 ClientRequest::InitializeRequest(r) => r.method.as_str(),
3956 ClientRequest::DiscoverRequest(r) => r.method.as_str(),
3957 ClientRequest::CompleteRequest(r) => r.method.as_str(),
3958 ClientRequest::SetLevelRequest(r) => r.method.as_str(),
3959 ClientRequest::GetPromptRequest(r) => r.method.as_str(),
3960 ClientRequest::ListPromptsRequest(r) => r.method.as_str(),
3961 ClientRequest::ListResourcesRequest(r) => r.method.as_str(),
3962 ClientRequest::ListResourceTemplatesRequest(r) => r.method.as_str(),
3963 ClientRequest::ReadResourceRequest(r) => r.method.as_str(),
3964 ClientRequest::SubscribeRequest(r) => r.method.as_str(),
3965 ClientRequest::UnsubscribeRequest(r) => r.method.as_str(),
3966 ClientRequest::CallToolRequest(r) => r.method.as_str(),
3967 ClientRequest::ListToolsRequest(r) => r.method.as_str(),
3968 ClientRequest::GetTaskRequest(r) => r.method.as_str(),
3969 ClientRequest::ListTasksRequest(r) => r.method.as_str(),
3970 ClientRequest::GetTaskPayloadRequest(r) => r.method.as_str(),
3971 ClientRequest::CancelTaskRequest(r) => r.method.as_str(),
3972 ClientRequest::CustomRequest(r) => r.method.as_str(),
3973 }
3974 }
3975}
3976
3977ts_union!(
3978 export type ClientNotification =
3979 | CancelledNotification
3980 | ProgressNotification
3981 | InitializedNotification
3982 | RootsListChangedNotification
3983 | TaskStatusNotification
3984 | CustomNotification;
3985);
3986
3987ts_union!(
3988 export type ClientResult =
3989 box CreateMessageResult
3990 | ListRootsResult
3991 | ElicitResult
3992 | EmptyResult
3993 | CustomResult;
3994);
3995
3996impl ClientResult {
3997 pub fn empty(_: ()) -> ClientResult {
3998 ClientResult::EmptyResult(EmptyResult {})
3999 }
4000}
4001
4002pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;
4003
4004ts_union!(
4005 export type ServerRequest =
4006 | PingRequest
4007 | CreateMessageRequest
4008 | ListRootsRequest
4009 | ElicitRequest
4010 | CustomRequest;
4011);
4012
4013ts_union!(
4014 export type ServerNotification =
4015 | CancelledNotification
4016 | ProgressNotification
4017 | LoggingMessageNotification
4018 | ResourceUpdatedNotification
4019 | ResourceListChangedNotification
4020 | ToolListChangedNotification
4021 | PromptListChangedNotification
4022 | TaskStatusNotification
4023 | CustomNotification;
4024);
4025
4026ts_union!(
4027 export type ServerResult =
4028 | DiscoverResult
4029 | InitializeResult
4030 | CompleteResult
4031 | GetPromptResult
4032 | ListPromptsResult
4033 | ListResourcesResult
4034 | ListResourceTemplatesResult
4035 | ReadResourceResult
4036 | ListToolsResult
4037 | ElicitResult
4038 | CreateTaskResult
4039 | ListTasksResult
4040 | GetTaskResult
4041 | CancelTaskResult
4042 | CallToolResult
4043 | InputRequiredResult
4044 | GetTaskPayloadResult
4045 | EmptyResult
4046 | CustomResult
4047 ;
4048);
4049
4050impl ServerResult {
4051 pub fn empty(_: ()) -> ServerResult {
4052 ServerResult::EmptyResult(EmptyResult {})
4053 }
4054}
4055
4056pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;
4057
4058impl TryInto<CancelledNotification> for ServerNotification {
4059 type Error = ServerNotification;
4060 fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4061 if let ServerNotification::CancelledNotification(t) = self {
4062 Ok(t)
4063 } else {
4064 Err(self)
4065 }
4066 }
4067}
4068
4069impl TryInto<CancelledNotification> for ClientNotification {
4070 type Error = ClientNotification;
4071 fn try_into(self) -> Result<CancelledNotification, Self::Error> {
4072 if let ClientNotification::CancelledNotification(t) = self {
4073 Ok(t)
4074 } else {
4075 Err(self)
4076 }
4077 }
4078}
4079
4080#[cfg(test)]
4085mod tests {
4086 use serde_json::json;
4087
4088 use super::*;
4089
4090 #[test]
4091 #[allow(deprecated)]
4092 fn deprecated_aliases_still_resolve() {
4093 let _: CreateElicitationResult = ElicitResult::new(ElicitationAction::Accept);
4095 let _: GetTaskResultParams = GetTaskPayloadParams::new("task-1");
4096 let _: ResourceReference = ResourceTemplateReference::new("res://x");
4097 }
4098
4099 #[test]
4100 fn cancelled_notification_request_id_is_optional_on_wire() {
4101 let p = CancelledNotificationParam::new(None, Some("user cancelled".into()));
4103 let v = serde_json::to_value(&p).unwrap();
4104 assert!(v.get("requestId").is_none());
4105
4106 let p = CancelledNotificationParam::new(Some(RequestId::Number(1)), None);
4108 let v = serde_json::to_value(&p).unwrap();
4109 assert_eq!(v["requestId"], json!(1));
4110 let back: CancelledNotificationParam = serde_json::from_value(v).unwrap();
4111 assert_eq!(back.request_id, Some(RequestId::Number(1)));
4112 }
4113
4114 #[test]
4115 fn test_notification_serde() {
4116 let raw = json!( {
4117 "jsonrpc": JsonRpcVersion2_0,
4118 "method": InitializedNotificationMethod,
4119 });
4120 let message: ClientJsonRpcMessage =
4121 serde_json::from_value(raw.clone()).expect("invalid notification");
4122 match &message {
4123 ClientJsonRpcMessage::Notification(JsonRpcNotification {
4124 notification: ClientNotification::InitializedNotification(_n),
4125 ..
4126 }) => {}
4127 _ => panic!("Expected Notification"),
4128 }
4129 let json = serde_json::to_value(message).expect("valid json");
4130 assert_eq!(json, raw);
4131 }
4132
4133 #[test]
4134 fn test_custom_client_notification_roundtrip() {
4135 let raw = json!( {
4136 "jsonrpc": JsonRpcVersion2_0,
4137 "method": "notifications/custom",
4138 "params": {"foo": "bar"},
4139 });
4140
4141 let message: ClientJsonRpcMessage =
4142 serde_json::from_value(raw.clone()).expect("invalid notification");
4143 match &message {
4144 ClientJsonRpcMessage::Notification(JsonRpcNotification {
4145 notification: ClientNotification::CustomNotification(notification),
4146 ..
4147 }) => {
4148 assert_eq!(notification.method, "notifications/custom");
4149 assert_eq!(
4150 notification
4151 .params
4152 .as_ref()
4153 .and_then(|p| p.get("foo"))
4154 .expect("foo present"),
4155 "bar"
4156 );
4157 }
4158 _ => panic!("Expected custom client notification"),
4159 }
4160
4161 let json = serde_json::to_value(message).expect("valid json");
4162 assert_eq!(json, raw);
4163 }
4164
4165 #[test]
4166 fn test_custom_server_notification_roundtrip() {
4167 let raw = json!( {
4168 "jsonrpc": JsonRpcVersion2_0,
4169 "method": "notifications/custom-server",
4170 "params": {"hello": "world"},
4171 });
4172
4173 let message: ServerJsonRpcMessage =
4174 serde_json::from_value(raw.clone()).expect("invalid notification");
4175 match &message {
4176 ServerJsonRpcMessage::Notification(JsonRpcNotification {
4177 notification: ServerNotification::CustomNotification(notification),
4178 ..
4179 }) => {
4180 assert_eq!(notification.method, "notifications/custom-server");
4181 assert_eq!(
4182 notification
4183 .params
4184 .as_ref()
4185 .and_then(|p| p.get("hello"))
4186 .expect("hello present"),
4187 "world"
4188 );
4189 }
4190 _ => panic!("Expected custom server notification"),
4191 }
4192
4193 let json = serde_json::to_value(message).expect("valid json");
4194 assert_eq!(json, raw);
4195 }
4196
4197 #[test]
4198 fn test_custom_request_roundtrip() {
4199 let raw = json!( {
4200 "jsonrpc": JsonRpcVersion2_0,
4201 "id": 42,
4202 "method": "requests/custom",
4203 "params": {"foo": "bar"},
4204 });
4205
4206 let message: ClientJsonRpcMessage =
4207 serde_json::from_value(raw.clone()).expect("invalid request");
4208 match &message {
4209 ClientJsonRpcMessage::Request(JsonRpcRequest { id, request, .. }) => {
4210 assert_eq!(id, &RequestId::Number(42));
4211 match request {
4212 ClientRequest::CustomRequest(custom) => {
4213 let expected_request = json!({
4214 "method": "requests/custom",
4215 "params": {"foo": "bar"},
4216 });
4217 let actual_request =
4218 serde_json::to_value(custom).expect("serialize custom request");
4219 assert_eq!(actual_request, expected_request);
4220 }
4221 other => panic!("Expected custom request, got: {other:?}"),
4222 }
4223 }
4224 other => panic!("Expected request, got: {other:?}"),
4225 }
4226
4227 let json = serde_json::to_value(message).expect("valid json");
4228 assert_eq!(json, raw);
4229 }
4230
4231 #[test]
4232 fn test_request_conversion() {
4233 let raw = json!( {
4234 "jsonrpc": JsonRpcVersion2_0,
4235 "id": 1,
4236 "method": "request",
4237 "params": {"key": "value"},
4238 });
4239 let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");
4240
4241 match &message {
4242 JsonRpcMessage::Request(r) => {
4243 assert_eq!(r.id, RequestId::Number(1));
4244 assert_eq!(r.request.method, "request");
4245 assert_eq!(
4246 &r.request.params,
4247 json!({"key": "value"})
4248 .as_object()
4249 .expect("should be an object")
4250 );
4251 }
4252 _ => panic!("Expected Request"),
4253 }
4254 let json = serde_json::to_value(&message).expect("valid json");
4255 assert_eq!(json, raw);
4256 }
4257
4258 #[test]
4259 fn test_initial_request_response_serde() {
4260 let request = json!({
4261 "jsonrpc": "2.0",
4262 "id": 1,
4263 "method": "initialize",
4264 "params": {
4265 "protocolVersion": "2024-11-05",
4266 "capabilities": {
4267 "roots": {
4268 "listChanged": true
4269 },
4270 "sampling": {}
4271 },
4272 "clientInfo": {
4273 "name": "ExampleClient",
4274 "version": "1.0.0"
4275 }
4276 }
4277 });
4278 let raw_response_json = json!({
4279 "jsonrpc": "2.0",
4280 "id": 1,
4281 "result": {
4282 "protocolVersion": "2024-11-05",
4283 "capabilities": {
4284 "logging": {},
4285 "prompts": {
4286 "listChanged": true
4287 },
4288 "resources": {
4289 "subscribe": true,
4290 "listChanged": true
4291 },
4292 "tools": {
4293 "listChanged": true
4294 }
4295 },
4296 "serverInfo": {
4297 "name": "ExampleServer",
4298 "version": "1.0.0"
4299 }
4300 }
4301 });
4302 let request: ClientJsonRpcMessage =
4303 serde_json::from_value(request.clone()).expect("invalid request");
4304 let (request, id) = request.into_request().expect("should be a request");
4305 assert_eq!(id, RequestId::Number(1));
4306 #[allow(deprecated)]
4307 match request {
4308 ClientRequest::InitializeRequest(Request {
4309 method: _,
4310 params:
4311 InitializeRequestParam {
4312 meta: _,
4313 protocol_version: _,
4314 capabilities,
4315 client_info,
4316 },
4317 ..
4318 }) => {
4319 assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
4320 let sampling = capabilities.sampling.unwrap();
4321 assert_eq!(sampling.tools, None);
4322 assert_eq!(sampling.context, None);
4323 assert_eq!(client_info.name, "ExampleClient");
4324 assert_eq!(client_info.version, "1.0.0");
4325 }
4326 _ => panic!("Expected InitializeRequest"),
4327 }
4328 let server_response: ServerJsonRpcMessage =
4329 serde_json::from_value(raw_response_json.clone()).expect("invalid response");
4330 let (response, id) = server_response
4331 .clone()
4332 .into_response()
4333 .expect("expect response");
4334 assert_eq!(id, RequestId::Number(1));
4335 match response {
4336 ServerResult::InitializeResult(InitializeResult {
4337 protocol_version: _,
4338 capabilities,
4339 server_info,
4340 instructions,
4341 ..
4342 }) => {
4343 assert_eq!(capabilities.logging.unwrap().len(), 0);
4344 assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
4345 assert_eq!(
4346 capabilities.resources.as_ref().unwrap().subscribe,
4347 Some(true)
4348 );
4349 assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
4350 assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
4351 assert_eq!(server_info.name, "ExampleServer");
4352 assert_eq!(server_info.version, "1.0.0");
4353 assert_eq!(server_info.icons, None);
4354 assert_eq!(instructions, None);
4355 }
4356 other => panic!("Expected InitializeResult, got {other:?}"),
4357 }
4358
4359 let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");
4360
4361 assert_eq!(server_response_json, raw_response_json);
4362 }
4363
4364 #[test]
4365 fn test_negative_and_large_request_ids() {
4366 let negative_id_json = json!({
4368 "jsonrpc": "2.0",
4369 "id": -1,
4370 "method": "test",
4371 "params": {}
4372 });
4373
4374 let message: JsonRpcMessage =
4375 serde_json::from_value(negative_id_json.clone()).expect("Should parse negative ID");
4376
4377 match &message {
4378 JsonRpcMessage::Request(r) => {
4379 assert_eq!(r.id, RequestId::Number(-1));
4380 }
4381 _ => panic!("Expected Request"),
4382 }
4383
4384 let serialized = serde_json::to_value(&message).expect("Should serialize");
4386 assert_eq!(serialized, negative_id_json);
4387
4388 let large_negative_json = json!({
4390 "jsonrpc": "2.0",
4391 "id": -9007199254740991i64, "method": "test",
4393 "params": {}
4394 });
4395
4396 let message: JsonRpcMessage = serde_json::from_value(large_negative_json.clone())
4397 .expect("Should parse large negative ID");
4398
4399 match &message {
4400 JsonRpcMessage::Request(r) => {
4401 assert_eq!(r.id, RequestId::Number(-9007199254740991i64));
4402 }
4403 _ => panic!("Expected Request"),
4404 }
4405
4406 let large_positive_json = json!({
4408 "jsonrpc": "2.0",
4409 "id": 9007199254740991i64,
4410 "method": "test",
4411 "params": {}
4412 });
4413
4414 let message: JsonRpcMessage = serde_json::from_value(large_positive_json.clone())
4415 .expect("Should parse large positive ID");
4416
4417 match &message {
4418 JsonRpcMessage::Request(r) => {
4419 assert_eq!(r.id, RequestId::Number(9007199254740991i64));
4420 }
4421 _ => panic!("Expected Request"),
4422 }
4423
4424 let zero_id_json = json!({
4426 "jsonrpc": "2.0",
4427 "id": 0,
4428 "method": "test",
4429 "params": {}
4430 });
4431
4432 let message: JsonRpcMessage =
4433 serde_json::from_value(zero_id_json.clone()).expect("Should parse zero ID");
4434
4435 match &message {
4436 JsonRpcMessage::Request(r) => {
4437 assert_eq!(r.id, RequestId::Number(0));
4438 }
4439 _ => panic!("Expected Request"),
4440 }
4441 }
4442
4443 #[test]
4444 fn test_protocol_version_order() {
4445 let v1 = ProtocolVersion::V_2024_11_05;
4446 let v2 = ProtocolVersion::V_2025_03_26;
4447 let v3 = ProtocolVersion::V_2025_06_18;
4448 let v4 = ProtocolVersion::V_2025_11_25;
4449 assert!(v1 < v2);
4450 assert!(v2 < v3);
4451 assert!(v3 < v4);
4452 }
4453
4454 #[test]
4455 fn test_icon_serialization() {
4456 let icon = Icon {
4457 src: "https://example.com/icon.png".to_string(),
4458 mime_type: Some("image/png".to_string()),
4459 sizes: Some(vec!["48x48".to_string()]),
4460 theme: Some(IconTheme::Light),
4461 };
4462
4463 let json = serde_json::to_value(&icon).unwrap();
4464 assert_eq!(json["src"], "https://example.com/icon.png");
4465 assert_eq!(json["mimeType"], "image/png");
4466 assert_eq!(json["sizes"][0], "48x48");
4467 assert_eq!(json["theme"], "light");
4468
4469 let deserialized: Icon = serde_json::from_value(json).unwrap();
4471 assert_eq!(deserialized, icon);
4472 }
4473
4474 #[test]
4475 fn test_icon_minimal() {
4476 let icon = Icon {
4477 src: "data:image/svg+xml;base64,PHN2Zy8+".to_string(),
4478 mime_type: None,
4479 sizes: None,
4480 theme: None,
4481 };
4482
4483 let json = serde_json::to_value(&icon).unwrap();
4484 assert_eq!(json["src"], "data:image/svg+xml;base64,PHN2Zy8+");
4485 assert!(json.get("mimeType").is_none());
4486 assert!(json.get("sizes").is_none());
4487 assert!(json.get("theme").is_none());
4488 }
4489
4490 #[test]
4491 fn test_implementation_with_icons() {
4492 let implementation = Implementation {
4493 name: "test-server".to_string(),
4494 title: Some("Test Server".to_string()),
4495 version: "1.0.0".to_string(),
4496 description: Some("A test server for unit testing".to_string()),
4497 icons: Some(vec![
4498 Icon {
4499 src: "https://example.com/icon.png".to_string(),
4500 mime_type: Some("image/png".to_string()),
4501 sizes: Some(vec!["48x48".to_string()]),
4502 theme: Some(IconTheme::Dark),
4503 },
4504 Icon {
4505 src: "https://example.com/icon.svg".to_string(),
4506 mime_type: Some("image/svg+xml".to_string()),
4507 sizes: Some(vec!["any".to_string()]),
4508 theme: Some(IconTheme::Light),
4509 },
4510 ]),
4511 website_url: Some("https://example.com".to_string()),
4512 };
4513
4514 let json = serde_json::to_value(&implementation).unwrap();
4515 assert_eq!(json["name"], "test-server");
4516 assert_eq!(json["description"], "A test server for unit testing");
4517 assert_eq!(json["websiteUrl"], "https://example.com");
4518 assert!(json["icons"].is_array());
4519 assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png");
4520 assert_eq!(json["icons"][0]["sizes"][0], "48x48");
4521 assert_eq!(json["icons"][1]["mimeType"], "image/svg+xml");
4522 assert_eq!(json["icons"][1]["sizes"][0], "any");
4523 assert_eq!(json["icons"][0]["theme"], "dark");
4524 assert_eq!(json["icons"][1]["theme"], "light");
4525 }
4526
4527 #[test]
4528 fn test_backward_compatibility() {
4529 let old_json = json!({
4531 "name": "legacy-server",
4532 "version": "0.9.0"
4533 });
4534
4535 let implementation: Implementation = serde_json::from_value(old_json).unwrap();
4536 assert_eq!(implementation.name, "legacy-server");
4537 assert_eq!(implementation.version, "0.9.0");
4538 assert_eq!(implementation.description, None);
4539 assert_eq!(implementation.icons, None);
4540 assert_eq!(implementation.website_url, None);
4541 }
4542
4543 #[test]
4544 fn test_initialize_with_icons() {
4545 let init_result = InitializeResult {
4546 protocol_version: ProtocolVersion::default(),
4547 capabilities: ServerCapabilities::default(),
4548 server_info: Implementation {
4549 name: "icon-server".to_string(),
4550 title: None,
4551 version: "2.0.0".to_string(),
4552 description: None,
4553 icons: Some(vec![Icon {
4554 src: "https://example.com/server.png".to_string(),
4555 mime_type: Some("image/png".to_string()),
4556 sizes: Some(vec!["48x48".to_string()]),
4557 theme: Some(IconTheme::Light),
4558 }]),
4559 website_url: Some("https://docs.example.com".to_string()),
4560 },
4561 instructions: None,
4562 meta: None,
4563 };
4564
4565 let json = serde_json::to_value(&init_result).unwrap();
4566 assert!(json["serverInfo"]["icons"].is_array());
4567 assert_eq!(
4568 json["serverInfo"]["icons"][0]["src"],
4569 "https://example.com/server.png"
4570 );
4571 assert_eq!(json["serverInfo"]["icons"][0]["sizes"][0], "48x48");
4572 assert_eq!(json["serverInfo"]["icons"][0]["theme"], "light");
4573 assert_eq!(json["serverInfo"]["websiteUrl"], "https://docs.example.com");
4574 }
4575
4576 #[test]
4577 fn test_elicitation_deserialization_untagged() {
4578 let json_data_without_tag = json!({
4580 "message": "Please provide more details.",
4581 "requestedSchema": {
4582 "title": "User Details",
4583 "type": "object",
4584 "properties": {
4585 "name": { "type": "string" },
4586 "age": { "type": "integer" }
4587 },
4588 "required": ["name", "age"]
4589 }
4590 });
4591 let elicitation: ElicitRequestParams =
4592 serde_json::from_value(json_data_without_tag).expect("Deserialization failed");
4593 if let ElicitRequestParams::FormElicitationParams {
4594 meta,
4595 message,
4596 requested_schema,
4597 } = elicitation
4598 {
4599 assert_eq!(meta, None);
4600 assert_eq!(message, "Please provide more details.");
4601 assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
4602 assert_eq!(requested_schema.type_, ObjectTypeConst);
4603 } else {
4604 panic!("Expected FormElicitationParam");
4605 }
4606 }
4607
4608 #[test]
4609 fn test_elicitation_deserialization() {
4610 let json_data_form = json!({
4611 "_meta": { "meta_form_key_1": "meta form value 1" },
4612 "mode": "form",
4613 "message": "Please provide more details.",
4614 "requestedSchema": {
4615 "title": "User Details",
4616 "type": "object",
4617 "properties": {
4618 "name": { "type": "string" },
4619 "age": { "type": "integer" }
4620 },
4621 "required": ["name", "age"]
4622 }
4623 });
4624 let elicitation_form: ElicitRequestParams =
4625 serde_json::from_value(json_data_form).expect("Deserialization failed");
4626 if let ElicitRequestParams::FormElicitationParams {
4627 meta,
4628 message,
4629 requested_schema,
4630 } = elicitation_form
4631 {
4632 assert_eq!(
4633 meta,
4634 Some(RequestMetaObject(MetaObject(
4635 object!({ "meta_form_key_1": "meta form value 1" })
4636 )))
4637 );
4638 assert_eq!(message, "Please provide more details.");
4639 assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
4640 assert_eq!(requested_schema.type_, ObjectTypeConst);
4641 } else {
4642 panic!("Expected FormElicitationParam");
4643 }
4644
4645 let json_data_url = json!({
4646 "_meta": { "meta_url_key_1": "meta url value 1" },
4647 "mode": "url",
4648 "message": "Please fill out the form at the following URL.",
4649 "url": "https://example.com/form",
4650 "elicitationId": "elicitation-123"
4651 });
4652 let elicitation_url: ElicitRequestParams =
4653 serde_json::from_value(json_data_url).expect("Deserialization failed");
4654 if let ElicitRequestParams::UrlElicitationParams {
4655 meta,
4656 message,
4657 url,
4658 elicitation_id,
4659 } = elicitation_url
4660 {
4661 assert_eq!(
4662 meta,
4663 Some(RequestMetaObject(MetaObject(
4664 object!({ "meta_url_key_1": "meta url value 1" })
4665 )))
4666 );
4667 assert_eq!(message, "Please fill out the form at the following URL.");
4668 assert_eq!(url, "https://example.com/form");
4669 assert_eq!(elicitation_id, "elicitation-123");
4670 } else {
4671 panic!("Expected UrlElicitationParam");
4672 }
4673 }
4674
4675 #[test]
4676 fn test_elicitation_serialization() {
4677 let form_elicitation = ElicitRequestParams::FormElicitationParams {
4678 meta: Some(RequestMetaObject(MetaObject(
4679 object!({ "meta_form_key_1": "meta form value 1" }),
4680 ))),
4681 message: "Please provide more details.".to_string(),
4682 requested_schema: ElicitationSchema::builder()
4683 .title("User Details")
4684 .string_property("name", |s| s)
4685 .build()
4686 .expect("Valid schema"),
4687 };
4688 let json_form = serde_json::to_value(&form_elicitation).expect("Serialization failed");
4689 let expected_form_json = json!({
4690 "_meta": { "meta_form_key_1": "meta form value 1" },
4691 "mode": "form",
4692 "message": "Please provide more details.",
4693 "requestedSchema": {
4694 "title":"User Details",
4695 "type":"object",
4696 "properties":{
4697 "name": { "type": "string" },
4698 },
4699 }
4700 });
4701 assert_eq!(json_form, expected_form_json);
4702
4703 let url_elicitation = ElicitRequestParams::UrlElicitationParams {
4704 meta: Some(RequestMetaObject(MetaObject(
4705 object!({ "meta_url_key_1": "meta url value 1" }),
4706 ))),
4707 message: "Please fill out the form at the following URL.".to_string(),
4708 url: "https://example.com/form".to_string(),
4709 elicitation_id: "elicitation-123".to_string(),
4710 };
4711 let json_url = serde_json::to_value(&url_elicitation).expect("Serialization failed");
4712 let expected_url_json = json!({
4713 "_meta": { "meta_url_key_1": "meta url value 1" },
4714 "mode": "url",
4715 "message": "Please fill out the form at the following URL.",
4716 "url": "https://example.com/form",
4717 "elicitationId": "elicitation-123"
4718 });
4719 assert_eq!(json_url, expected_url_json);
4720 }
4721
4722 #[test]
4723 fn notification_without_params_should_deserialize_as_bare_jsonrpc_message() {
4724 let payload = b"{\"method\":\"notifications/initialized\",\"jsonrpc\":\"2.0\"}";
4725 let result: Result<JsonRpcMessage, _> = serde_json::from_slice(payload);
4726 assert!(
4727 matches!(result, Ok(JsonRpcMessage::Notification(_))),
4728 "Expected Ok(Notification), got: {:?}",
4729 result
4730 );
4731 }
4732}