@@ -250,6 +250,34 @@ fn message_has_per_request_protocol_version(message: &ClientJsonRpcMessage) -> b
250250 }
251251}
252252
253+ // SEP-2567: sessions are removed from 2026-07-28; older versions are legacy.
254+ fn is_legacy_request ( message : Option < & ClientJsonRpcMessage > , headers : & HeaderMap ) -> bool {
255+ let from_body = match message {
256+ Some ( ClientJsonRpcMessage :: Request ( req) ) => match & req. request {
257+ ClientRequest :: InitializeRequest ( init) => Some ( init. params . protocol_version . clone ( ) ) ,
258+ _ => req. request . get_meta ( ) . protocol_version ( ) ,
259+ } ,
260+ _ => None ,
261+ } ;
262+ let version = from_body
263+ . or_else ( || {
264+ headers
265+ . get ( HEADER_MCP_PROTOCOL_VERSION )
266+ . and_then ( |value| value. to_str ( ) . ok ( ) )
267+ . and_then ( |s| serde_json:: from_value ( serde_json:: Value :: String ( s. to_owned ( ) ) ) . ok ( ) )
268+ } )
269+ . unwrap_or ( ProtocolVersion :: V_2025_03_26 ) ;
270+ version < ProtocolVersion :: V_2026_07_28
271+ }
272+
273+ fn method_not_allowed_response ( ) -> BoxResponse {
274+ Response :: builder ( )
275+ . status ( http:: StatusCode :: METHOD_NOT_ALLOWED )
276+ . header ( ALLOW , "POST" )
277+ . body ( Full :: new ( Bytes :: from ( "Method Not Allowed" ) ) . boxed ( ) )
278+ . expect ( "valid response" )
279+ }
280+
253281fn invalid_request_jsonrpc_response (
254282 id : Option < RequestId > ,
255283 message : impl Into < Cow < ' static , str > > ,
@@ -1204,6 +1232,9 @@ where
12041232 )
12051233 . expect ( "valid response" ) ) ;
12061234 }
1235+ if !is_legacy_request ( None , request. headers ( ) ) {
1236+ return Ok ( method_not_allowed_response ( ) ) ;
1237+ }
12071238 // check session id
12081239 let session_id = request
12091240 . headers ( )
@@ -1340,29 +1371,8 @@ where
13401371 Err ( response) => return Ok ( response) ,
13411372 } ;
13421373
1343- // SEP-2567: sessions are removed at the protocol level from 2026-07-28.
1344- // Serve such requests statelessly even in stateful mode, never assigning
1345- // or requiring an Mcp-Session-Id. `initialize` declares the version in its
1346- // body params; every other request in the `MCP-Protocol-Version` header
1347- // (defaulting to `2025-03-26` when absent).
1348- let init_version = match & message {
1349- ClientJsonRpcMessage :: Request ( req) => match & req. request {
1350- ClientRequest :: InitializeRequest ( init) => {
1351- Some ( init. params . protocol_version . clone ( ) )
1352- }
1353- _ => None ,
1354- } ,
1355- _ => None ,
1356- } ;
1357- let declared_version = init_version. unwrap_or_else ( || {
1358- part. headers
1359- . get ( HEADER_MCP_PROTOCOL_VERSION )
1360- . and_then ( |value| value. to_str ( ) . ok ( ) )
1361- . and_then ( |s| serde_json:: from_value ( serde_json:: Value :: String ( s. to_owned ( ) ) ) . ok ( ) )
1362- . unwrap_or ( ProtocolVersion :: V_2025_03_26 )
1363- } ) ;
13641374 let use_session =
1365- self . config . stateful_mode && declared_version < ProtocolVersion :: V_2026_07_28 ;
1375+ self . config . stateful_mode && is_legacy_request ( Some ( & message ) , & part . headers ) ;
13661376
13671377 if use_session {
13681378 // do we have a session id?
@@ -1697,6 +1707,9 @@ where
16971707 B : Body + Send + ' static ,
16981708 B :: Error : Display ,
16991709 {
1710+ if !is_legacy_request ( None , request. headers ( ) ) {
1711+ return Ok ( method_not_allowed_response ( ) ) ;
1712+ }
17001713 // check session id
17011714 let session_id = request
17021715 . headers ( )
0 commit comments