agenterra_rmcp/
model.rs

1use std::{borrow::Cow, sync::Arc};
2mod annotated;
3mod capabilities;
4mod content;
5mod extension;
6mod meta;
7mod prompt;
8mod resource;
9mod serde_impl;
10mod tool;
11pub use annotated::*;
12pub use capabilities::*;
13pub use content::*;
14pub use extension::*;
15pub use meta::*;
16pub use prompt::*;
17pub use resource::*;
18use serde::{Deserialize, Serialize};
19use serde_json::Value;
20pub use tool::*;
21
22/// You can use [`crate::object!`] or [`crate::model::object`] to create a json object quickly.
23pub type JsonObject<F = Value> = serde_json::Map<String, F>;
24
25/// unwrap the JsonObject under [`serde_json::Value`]
26///
27/// # Panic
28/// This will panic when the value is not a object in debug mode.
29pub fn object(value: serde_json::Value) -> JsonObject {
30    debug_assert!(value.is_object());
31    match value {
32        serde_json::Value::Object(map) => map,
33        _ => JsonObject::default(),
34    }
35}
36
37/// Use this macro just like [`serde_json::json!`]
38#[cfg(feature = "macros")]
39#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
40#[macro_export]
41macro_rules! object {
42    ({$($tt:tt)*}) => {
43        $crate::model::object(serde_json::json! {
44            {$($tt)*}
45        })
46    };
47}
48#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
49#[cfg_attr(feature = "server", derive(schemars::JsonSchema))]
50pub struct EmptyObject {}
51
52pub trait ConstString: Default {
53    const VALUE: &str;
54}
55#[macro_export]
56macro_rules! const_string {
57    ($name:ident = $value:literal) => {
58        #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
59        pub struct $name;
60
61        impl ConstString for $name {
62            const VALUE: &str = $value;
63        }
64
65        impl serde::Serialize for $name {
66            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67            where
68                S: serde::Serializer,
69            {
70                $value.serialize(serializer)
71            }
72        }
73
74        impl<'de> serde::Deserialize<'de> for $name {
75            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
76            where
77                D: serde::Deserializer<'de>,
78            {
79                let s: String = serde::Deserialize::deserialize(deserializer)?;
80                if s == $value {
81                    Ok($name)
82                } else {
83                    Err(serde::de::Error::custom(format!(concat!(
84                        "expect const string value \"",
85                        $value,
86                        "\""
87                    ))))
88                }
89            }
90        }
91
92        #[cfg(feature = "schemars")]
93        impl schemars::JsonSchema for $name {
94            fn schema_name() -> String {
95                stringify!($name).to_string()
96            }
97
98            fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::schema::Schema {
99                // Create a schema for a constant value of type String
100                schemars::schema::Schema::Object(schemars::schema::SchemaObject {
101                    instance_type: Some(schemars::schema::InstanceType::String.into()),
102                    format: Some("const".to_string()),
103                    const_value: Some(serde_json::Value::String($value.into())),
104                    ..Default::default()
105                })
106            }
107        }
108    };
109}
110
111const_string!(JsonRpcVersion2_0 = "2.0");
112
113#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
114#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
115pub struct ProtocolVersion(Cow<'static, str>);
116
117impl Default for ProtocolVersion {
118    fn default() -> Self {
119        Self::LATEST
120    }
121}
122
123impl std::fmt::Display for ProtocolVersion {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        self.0.fmt(f)
126    }
127}
128
129impl ProtocolVersion {
130    pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
131    pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
132    pub const LATEST: Self = Self::V_2025_03_26;
133}
134
135impl Serialize for ProtocolVersion {
136    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137    where
138        S: serde::Serializer,
139    {
140        self.0.serialize(serializer)
141    }
142}
143
144impl<'de> Deserialize<'de> for ProtocolVersion {
145    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
146    where
147        D: serde::Deserializer<'de>,
148    {
149        let s: String = Deserialize::deserialize(deserializer)?;
150        #[allow(clippy::single_match)]
151        match s.as_str() {
152            "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
153            "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
154            _ => {}
155        }
156        Ok(ProtocolVersion(Cow::Owned(s)))
157    }
158}
159
160#[derive(Debug, Clone, Eq, PartialEq, Hash)]
161pub enum NumberOrString {
162    Number(u32),
163    String(Arc<str>),
164}
165
166impl NumberOrString {
167    pub fn into_json_value(self) -> Value {
168        match self {
169            NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
170            NumberOrString::String(s) => Value::String(s.to_string()),
171        }
172    }
173}
174
175impl std::fmt::Display for NumberOrString {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        match self {
178            NumberOrString::Number(n) => n.fmt(f),
179            NumberOrString::String(s) => s.fmt(f),
180        }
181    }
182}
183
184impl Serialize for NumberOrString {
185    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186    where
187        S: serde::Serializer,
188    {
189        match self {
190            NumberOrString::Number(n) => n.serialize(serializer),
191            NumberOrString::String(s) => s.serialize(serializer),
192        }
193    }
194}
195
196impl<'de> Deserialize<'de> for NumberOrString {
197    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
198    where
199        D: serde::Deserializer<'de>,
200    {
201        let value: Value = Deserialize::deserialize(deserializer)?;
202        match value {
203            Value::Number(n) => Ok(NumberOrString::Number(
204                n.as_u64()
205                    .ok_or(serde::de::Error::custom("Expect an integer"))? as u32,
206            )),
207            Value::String(s) => Ok(NumberOrString::String(s.into())),
208            _ => Err(serde::de::Error::custom("Expect number or string")),
209        }
210    }
211}
212
213#[cfg(feature = "schemars")]
214impl schemars::JsonSchema for NumberOrString {
215    fn schema_name() -> String {
216        "NumberOrString".to_string()
217    }
218
219    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::schema::Schema {
220        schemars::schema::Schema::Object(schemars::schema::SchemaObject {
221            subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
222                one_of: Some(vec![
223                    schemars::schema::Schema::Object(schemars::schema::SchemaObject {
224                        instance_type: Some(schemars::schema::InstanceType::Number.into()),
225                        ..Default::default()
226                    }),
227                    schemars::schema::Schema::Object(schemars::schema::SchemaObject {
228                        instance_type: Some(schemars::schema::InstanceType::String.into()),
229                        ..Default::default()
230                    }),
231                ]),
232                ..Default::default()
233            })),
234            ..Default::default()
235        })
236    }
237}
238
239pub type RequestId = NumberOrString;
240
241#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
242#[serde(transparent)]
243#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
244pub struct ProgressToken(pub NumberOrString);
245#[derive(Debug, Clone)]
246#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
247pub struct Request<M = String, P = JsonObject> {
248    pub method: M,
249    // #[serde(skip_serializing_if = "Option::is_none")]
250    pub params: P,
251    /// extensions will carry anything possible in the context, including [`Meta`]
252    ///
253    /// this is similar with the Extensions in `http` crate
254    #[cfg_attr(feature = "schemars", schemars(skip))]
255    pub extensions: Extensions,
256}
257
258impl<M, P> GetExtensions for Request<M, P> {
259    fn extensions(&self) -> &Extensions {
260        &self.extensions
261    }
262    fn extensions_mut(&mut self) -> &mut Extensions {
263        &mut self.extensions
264    }
265}
266
267#[derive(Debug, Clone)]
268#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
269pub struct RequestOptionalParam<M = String, P = JsonObject> {
270    pub method: M,
271    // #[serde(skip_serializing_if = "Option::is_none")]
272    pub params: Option<P>,
273    /// extensions will carry anything possible in the context, including [`Meta`]
274    ///
275    /// this is similar with the Extensions in `http` crate
276    #[cfg_attr(feature = "schemars", schemars(skip))]
277    pub extensions: Extensions,
278}
279
280#[derive(Debug, Clone)]
281#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
282pub struct RequestNoParam<M = String> {
283    pub method: M,
284    /// extensions will carry anything possible in the context, including [`Meta`]
285    ///
286    /// this is similar with the Extensions in `http` crate
287    #[cfg_attr(feature = "schemars", schemars(skip))]
288    pub extensions: Extensions,
289}
290
291impl<M> GetExtensions for RequestNoParam<M> {
292    fn extensions(&self) -> &Extensions {
293        &self.extensions
294    }
295    fn extensions_mut(&mut self) -> &mut Extensions {
296        &mut self.extensions
297    }
298}
299#[derive(Debug, Clone)]
300#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
301pub struct Notification<M = String, P = JsonObject> {
302    pub method: M,
303    pub params: P,
304    /// extensions will carry anything possible in the context, including [`Meta`]
305    ///
306    /// this is similar with the Extensions in `http` crate
307    #[cfg_attr(feature = "schemars", schemars(skip))]
308    pub extensions: Extensions,
309}
310
311#[derive(Debug, Clone)]
312#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
313pub struct NotificationNoParam<M = String> {
314    pub method: M,
315    /// extensions will carry anything possible in the context, including [`Meta`]
316    ///
317    /// this is similar with the Extensions in `http` crate
318    #[cfg_attr(feature = "schemars", schemars(skip))]
319    pub extensions: Extensions,
320}
321
322#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
323#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
324pub struct JsonRpcRequest<R = Request> {
325    pub jsonrpc: JsonRpcVersion2_0,
326    pub id: RequestId,
327    #[serde(flatten)]
328    pub request: R,
329}
330
331type DefaultResponse = JsonObject;
332#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
333#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
334pub struct JsonRpcResponse<R = JsonObject> {
335    pub jsonrpc: JsonRpcVersion2_0,
336    pub id: RequestId,
337    pub result: R,
338}
339
340#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
341#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
342pub struct JsonRpcError {
343    pub jsonrpc: JsonRpcVersion2_0,
344    pub id: RequestId,
345    pub error: ErrorData,
346}
347
348#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
350pub struct JsonRpcNotification<N = Notification> {
351    pub jsonrpc: JsonRpcVersion2_0,
352    #[serde(flatten)]
353    pub notification: N,
354}
355
356// Standard JSON-RPC error codes
357#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
358#[serde(transparent)]
359#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
360pub struct ErrorCode(pub i32);
361
362impl ErrorCode {
363    pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
364    pub const INVALID_REQUEST: Self = Self(-32600);
365    pub const METHOD_NOT_FOUND: Self = Self(-32601);
366    pub const INVALID_PARAMS: Self = Self(-32602);
367    pub const INTERNAL_ERROR: Self = Self(-32603);
368    pub const PARSE_ERROR: Self = Self(-32700);
369}
370
371/// Error information for JSON-RPC error responses.
372#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
373#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
374pub struct ErrorData {
375    /// The error type that occurred.
376    pub code: ErrorCode,
377
378    /// A short description of the error. The message SHOULD be limited to a concise single sentence.
379    pub message: Cow<'static, str>,
380
381    /// Additional information about the error. The value of this member is defined by the
382    /// sender (e.g. detailed error information, nested errors etc.).
383    #[serde(skip_serializing_if = "Option::is_none")]
384    pub data: Option<Value>,
385}
386
387impl ErrorData {
388    pub fn new(
389        code: ErrorCode,
390        message: impl Into<Cow<'static, str>>,
391        data: Option<Value>,
392    ) -> Self {
393        Self {
394            code,
395            message: message.into(),
396            data,
397        }
398    }
399    pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
400        Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
401    }
402    pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
403        Self::new(ErrorCode::PARSE_ERROR, message, data)
404    }
405    pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
406        Self::new(ErrorCode::INVALID_REQUEST, message, data)
407    }
408    pub fn method_not_found<M: ConstString>() -> Self {
409        Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
410    }
411    pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
412        Self::new(ErrorCode::INVALID_PARAMS, message, data)
413    }
414    pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
415        Self::new(ErrorCode::INTERNAL_ERROR, message, data)
416    }
417}
418
419#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
420#[serde(untagged)]
421#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
422pub enum JsonRpcBatchRequestItem<Req, Not> {
423    Request(JsonRpcRequest<Req>),
424    Notification(JsonRpcNotification<Not>),
425}
426
427impl<Req, Not> JsonRpcBatchRequestItem<Req, Not> {
428    pub fn into_non_batch_message<Resp>(self) -> JsonRpcMessage<Req, Resp, Not> {
429        match self {
430            JsonRpcBatchRequestItem::Request(r) => JsonRpcMessage::Request(r),
431            JsonRpcBatchRequestItem::Notification(n) => JsonRpcMessage::Notification(n),
432        }
433    }
434}
435
436#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
437#[serde(untagged)]
438#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
439pub enum JsonRpcBatchResponseItem<Resp> {
440    Response(JsonRpcResponse<Resp>),
441    Error(JsonRpcError),
442}
443
444impl<Resp> JsonRpcBatchResponseItem<Resp> {
445    pub fn into_non_batch_message<Req, Not>(self) -> JsonRpcMessage<Req, Resp, Not> {
446        match self {
447            JsonRpcBatchResponseItem::Response(r) => JsonRpcMessage::Response(r),
448            JsonRpcBatchResponseItem::Error(e) => JsonRpcMessage::Error(e),
449        }
450    }
451}
452
453#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
454#[serde(untagged)]
455#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
456pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
457    Request(JsonRpcRequest<Req>),
458    Response(JsonRpcResponse<Resp>),
459    Notification(JsonRpcNotification<Noti>),
460    BatchRequest(Vec<JsonRpcBatchRequestItem<Req, Noti>>),
461    BatchResponse(Vec<JsonRpcBatchResponseItem<Resp>>),
462    Error(JsonRpcError),
463}
464
465impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
466    #[inline]
467    pub const fn request(request: Req, id: RequestId) -> Self {
468        JsonRpcMessage::Request(JsonRpcRequest {
469            jsonrpc: JsonRpcVersion2_0,
470            id,
471            request,
472        })
473    }
474    #[inline]
475    pub const fn response(response: Resp, id: RequestId) -> Self {
476        JsonRpcMessage::Response(JsonRpcResponse {
477            jsonrpc: JsonRpcVersion2_0,
478            id,
479            result: response,
480        })
481    }
482    #[inline]
483    pub const fn error(error: ErrorData, id: RequestId) -> Self {
484        JsonRpcMessage::Error(JsonRpcError {
485            jsonrpc: JsonRpcVersion2_0,
486            id,
487            error,
488        })
489    }
490    #[inline]
491    pub const fn notification(notification: Not) -> Self {
492        JsonRpcMessage::Notification(JsonRpcNotification {
493            jsonrpc: JsonRpcVersion2_0,
494            notification,
495        })
496    }
497    pub fn into_request(self) -> Option<(Req, RequestId)> {
498        match self {
499            JsonRpcMessage::Request(r) => Some((r.request, r.id)),
500            _ => None,
501        }
502    }
503    pub fn into_response(self) -> Option<(Resp, RequestId)> {
504        match self {
505            JsonRpcMessage::Response(r) => Some((r.result, r.id)),
506            _ => None,
507        }
508    }
509    pub fn into_notification(self) -> Option<Not> {
510        match self {
511            JsonRpcMessage::Notification(n) => Some(n.notification),
512            _ => None,
513        }
514    }
515    pub fn into_error(self) -> Option<(ErrorData, RequestId)> {
516        match self {
517            JsonRpcMessage::Error(e) => Some((e.error, e.id)),
518            _ => None,
519        }
520    }
521    pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, RequestId)> {
522        match self {
523            JsonRpcMessage::Response(r) => Some((Ok(r.result), r.id)),
524            JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),
525
526            _ => None,
527        }
528    }
529}
530
531/// # Empty result
532/// A response that indicates success but carries no data.
533pub type EmptyResult = EmptyObject;
534
535impl From<()> for EmptyResult {
536    fn from(_value: ()) -> Self {
537        EmptyResult {}
538    }
539}
540
541impl From<EmptyResult> for () {
542    fn from(_value: EmptyResult) {}
543}
544
545#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
546#[serde(rename_all = "camelCase")]
547#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
548pub struct CancelledNotificationParam {
549    pub request_id: RequestId,
550    pub reason: Option<String>,
551}
552
553const_string!(CancelledNotificationMethod = "notifications/cancelled");
554
555/// # Cancellation
556/// This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
557///
558/// The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
559///
560/// This notification indicates that the result will be unused, so any associated processing SHOULD cease.
561///
562/// A client MUST NOT attempt to cancel its `initialize` request.
563pub type CancelledNotification =
564    Notification<CancelledNotificationMethod, CancelledNotificationParam>;
565
566const_string!(InitializeResultMethod = "initialize");
567/// # Initialization
568/// This request is sent from the client to the server when it first connects, asking it to begin initialization.
569pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParam>;
570
571const_string!(InitializedNotificationMethod = "notifications/initialized");
572/// This notification is sent from the client to the server after initialization has finished.
573pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;
574#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
575#[serde(rename_all = "camelCase")]
576#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
577pub struct InitializeRequestParam {
578    pub protocol_version: ProtocolVersion,
579    pub capabilities: ClientCapabilities,
580    pub client_info: Implementation,
581}
582
583#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
584#[serde(rename_all = "camelCase")]
585#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
586pub struct InitializeResult {
587    pub protocol_version: ProtocolVersion,
588    pub capabilities: ServerCapabilities,
589    pub server_info: Implementation,
590    #[serde(skip_serializing_if = "Option::is_none")]
591    pub instructions: Option<String>,
592}
593
594pub type ServerInfo = InitializeResult;
595pub type ClientInfo = InitializeRequestParam;
596
597impl Default for ServerInfo {
598    fn default() -> Self {
599        ServerInfo {
600            protocol_version: ProtocolVersion::default(),
601            capabilities: ServerCapabilities::default(),
602            server_info: Implementation::from_build_env(),
603            instructions: None,
604        }
605    }
606}
607
608impl Default for ClientInfo {
609    fn default() -> Self {
610        ClientInfo {
611            protocol_version: ProtocolVersion::default(),
612            capabilities: ClientCapabilities::default(),
613            client_info: Implementation::from_build_env(),
614        }
615    }
616}
617
618#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
619#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
620pub struct Implementation {
621    pub name: String,
622    pub version: String,
623}
624
625impl Default for Implementation {
626    fn default() -> Self {
627        Self::from_build_env()
628    }
629}
630
631impl Implementation {
632    pub fn from_build_env() -> Self {
633        Implementation {
634            name: env!("CARGO_CRATE_NAME").to_owned(),
635            version: env!("CARGO_PKG_VERSION").to_owned(),
636        }
637    }
638}
639
640#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
641#[serde(rename_all = "camelCase")]
642#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
643pub struct PaginatedRequestParam {
644    #[serde(skip_serializing_if = "Option::is_none")]
645    pub cursor: Option<String>,
646}
647const_string!(PingRequestMethod = "ping");
648pub type PingRequest = RequestNoParam<PingRequestMethod>;
649
650const_string!(ProgressNotificationMethod = "notifications/progress");
651#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
652#[serde(rename_all = "camelCase")]
653#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
654pub struct ProgressNotificationParam {
655    pub progress_token: ProgressToken,
656    /// The progress thus far. This should increase every time progress is made, even if the total is unknown.
657    pub progress: u32,
658    /// Total number of items to process (or total progress required), if known
659    #[serde(skip_serializing_if = "Option::is_none")]
660    pub total: Option<u32>,
661    /// An optional message describing the current progress.
662    #[serde(skip_serializing_if = "Option::is_none")]
663    pub message: Option<String>,
664}
665
666pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;
667
668pub type Cursor = String;
669
670macro_rules! paginated_result {
671    ($t:ident {
672        $i_item: ident: $t_item: ty
673    }) => {
674        #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
675        #[serde(rename_all = "camelCase")]
676        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
677        pub struct $t {
678            #[serde(skip_serializing_if = "Option::is_none")]
679            pub next_cursor: Option<Cursor>,
680            pub $i_item: $t_item,
681        }
682
683        impl $t {
684            pub fn with_all_items(
685                items: $t_item,
686            ) -> Self {
687                Self {
688                    next_cursor: None,
689                    $i_item: items,
690                }
691            }
692        }
693    };
694}
695
696const_string!(ListResourcesRequestMethod = "resources/list");
697pub type ListResourcesRequest =
698    RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParam>;
699paginated_result!(ListResourcesResult {
700    resources: Vec<Resource>
701});
702
703const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
704pub type ListResourceTemplatesRequest =
705    RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParam>;
706paginated_result!(ListResourceTemplatesResult {
707    resource_templates: Vec<ResourceTemplate>
708});
709
710const_string!(ReadResourceRequestMethod = "resources/read");
711#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
712#[serde(rename_all = "camelCase")]
713#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
714pub struct ReadResourceRequestParam {
715    pub uri: String,
716}
717
718#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
719#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
720pub struct ReadResourceResult {
721    pub contents: Vec<ResourceContents>,
722}
723
724pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParam>;
725
726const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
727pub type ResourceListChangedNotification =
728    NotificationNoParam<ResourceListChangedNotificationMethod>;
729
730const_string!(SubscribeRequestMethod = "resources/subscribe");
731#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
732#[serde(rename_all = "camelCase")]
733#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
734pub struct SubscribeRequestParam {
735    pub uri: String,
736}
737pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParam>;
738
739const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
740#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
741#[serde(rename_all = "camelCase")]
742#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
743pub struct UnsubscribeRequestParam {
744    pub uri: String,
745}
746pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParam>;
747
748const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
749#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
750#[serde(rename_all = "camelCase")]
751#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
752pub struct ResourceUpdatedNotificationParam {
753    pub uri: String,
754}
755pub type ResourceUpdatedNotification =
756    Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;
757
758const_string!(ListPromptsRequestMethod = "prompts/list");
759pub type ListPromptsRequest = RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParam>;
760paginated_result!(ListPromptsResult {
761    prompts: Vec<Prompt>
762});
763
764const_string!(GetPromptRequestMethod = "prompts/get");
765#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
766#[serde(rename_all = "camelCase")]
767#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
768pub struct GetPromptRequestParam {
769    pub name: String,
770    #[serde(skip_serializing_if = "Option::is_none")]
771    pub arguments: Option<JsonObject>,
772}
773pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParam>;
774
775const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
776pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;
777
778const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
779pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;
780// 日志相关
781#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
782#[serde(rename_all = "lowercase")] //match spec
783#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
784pub enum LoggingLevel {
785    Debug,
786    Info,
787    Notice,
788    Warning,
789    Error,
790    Critical,
791    Alert,
792    Emergency,
793}
794
795const_string!(SetLevelRequestMethod = "logging/setLevel");
796#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
797#[serde(rename_all = "camelCase")]
798#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
799pub struct SetLevelRequestParam {
800    pub level: LoggingLevel,
801}
802pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParam>;
803
804const_string!(LoggingMessageNotificationMethod = "notifications/message");
805#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
806#[serde(rename_all = "camelCase")]
807#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
808pub struct LoggingMessageNotificationParam {
809    pub level: LoggingLevel,
810    #[serde(skip_serializing_if = "Option::is_none")]
811    pub logger: Option<String>,
812    pub data: Value,
813}
814pub type LoggingMessageNotification =
815    Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;
816
817const_string!(CreateMessageRequestMethod = "sampling/createMessage");
818pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParam>;
819
820#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
821#[serde(rename_all = "camelCase")]
822#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
823pub enum Role {
824    User,
825    Assistant,
826}
827
828#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
829#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
830pub struct SamplingMessage {
831    pub role: Role,
832    pub content: Content,
833}
834
835#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
836#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
837pub enum ContextInclusion {
838    #[serde(rename = "allServers")]
839    AllServers,
840    #[serde(rename = "none")]
841    None,
842    #[serde(rename = "thisServer")]
843    ThisServer,
844}
845
846#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
847#[serde(rename_all = "camelCase")]
848#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
849pub struct CreateMessageRequestParam {
850    pub messages: Vec<SamplingMessage>,
851    #[serde(skip_serializing_if = "Option::is_none")]
852    pub model_preferences: Option<ModelPreferences>,
853    #[serde(skip_serializing_if = "Option::is_none")]
854    pub system_prompt: Option<String>,
855    #[serde(skip_serializing_if = "Option::is_none")]
856    pub include_context: Option<ContextInclusion>,
857    #[serde(skip_serializing_if = "Option::is_none")]
858    pub temperature: Option<f32>,
859    pub max_tokens: u32,
860    #[serde(skip_serializing_if = "Option::is_none")]
861    pub stop_sequences: Option<Vec<String>>,
862    #[serde(skip_serializing_if = "Option::is_none")]
863    pub metadata: Option<Value>,
864}
865
866#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
867#[serde(rename_all = "camelCase")]
868#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
869pub struct ModelPreferences {
870    #[serde(skip_serializing_if = "Option::is_none")]
871    pub hints: Option<Vec<ModelHint>>,
872    #[serde(skip_serializing_if = "Option::is_none")]
873    pub cost_priority: Option<f32>,
874    #[serde(skip_serializing_if = "Option::is_none")]
875    pub speed_priority: Option<f32>,
876    #[serde(skip_serializing_if = "Option::is_none")]
877    pub intelligence_priority: Option<f32>,
878}
879
880#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
881#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
882pub struct ModelHint {
883    #[serde(skip_serializing_if = "Option::is_none")]
884    pub name: Option<String>,
885}
886
887#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
888#[serde(rename_all = "camelCase")]
889#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
890pub struct CompleteRequestParam {
891    pub r#ref: Reference,
892    pub argument: ArgumentInfo,
893}
894
895pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParam>;
896
897#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
898#[serde(rename_all = "camelCase")]
899#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
900pub struct CompletionInfo {
901    pub values: Vec<String>,
902    #[serde(skip_serializing_if = "Option::is_none")]
903    pub total: Option<u32>,
904    #[serde(skip_serializing_if = "Option::is_none")]
905    pub has_more: Option<bool>,
906}
907
908#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
909#[serde(rename_all = "camelCase")]
910#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
911pub struct CompleteResult {
912    pub completion: CompletionInfo,
913}
914
915#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
916#[serde(tag = "type")]
917#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
918pub enum Reference {
919    #[serde(rename = "ref/resource")]
920    Resource(ResourceReference),
921    #[serde(rename = "ref/prompt")]
922    Prompt(PromptReference),
923}
924
925#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
926#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
927pub struct ResourceReference {
928    pub uri: String,
929}
930
931#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
932#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
933pub struct PromptReference {
934    pub name: String,
935}
936
937const_string!(CompleteRequestMethod = "completion/complete");
938#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
939#[serde(rename_all = "camelCase")]
940#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
941pub struct ArgumentInfo {
942    pub name: String,
943    pub value: String,
944}
945
946// 根目录相关
947#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
948#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
949pub struct Root {
950    pub uri: String,
951    #[serde(skip_serializing_if = "Option::is_none")]
952    pub name: Option<String>,
953}
954
955const_string!(ListRootsRequestMethod = "roots/list");
956pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;
957
958#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
959#[serde(rename_all = "camelCase")]
960#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
961pub struct ListRootsResult {
962    pub roots: Vec<Root>,
963}
964
965const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
966pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;
967
968#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
969#[serde(rename_all = "camelCase")]
970#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
971pub struct CallToolResult {
972    pub content: Vec<Content>,
973    #[serde(skip_serializing_if = "Option::is_none")]
974    pub is_error: Option<bool>,
975}
976
977impl CallToolResult {
978    pub fn success(content: Vec<Content>) -> Self {
979        CallToolResult {
980            content,
981            is_error: Some(false),
982        }
983    }
984    pub fn error(content: Vec<Content>) -> Self {
985        CallToolResult {
986            content,
987            is_error: Some(true),
988        }
989    }
990}
991
992const_string!(ListToolsRequestMethod = "tools/list");
993pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParam>;
994paginated_result!(
995    ListToolsResult {
996        tools: Vec<Tool>
997    }
998);
999
1000const_string!(CallToolRequestMethod = "tools/call");
1001#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1002#[serde(rename_all = "camelCase")]
1003#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1004pub struct CallToolRequestParam {
1005    pub name: Cow<'static, str>,
1006    #[serde(skip_serializing_if = "Option::is_none")]
1007    pub arguments: Option<JsonObject>,
1008}
1009
1010pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParam>;
1011
1012#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1013#[serde(rename_all = "camelCase")]
1014#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1015pub struct CreateMessageResult {
1016    pub model: String,
1017    #[serde(skip_serializing_if = "Option::is_none")]
1018    pub stop_reason: Option<String>,
1019    #[serde(flatten)]
1020    pub message: SamplingMessage,
1021}
1022
1023impl CreateMessageResult {
1024    pub const STOP_REASON_END_TURN: &str = "endTurn";
1025    pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
1026    pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
1027}
1028
1029#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1030#[serde(rename_all = "camelCase")]
1031#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1032pub struct GetPromptResult {
1033    #[serde(skip_serializing_if = "Option::is_none")]
1034    pub description: Option<String>,
1035    pub messages: Vec<PromptMessage>,
1036}
1037
1038macro_rules! ts_union {
1039    (
1040        export type $U: ident =
1041            $(|)?$($V: ident)|*;
1042    ) => {
1043        #[derive(Debug, Serialize, Deserialize, Clone)]
1044        #[serde(untagged)]
1045        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1046        pub enum $U {
1047            $($V($V),)*
1048        }
1049    };
1050}
1051
1052ts_union!(
1053    export type ClientRequest =
1054    | PingRequest
1055    | InitializeRequest
1056    | CompleteRequest
1057    | SetLevelRequest
1058    | GetPromptRequest
1059    | ListPromptsRequest
1060    | ListResourcesRequest
1061    | ListResourceTemplatesRequest
1062    | ReadResourceRequest
1063    | SubscribeRequest
1064    | UnsubscribeRequest
1065    | CallToolRequest
1066    | ListToolsRequest;
1067);
1068
1069ts_union!(
1070    export type ClientNotification =
1071    | CancelledNotification
1072    | ProgressNotification
1073    | InitializedNotification
1074    | RootsListChangedNotification;
1075);
1076
1077ts_union!(
1078    export type ClientResult = CreateMessageResult | ListRootsResult | EmptyResult;
1079);
1080
1081impl ClientResult {
1082    pub fn empty(_: ()) -> ClientResult {
1083        ClientResult::EmptyResult(EmptyResult {})
1084    }
1085}
1086
1087pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;
1088
1089ts_union!(
1090    export type ServerRequest =
1091    | PingRequest
1092    | CreateMessageRequest
1093    | ListRootsRequest;
1094);
1095
1096ts_union!(
1097    export type ServerNotification =
1098    | CancelledNotification
1099    | ProgressNotification
1100    | LoggingMessageNotification
1101    | ResourceUpdatedNotification
1102    | ResourceListChangedNotification
1103    | ToolListChangedNotification
1104    | PromptListChangedNotification;
1105);
1106
1107ts_union!(
1108    export type ServerResult =
1109    | InitializeResult
1110    | CompleteResult
1111    | GetPromptResult
1112    | ListPromptsResult
1113    | ListResourcesResult
1114    | ListResourceTemplatesResult
1115    | ReadResourceResult
1116    | CallToolResult
1117    | ListToolsResult
1118    | EmptyResult
1119    ;
1120);
1121
1122impl ServerResult {
1123    pub fn empty(_: ()) -> ServerResult {
1124        ServerResult::EmptyResult(EmptyResult {})
1125    }
1126}
1127
1128pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;
1129
1130impl TryInto<CancelledNotification> for ServerNotification {
1131    type Error = ServerNotification;
1132    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
1133        if let ServerNotification::CancelledNotification(t) = self {
1134            Ok(t)
1135        } else {
1136            Err(self)
1137        }
1138    }
1139}
1140
1141impl TryInto<CancelledNotification> for ClientNotification {
1142    type Error = ClientNotification;
1143    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
1144        if let ClientNotification::CancelledNotification(t) = self {
1145            Ok(t)
1146        } else {
1147            Err(self)
1148        }
1149    }
1150}
1151impl From<CancelledNotification> for ServerNotification {
1152    fn from(value: CancelledNotification) -> Self {
1153        ServerNotification::CancelledNotification(value)
1154    }
1155}
1156
1157impl From<CancelledNotification> for ClientNotification {
1158    fn from(value: CancelledNotification) -> Self {
1159        ClientNotification::CancelledNotification(value)
1160    }
1161}
1162
1163#[cfg(test)]
1164mod tests {
1165    use serde_json::json;
1166
1167    use super::*;
1168
1169    #[test]
1170    fn test_notification_serde() {
1171        let raw = json!( {
1172            "jsonrpc": JsonRpcVersion2_0,
1173            "method": InitializedNotificationMethod,
1174        });
1175        let message: ClientJsonRpcMessage =
1176            serde_json::from_value(raw.clone()).expect("invalid notification");
1177        match &message {
1178            ClientJsonRpcMessage::Notification(JsonRpcNotification {
1179                notification: ClientNotification::InitializedNotification(_n),
1180                ..
1181            }) => {}
1182            _ => panic!("Expected Notification"),
1183        }
1184        let json = serde_json::to_value(message).expect("valid json");
1185        assert_eq!(json, raw);
1186    }
1187
1188    #[test]
1189    fn test_request_conversion() {
1190        let raw = json!( {
1191            "jsonrpc": JsonRpcVersion2_0,
1192            "id": 1,
1193            "method": "request",
1194            "params": {"key": "value"},
1195        });
1196        let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");
1197
1198        match &message {
1199            JsonRpcMessage::Request(r) => {
1200                assert_eq!(r.id, RequestId::Number(1));
1201                assert_eq!(r.request.method, "request");
1202                assert_eq!(
1203                    &r.request.params,
1204                    json!({"key": "value"})
1205                        .as_object()
1206                        .expect("should be an object")
1207                );
1208            }
1209            _ => panic!("Expected Request"),
1210        }
1211        let json = serde_json::to_value(&message).expect("valid json");
1212        assert_eq!(json, raw);
1213    }
1214
1215    #[test]
1216    fn test_initial_request_response_serde() {
1217        let request = json!({
1218          "jsonrpc": "2.0",
1219          "id": 1,
1220          "method": "initialize",
1221          "params": {
1222            "protocolVersion": "2024-11-05",
1223            "capabilities": {
1224              "roots": {
1225                "listChanged": true
1226              },
1227              "sampling": {}
1228            },
1229            "clientInfo": {
1230              "name": "ExampleClient",
1231              "version": "1.0.0"
1232            }
1233          }
1234        });
1235        let raw_response_json = json!({
1236          "jsonrpc": "2.0",
1237          "id": 1,
1238          "result": {
1239            "protocolVersion": "2024-11-05",
1240            "capabilities": {
1241              "logging": {},
1242              "prompts": {
1243                "listChanged": true
1244              },
1245              "resources": {
1246                "subscribe": true,
1247                "listChanged": true
1248              },
1249              "tools": {
1250                "listChanged": true
1251              }
1252            },
1253            "serverInfo": {
1254              "name": "ExampleServer",
1255              "version": "1.0.0"
1256            }
1257          }
1258        });
1259        let request: ClientJsonRpcMessage =
1260            serde_json::from_value(request.clone()).expect("invalid request");
1261        let (request, id) = request.into_request().expect("should be a request");
1262        assert_eq!(id, RequestId::Number(1));
1263        match request {
1264            ClientRequest::InitializeRequest(Request {
1265                method: _,
1266                params:
1267                    InitializeRequestParam {
1268                        protocol_version: _,
1269                        capabilities,
1270                        client_info,
1271                    },
1272                ..
1273            }) => {
1274                assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
1275                assert_eq!(capabilities.sampling.unwrap().len(), 0);
1276                assert_eq!(client_info.name, "ExampleClient");
1277                assert_eq!(client_info.version, "1.0.0");
1278            }
1279            _ => panic!("Expected InitializeRequest"),
1280        }
1281        let server_response: ServerJsonRpcMessage =
1282            serde_json::from_value(raw_response_json.clone()).expect("invalid response");
1283        let (response, id) = server_response
1284            .clone()
1285            .into_response()
1286            .expect("expect response");
1287        assert_eq!(id, RequestId::Number(1));
1288        match response {
1289            ServerResult::InitializeResult(InitializeResult {
1290                protocol_version: _,
1291                capabilities,
1292                server_info,
1293                instructions,
1294            }) => {
1295                assert_eq!(capabilities.logging.unwrap().len(), 0);
1296                assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
1297                assert_eq!(
1298                    capabilities.resources.as_ref().unwrap().subscribe,
1299                    Some(true)
1300                );
1301                assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
1302                assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
1303                assert_eq!(server_info.name, "ExampleServer");
1304                assert_eq!(server_info.version, "1.0.0");
1305                assert_eq!(instructions, None);
1306            }
1307            other => panic!("Expected InitializeResult, got {other:?}"),
1308        }
1309
1310        let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");
1311
1312        assert_eq!(server_response_json, raw_response_json);
1313    }
1314
1315    #[test]
1316    fn test_protocol_version_order() {
1317        let v1 = ProtocolVersion::V_2024_11_05;
1318        let v2 = ProtocolVersion::V_2025_03_26;
1319        assert!(v1 < v2);
1320    }
1321}