@@ -172,11 +172,35 @@ impl ProtocolVersion {
172172 pub const V_2025_06_18 : Self = Self ( Cow :: Borrowed ( "2025-06-18" ) ) ;
173173 pub const V_2025_03_26 : Self = Self ( Cow :: Borrowed ( "2025-03-26" ) ) ;
174174 pub const V_2024_11_05 : Self = Self ( Cow :: Borrowed ( "2024-11-05" ) ) ;
175- pub const LATEST : Self = Self :: V_2025_11_25 ;
175+
176+ /// The newest protocol version known to this SDK.
177+ pub const LATEST : Self = Self :: V_2026_07_28 ;
176178
177179 /// First protocol version that requires SEP-2243 standard HTTP headers.
178180 pub const STANDARD_HEADERS : Self = Self :: V_2026_07_28 ;
179181
182+ /// First protocol version that replaced the `initialize` handshake with
183+ /// per-request `_meta` (SEP-2567).
184+ pub const NO_INITIALIZE : Self = Self :: V_2026_07_28 ;
185+
186+ /// The newest protocol version that still has an `initialize` handshake.
187+ ///
188+ /// From [`Self::NO_INITIALIZE`] onward the lifecycle moved into per-request
189+ /// `_meta`, so there is no handshake left to answer. A server replying to
190+ /// `initialize` can therefore never name [`Self::LATEST`] once `LATEST`
191+ /// reaches that revision — it has to name this one instead.
192+ ///
193+ /// Use this, not `LATEST`, whenever the subject is the handshake itself:
194+ /// the version a server can echo from `initialize`, or the version a test
195+ /// needs in order to exercise session-based behavior.
196+ ///
197+ /// ```
198+ /// # use rmcp::model::ProtocolVersion;
199+ /// assert!(ProtocolVersion::LATEST_WITH_INITIALIZE.has_initialize());
200+ /// assert!(!ProtocolVersion::LATEST.has_initialize());
201+ /// ```
202+ pub const LATEST_WITH_INITIALIZE : Self = Self :: V_2025_11_25 ;
203+
180204 /// All protocol versions known to this SDK, oldest first.
181205 pub const KNOWN_VERSIONS : & [ Self ] = & [
182206 Self :: V_2024_11_05 ,
@@ -191,6 +215,23 @@ impl ProtocolVersion {
191215 & self . 0
192216 }
193217
218+ /// Whether this revision negotiates its lifecycle over the `initialize`
219+ /// handshake.
220+ ///
221+ /// `false` from [`Self::NO_INITIALIZE`] onward, where SEP-2567 moved the
222+ /// lifecycle into per-request `_meta`. Unknown versions are compared
223+ /// lexically, which orders correctly because every revision is dated
224+ /// `YYYY-MM-DD`.
225+ ///
226+ /// ```
227+ /// # use rmcp::model::ProtocolVersion;
228+ /// assert!(ProtocolVersion::V_2025_11_25.has_initialize());
229+ /// assert!(!ProtocolVersion::V_2026_07_28.has_initialize());
230+ /// ```
231+ pub fn has_initialize ( & self ) -> bool {
232+ self . as_str ( ) < Self :: NO_INITIALIZE . as_str ( )
233+ }
234+
194235 /// The known versions up to and including `max`, oldest first.
195236 ///
196237 /// Servers that implement every revision up to some ceiling can return
@@ -4784,6 +4825,34 @@ mod tests {
47844825 ) ;
47854826 }
47864827
4828+ // Guards the pair of constants this SDK's negotiation rests on. `LATEST`
4829+ // and `LATEST_WITH_INITIALIZE` were the same value until `LATEST` reached
4830+ // `NO_INITIALIZE`; conflating them is what made bumping `LATEST` expensive.
4831+ #[ test]
4832+ fn latest_with_initialize_is_the_newest_known_version_that_has_one ( ) {
4833+ let derived = ProtocolVersion :: KNOWN_VERSIONS
4834+ . iter ( )
4835+ . filter ( |version| version. has_initialize ( ) )
4836+ . max_by ( |left, right| left. as_str ( ) . cmp ( right. as_str ( ) ) )
4837+ . expect ( "some known version should have an initialize handshake" ) ;
4838+ assert_eq ! (
4839+ derived,
4840+ & ProtocolVersion :: LATEST_WITH_INITIALIZE ,
4841+ "LATEST_WITH_INITIALIZE must track KNOWN_VERSIONS"
4842+ ) ;
4843+ }
4844+
4845+ #[ test]
4846+ fn has_initialize_splits_known_versions_at_no_initialize ( ) {
4847+ for version in ProtocolVersion :: KNOWN_VERSIONS {
4848+ assert_eq ! (
4849+ version. has_initialize( ) ,
4850+ version. as_str( ) < ProtocolVersion :: NO_INITIALIZE . as_str( ) ,
4851+ "{version} classified inconsistently"
4852+ ) ;
4853+ }
4854+ }
4855+
47874856 #[ test]
47884857 fn known_up_to_includes_the_ceiling_itself ( ) {
47894858 assert_eq ! (
0 commit comments