@@ -175,6 +175,30 @@ class StdioTransportTest < ActiveSupport::TestCase
175175 end
176176 end
177177
178+ test "open answers a frame whose JSON key is not valid UTF-8 with -32700 and keeps reading" do
179+ # `JSON.parse` with `symbolize_names` raises `EncodingError` for such a key, which ended the loop.
180+ # The frames are read as bytes here, so the key reaches the parser whatever `String#strip` does.
181+ frames = "{\" jsonrpc\" :\" 2.0\" ,\" id\" :1,\" method\" :\" ping\" ,\" k\xFF \" :1}\n " \
182+ "{\" jsonrpc\" :\" 2.0\" ,\" id\" :2,\" method\" :\" ping\" }\n "
183+ input = StringIO . new ( frames . b )
184+ output = StringIO . new
185+ original_stdin = $stdin
186+ original_stdout = $stdout
187+
188+ begin
189+ $stdin = input
190+ $stdout = output
191+ @transport . open
192+
193+ responses = output . string . lines . map { |line | JSON . parse ( line , symbolize_names : true ) }
194+ assert_equal ( -32700 , responses [ 0 ] [ :error ] [ :code ] )
195+ assert_equal ( { jsonrpc : "2.0" , id : 2 , result : { } } , responses [ 1 ] )
196+ ensure
197+ $stdin = original_stdin
198+ $stdout = original_stdout
199+ end
200+ end
201+
178202 test "rejects duplicate initialize on the same stdio session with -32600" do
179203 first = {
180204 jsonrpc : "2.0" ,
@@ -339,6 +363,37 @@ class StdioTransportTest < ActiveSupport::TestCase
339363 end
340364 end
341365
366+ test "send_request reports a client reply whose JSON key is not valid UTF-8 as a parse failure" do
367+ reader , writer = IO . pipe
368+
369+ # Read as bytes, so the key reaches the parser whatever `String#strip` does.
370+ reader . binmode
371+ output = StringIO . new
372+ original_stdin = $stdin
373+ original_stdout = $stdout
374+ reported = [ ]
375+ original_reporter = MCP . configuration . exception_reporter
376+
377+ begin
378+ MCP . configuration . exception_reporter = -> ( e , context ) { reported << [ e . class , context ] }
379+ $stdin = reader
380+ $stdout = output
381+ @transport . instance_variable_set ( :@open , true )
382+
383+ writer . write ( "{\" jsonrpc\" :\" 2.0\" ,\" id\" :\" x\" ,\" result\" :{\" k\xFF \" :1}}\n " . b )
384+ writer . flush
385+
386+ assert_raises ( EncodingError ) { @transport . send_request ( "test/method" ) }
387+ assert_equal ( [ [ EncodingError , { error : "Failed to parse response" } ] ] , reported )
388+ ensure
389+ MCP . configuration . exception_reporter = original_reporter
390+ $stdin = original_stdin
391+ $stdout = original_stdout
392+ writer . close
393+ reader . close
394+ end
395+ end
396+
342397 test "send_request does not double-report intentional raises via exception_reporter" do
343398 reader , writer = IO . pipe
344399 output = StringIO . new
0 commit comments