@@ -9,11 +9,102 @@ use common::handlers::TestClientHandler;
99use rmcp:: {
1010 ServiceExt ,
1111 model:: {
12- ErrorCode , ErrorData , JsonRpcError , JsonRpcVersion2_0 , RequestId , ServerJsonRpcMessage ,
12+ ClientJsonRpcMessage , ErrorCode , ErrorData , InitializeResult , JsonRpcError ,
13+ JsonRpcVersion2_0 , RequestId , ServerCapabilities , ServerJsonRpcMessage , ServerResult ,
1314 } ,
1415 transport:: { IntoTransport , Transport } ,
1516} ;
1617
18+ fn stringify_numeric_id ( id : RequestId ) -> RequestId {
19+ let RequestId :: Number ( id) = id else {
20+ panic ! ( "expected a numeric request ID" ) ;
21+ } ;
22+ RequestId :: String ( id. to_string ( ) . into ( ) )
23+ }
24+
25+ #[ tokio:: test]
26+ async fn client_initialization_accepts_stringified_numeric_response_id ( ) {
27+ let ( server_transport, client_transport) = tokio:: io:: duplex ( 1024 ) ;
28+ let mut server = IntoTransport :: < rmcp:: RoleServer , _ , _ > :: into_transport ( server_transport) ;
29+ let server_task = tokio:: spawn ( async move {
30+ let ClientJsonRpcMessage :: Request ( request) =
31+ server. receive ( ) . await . expect ( "expected initialize request" )
32+ else {
33+ panic ! ( "expected initialize request" ) ;
34+ } ;
35+ server
36+ . send ( ServerJsonRpcMessage :: response (
37+ ServerResult :: InitializeResult (
38+ InitializeResult :: new ( ServerCapabilities :: default ( ) ) ,
39+ ) ,
40+ stringify_numeric_id ( request. id ) ,
41+ ) )
42+ . await
43+ . expect ( "send initialize response" ) ;
44+ assert ! ( matches!(
45+ server. receive( ) . await ,
46+ Some ( ClientJsonRpcMessage :: Notification ( _) )
47+ ) ) ;
48+ } ) ;
49+
50+ let client = TestClientHandler :: new ( true , true )
51+ . serve ( client_transport)
52+ . await
53+ . expect ( "client should accept stringified initialize response ID" ) ;
54+ client. cancel ( ) . await . expect ( "cancel client" ) ;
55+ server_task. await . expect ( "server task" ) ;
56+ }
57+
58+ #[ tokio:: test]
59+ async fn client_correlates_stringified_numeric_response_id ( ) {
60+ let ( server_transport, client_transport) = tokio:: io:: duplex ( 1024 ) ;
61+ let mut server = IntoTransport :: < rmcp:: RoleServer , _ , _ > :: into_transport ( server_transport) ;
62+ let server_task = tokio:: spawn ( async move {
63+ let ClientJsonRpcMessage :: Request ( initialize) =
64+ server. receive ( ) . await . expect ( "expected initialize request" )
65+ else {
66+ panic ! ( "expected initialize request" ) ;
67+ } ;
68+ server
69+ . send ( ServerJsonRpcMessage :: response (
70+ ServerResult :: InitializeResult (
71+ InitializeResult :: new ( ServerCapabilities :: default ( ) ) ,
72+ ) ,
73+ initialize. id ,
74+ ) )
75+ . await
76+ . expect ( "send initialize response" ) ;
77+ assert ! ( matches!(
78+ server. receive( ) . await ,
79+ Some ( ClientJsonRpcMessage :: Notification ( _) )
80+ ) ) ;
81+
82+ let ClientJsonRpcMessage :: Request ( request) =
83+ server. receive ( ) . await . expect ( "expected tools/list request" )
84+ else {
85+ panic ! ( "expected tools/list request" ) ;
86+ } ;
87+ server
88+ . send ( ServerJsonRpcMessage :: response (
89+ ServerResult :: ListToolsResult ( Default :: default ( ) ) ,
90+ stringify_numeric_id ( request. id ) ,
91+ ) )
92+ . await
93+ . expect ( "send tools/list response" ) ;
94+ } ) ;
95+
96+ let client = TestClientHandler :: new ( true , true )
97+ . serve ( client_transport)
98+ . await
99+ . expect ( "initialize client" ) ;
100+ client
101+ . list_tools ( None )
102+ . await
103+ . expect ( "client should correlate stringified response ID" ) ;
104+ client. cancel ( ) . await . expect ( "cancel client" ) ;
105+ server_task. await . expect ( "server task" ) ;
106+ }
107+
17108#[ tokio:: test]
18109async fn test_client_init_handles_jsonrpc_error ( ) {
19110 let ( server_transport, client_transport) = tokio:: io:: duplex ( 1024 ) ;
0 commit comments