11#![ cfg( not( feature = "local" ) ) ]
22//! Regression tests for the `MCP-Protocol-Version` header / initialize body consistency check.
3+ use std:: sync:: Arc ;
4+
35use rmcp:: transport:: streamable_http_server:: {
46 StreamableHttpServerConfig , StreamableHttpService , session:: local:: LocalSessionManager ,
57} ;
@@ -16,10 +18,17 @@ fn init_body(body_version: &str) -> String {
1618
1719async fn spawn_server (
1820 config : StreamableHttpServerConfig ,
21+ ) -> ( reqwest:: Client , String , CancellationToken ) {
22+ spawn_server_with_manager ( config, Arc :: new ( LocalSessionManager :: default ( ) ) ) . await
23+ }
24+
25+ async fn spawn_server_with_manager (
26+ config : StreamableHttpServerConfig ,
27+ session_manager : Arc < LocalSessionManager > ,
1928) -> ( reqwest:: Client , String , CancellationToken ) {
2029 let ct = config. cancellation_token . clone ( ) ;
2130 let service: StreamableHttpService < Calculator , LocalSessionManager > =
22- StreamableHttpService :: new ( || Ok ( Calculator :: new ( ) ) , Default :: default ( ) , config) ;
31+ StreamableHttpService :: new ( || Ok ( Calculator :: new ( ) ) , session_manager , config) ;
2332
2433 let router = axum:: Router :: new ( ) . nest_service ( "/mcp" , service) ;
2534 let tcp_listener = tokio:: net:: TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
@@ -71,6 +80,17 @@ async fn post_init(
7180 req. send ( ) . await . expect ( "send initialize request" )
7281}
7382
83+ async fn post_non_initialize ( client : & reqwest:: Client , url : & str ) -> reqwest:: Response {
84+ client
85+ . post ( url)
86+ . header ( "Content-Type" , "application/json" )
87+ . header ( "Accept" , "application/json, text/event-stream" )
88+ . body ( r#"{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}"# )
89+ . send ( )
90+ . await
91+ . expect ( "send non-initialize request" )
92+ }
93+
7494#[ tokio:: test]
7595async fn stateless_init_rejects_when_header_older_than_body ( ) -> anyhow:: Result < ( ) > {
7696 let ( client, url, ct) = spawn_server ( stateless_json_config ( ) ) . await ;
@@ -147,3 +167,21 @@ async fn stateful_init_rejects_when_header_mismatches_body() -> anyhow::Result<(
147167 ct. cancel ( ) ;
148168 Ok ( ( ) )
149169}
170+
171+ #[ tokio:: test]
172+ async fn stateful_rejected_initial_posts_do_not_create_sessions ( ) -> anyhow:: Result < ( ) > {
173+ let session_manager = Arc :: new ( LocalSessionManager :: default ( ) ) ;
174+ let ( client, url, ct) =
175+ spawn_server_with_manager ( stateful_config ( ) , session_manager. clone ( ) ) . await ;
176+
177+ let response = post_non_initialize ( & client, & url) . await ;
178+ assert_eq ! ( response. status( ) , 422 ) ;
179+ assert_eq ! ( session_manager. sessions. read( ) . await . len( ) , 0 ) ;
180+
181+ let response = post_init ( & client, & url, Some ( "2024-11-05" ) , "2025-11-25" ) . await ;
182+ assert_eq ! ( response. status( ) , 400 ) ;
183+ assert_eq ! ( session_manager. sessions. read( ) . await . len( ) , 0 ) ;
184+
185+ ct. cancel ( ) ;
186+ Ok ( ( ) )
187+ }
0 commit comments