99module MCP
1010 class Client
1111 class StdioTest < Minitest ::Test
12- IMPLICIT_CONNECT_DEPRECATION_WARNING =
13- /Calling `MCP::Client::Stdio#send_request` without calling `MCP::Client#connect` is deprecated\. Use `MCP::Client#connect` before sending requests instead\. / . freeze
12+ def test_send_request_raises_when_connect_not_called
13+ Open3 . expects ( :popen3 ) . never
14+
15+ transport = Stdio . new ( command : "ruby" , args : [ "server.rb" ] )
16+
17+ error = assert_raises ( RuntimeError ) do
18+ transport . send_request ( request : { jsonrpc : "2.0" , id : "test-id" , method : "tools/list" } )
19+ end
20+
21+ assert_equal ( "MCP::Client#connect must be called before sending requests." , error . message )
22+ end
1423
1524 def test_send_request_starts_process_and_returns_response
1625 stdin_read , stdin_write = IO . pipe
@@ -59,10 +68,8 @@ def test_send_request_starts_process_and_returns_response
5968 stdout_write . flush
6069 end
6170
62- response = nil
63- assert_implicit_connect_deprecation_warning do
64- response = transport . send_request ( request : request )
65- end
71+ transport . connect
72+ response = transport . send_request ( request : request )
6673
6774 assert_equal ( "test-id" , response [ "id" ] )
6875 assert_equal ( 1 , response . dig ( "result" , "tools" ) . size )
@@ -76,73 +83,6 @@ def test_send_request_starts_process_and_returns_response
7683 stderr_read . close
7784 end
7885
79- def test_send_request_initializes_session_on_first_call
80- stdin_read , stdin_write = IO . pipe
81- stdout_read , stdout_write = IO . pipe
82- stderr_read , _ = IO . pipe
83-
84- Open3 . stubs ( :popen3 ) . returns ( [ stdin_write , stdout_read , stderr_read , mock_wait_thread ] )
85-
86- transport = Stdio . new ( command : "ruby" , args : [ "server.rb" ] )
87-
88- request = {
89- jsonrpc : "2.0" ,
90- id : "test-id" ,
91- method : "tools/list" ,
92- }
93-
94- received_methods = [ ]
95-
96- server_thread = Thread . new do
97- # Read initialize request
98- init_line = stdin_read . gets
99- init_request = JSON . parse ( init_line )
100- received_methods << init_request [ "method" ]
101-
102- init_response = {
103- jsonrpc : "2.0" ,
104- id : init_request [ "id" ] ,
105- result : {
106- protocolVersion : "2025-11-25" ,
107- capabilities : { } ,
108- serverInfo : { name : "test-server" , version : "1.0.0" } ,
109- } ,
110- }
111- stdout_write . puts ( JSON . generate ( init_response ) )
112- stdout_write . flush
113-
114- # Read initialized notification
115- notification_line = stdin_read . gets
116- notification = JSON . parse ( notification_line )
117- received_methods << notification [ "method" ]
118-
119- # Read tools/list request
120- tools_line = stdin_read . gets
121- tools_request = JSON . parse ( tools_line )
122- received_methods << tools_request [ "method" ]
123-
124- tools_response = {
125- jsonrpc : "2.0" ,
126- id : tools_request [ "id" ] ,
127- result : { tools : [ ] } ,
128- }
129- stdout_write . puts ( JSON . generate ( tools_response ) )
130- stdout_write . flush
131- end
132-
133- assert_implicit_connect_deprecation_warning do
134- transport . send_request ( request : request )
135- end
136-
137- assert_equal ( [ "initialize" , "notifications/initialized" , "tools/list" ] , received_methods )
138- ensure
139- server_thread . join
140- stdin_read . close
141- stdin_write . close
142- stdout_read . close
143- stdout_write . close
144- end
145-
14686 def test_send_request_skips_notifications
14787 stdin_read , stdin_write = IO . pipe
14888 stdout_read , stdout_write = IO . pipe
@@ -193,10 +133,8 @@ def test_send_request_skips_notifications
193133 stdout_write . flush
194134 end
195135
196- response = nil
197- assert_implicit_connect_deprecation_warning do
198- response = transport . send_request ( request : request )
199- end
136+ transport . connect
137+ response = transport . send_request ( request : request )
200138
201139 assert_equal ( "test-id" , response [ "id" ] )
202140 assert_empty ( response . dig ( "result" , "tools" ) )
@@ -223,17 +161,8 @@ def test_send_request_raises_error_when_process_exits
223161 transport = Stdio . new ( command : "ruby" , args : [ "server.rb" ] )
224162 transport . start
225163
226- request = {
227- jsonrpc : "2.0" ,
228- id : "test-id" ,
229- method : "tools/list" ,
230- }
231-
232- error = nil
233- assert_implicit_connect_deprecation_warning do
234- error = assert_raises ( RequestHandlerError ) do
235- transport . send_request ( request : request )
236- end
164+ error = assert_raises ( RequestHandlerError ) do
165+ transport . connect
237166 end
238167
239168 assert_equal ( "Server process has exited" , error . message )
@@ -283,11 +212,9 @@ def test_send_request_raises_error_on_closed_stdout
283212 stdout_write . close
284213 end
285214
286- error = nil
287- assert_implicit_connect_deprecation_warning do
288- error = assert_raises ( RequestHandlerError ) do
289- transport . send_request ( request : request )
290- end
215+ transport . connect
216+ error = assert_raises ( RequestHandlerError ) do
217+ transport . send_request ( request : request )
291218 end
292219
293220 assert_equal ( "Server process closed stdout unexpectedly" , error . message )
@@ -341,7 +268,7 @@ def test_close_resets_state
341268 stderr_write . close
342269 end
343270
344- def test_send_request_skips_initialization_on_second_call
271+ def test_multiple_send_requests_do_not_reinitialize
345272 stdin_read , stdin_write = IO . pipe
346273 stdout_read , stdout_write = IO . pipe
347274 stderr_read , _ = IO . pipe
@@ -398,9 +325,8 @@ def test_send_request_skips_initialization_on_second_call
398325 stdout_write . flush
399326 end
400327
401- assert_implicit_connect_deprecation_warning do
402- transport . send_request ( request : { jsonrpc : "2.0" , id : "first" , method : "tools/list" } )
403- end
328+ transport . connect
329+ transport . send_request ( request : { jsonrpc : "2.0" , id : "first" , method : "tools/list" } )
404330 transport . send_request ( request : { jsonrpc : "2.0" , id : "second" , method : "tools/list" } )
405331
406332 assert_equal (
@@ -464,11 +390,9 @@ def test_send_request_raises_error_on_invalid_json
464390 stdout_write . flush
465391 end
466392
467- error = nil
468- assert_implicit_connect_deprecation_warning do
469- error = assert_raises ( RequestHandlerError ) do
470- transport . send_request ( request : request )
471- end
393+ transport . connect
394+ error = assert_raises ( RequestHandlerError ) do
395+ transport . send_request ( request : request )
472396 end
473397
474398 assert_equal ( "Failed to parse server response" , error . message )
@@ -482,50 +406,6 @@ def test_send_request_raises_error_on_invalid_json
482406 stdout_write . close
483407 end
484408
485- def test_send_request_raises_error_when_initialization_fails
486- stdin_read , stdin_write = IO . pipe
487- stdout_read , stdout_write = IO . pipe
488- stderr_read , _ = IO . pipe
489-
490- Open3 . stubs ( :popen3 ) . returns ( [ stdin_write , stdout_read , stderr_read , mock_wait_thread ] )
491-
492- transport = Stdio . new ( command : "ruby" , args : [ "server.rb" ] )
493-
494- request = {
495- jsonrpc : "2.0" ,
496- id : "test-id" ,
497- method : "tools/list" ,
498- }
499-
500- server_thread = Thread . new do
501- # Read initialize request and return an error
502- init_line = stdin_read . gets
503- init_request = JSON . parse ( init_line )
504- stdout_write . puts ( JSON . generate ( {
505- jsonrpc : "2.0" ,
506- id : init_request [ "id" ] ,
507- error : { code : -32600 , message : "Invalid Request" , data : "Unsupported protocol version" } ,
508- } ) )
509- stdout_write . flush
510- end
511-
512- error = nil
513- assert_implicit_connect_deprecation_warning do
514- error = assert_raises ( RequestHandlerError ) do
515- transport . send_request ( request : request )
516- end
517- end
518-
519- assert_equal ( "Server initialization failed: Invalid Request" , error . message )
520- assert_equal ( :internal_error , error . error_type )
521- ensure
522- server_thread . join
523- stdin_read . close
524- stdin_write . close
525- stdout_read . close
526- stdout_write . close
527- end
528-
529409 def test_close_kills_process_on_timeout
530410 stdin_read , stdin_write = IO . pipe
531411 stdout_read , stdout_write = IO . pipe
@@ -589,11 +469,9 @@ def test_read_response_raises_error_on_timeout
589469 stdin_read . gets
590470 end
591471
592- error = nil
593- assert_implicit_connect_deprecation_warning do
594- error = assert_raises ( RequestHandlerError ) do
595- transport . send_request ( request : request )
596- end
472+ transport . connect
473+ error = assert_raises ( RequestHandlerError ) do
474+ transport . send_request ( request : request )
597475 end
598476
599477 assert_equal ( "Timed out waiting for server response" , error . message )
@@ -644,10 +522,9 @@ def test_send_request_raises_error_when_stdin_is_closed
644522 stdout_write . flush
645523 end
646524
647- # Complete handshake with a successful request
648- assert_implicit_connect_deprecation_warning do
649- transport . send_request ( request : { jsonrpc : "2.0" , id : "setup" , method : "ping" } )
650- end
525+ transport . connect
526+ # Complete a successful request before breaking the pipe.
527+ transport . send_request ( request : { jsonrpc : "2.0" , id : "setup" , method : "ping" } )
651528 server_thread . join
652529
653530 # Now close stdin to simulate broken pipe
@@ -713,49 +590,6 @@ def test_start_raises_error_for_invalid_command
713590 assert_instance_of ( Errno ::ENOENT , error . original_error )
714591 end
715592
716- def test_send_request_raises_error_for_missing_result
717- stdin_read , stdin_write = IO . pipe
718- stdout_read , stdout_write = IO . pipe
719- stderr_read , _ = IO . pipe
720-
721- Open3 . stubs ( :popen3 ) . returns ( [ stdin_write , stdout_read , stderr_read , mock_wait_thread ] )
722-
723- transport = Stdio . new ( command : "ruby" , args : [ "server.rb" ] )
724-
725- request = {
726- jsonrpc : "2.0" ,
727- id : "test-id" ,
728- method : "tools/list" ,
729- }
730-
731- server_thread = Thread . new do
732- # Read initialize request and return a response without result
733- init_line = stdin_read . gets
734- init_request = JSON . parse ( init_line )
735- stdout_write . puts ( JSON . generate ( {
736- jsonrpc : "2.0" ,
737- id : init_request [ "id" ] ,
738- } ) )
739- stdout_write . flush
740- end
741-
742- error = nil
743- assert_implicit_connect_deprecation_warning do
744- error = assert_raises ( RequestHandlerError ) do
745- transport . send_request ( request : request )
746- end
747- end
748-
749- assert_equal ( "Server initialization failed: missing result in response" , error . message )
750- assert_equal ( :internal_error , error . error_type )
751- ensure
752- server_thread . join
753- stdin_read . close
754- stdin_write . close
755- stdout_read . close
756- stdout_write . close
757- end
758-
759593 def test_connect_performs_initialize_handshake_explicitly
760594 stdin_read , stdin_write = IO . pipe
761595 stdout_read , stdout_write = IO . pipe
@@ -1343,14 +1177,6 @@ def test_concurrent_write_message_does_not_interleave_lines
13431177
13441178 private
13451179
1346- def assert_implicit_connect_deprecation_warning ( &block )
1347- original_verbose = $VERBOSE
1348- $VERBOSE = false
1349- assert_output ( nil , IMPLICIT_CONNECT_DEPRECATION_WARNING , &block )
1350- ensure
1351- $VERBOSE = original_verbose
1352- end
1353-
13541180 def stub_successful_connect
13551181 stdin_read , stdin_write = IO . pipe
13561182 stdout_read , stdout_write = IO . pipe
0 commit comments