@@ -4350,18 +4350,44 @@ def server_context
43504350 end
43514351 end
43524352
4353- test "#handle tools/call and prompts/get ignore a _meta that is not an object" do
4354- @server . define_tool ( name : "echo_tool" ) { Tool ::Response . new ( [ ] ) }
4353+ test "#handle refuses a _meta that is not an object with -32602 before any handler runs" do
4354+ calls = 0
4355+ server = Server . new ( name : "meta_server" , server_context : { user : "u" } )
4356+ # Reads `_meta` as the server context page shows (`dig`), which raises TypeError on a String or an Array.
4357+ server . define_tool ( name : "meta_reader" ) do |server_context :|
4358+ calls += 1
4359+ server_context . dig ( :_meta , :key )
4360+ Tool ::Response . new ( [ ] )
4361+ end
4362+
4363+ [ "not-an-object" , [ ] , 42 ] . each do |meta |
4364+ [
4365+ [ server , { jsonrpc : "2.0" , method : "tools/call" , id : 1 , params : { name : "meta_reader" , _meta : meta } } ] ,
4366+ [ server , { jsonrpc : "2.0" , method : "tools/call" , id : 1 , params : { name : "meta_reader" , "_meta" => meta } } ] ,
4367+ [ server , { jsonrpc : "2.0" , method : "tools/list" , id : 1 , params : { _meta : meta } } ] ,
4368+ [ @server , { jsonrpc : "2.0" , method : "prompts/get" , id : 1 , params : { name : "test_prompt" , arguments : { test_argument : "x" } , _meta : meta } } ] ,
4369+ ] . each do |target , request |
4370+ response = target . handle ( request )
4371+ assert_equal ( -32602 , response [ :error ] [ :code ] , request . inspect )
4372+ assert_equal "Invalid params: _meta must be an object" , response [ :error ] [ :message ]
4373+ end
4374+ end
4375+ assert_equal 0 , calls
43554376
4356- [ "not-an- object" , [ ] ] . each do | meta |
4357- tool = @ server. handle ( { jsonrpc : "2.0" , method : "tools/call" , id : 1 , params : { name : "echo_tool " , _meta : meta } } )
4358- prompt = @ server. handle ( {
4359- jsonrpc : "2.0" , method : "prompts/get" , id : 1 , params : { name : "test_prompt" , arguments : { test_argument : "x" } , _meta : meta } ,
4360- } )
4377+ # `null` reads as absent and an object reaches the handler, where the documented `dig` works on both.
4378+ assert_nil server . handle ( { jsonrpc : "2.0" , method : "tools/call" , id : 1 , params : { name : "meta_reader " , _meta : nil } } ) [ :error ]
4379+ assert_nil server . handle ( { jsonrpc : "2.0" , method : "tools/call" , id : 1 , params : { name : "meta_reader" , _meta : { key : "v" } } } ) [ :error ]
4380+ assert_equal 2 , calls
4381+ end
43614382
4362- assert_nil tool [ :error ]
4363- assert_nil prompt [ :error ]
4364- end
4383+ test "#handle drops a notification whose _meta is not an object without running its handler" do
4384+ calls = 0
4385+ @server . define_custom_method ( method_name : "custom/notify" ) { |_params | calls += 1 }
4386+
4387+ assert_nil @server . handle ( { jsonrpc : "2.0" , method : "custom/notify" , params : { _meta : "not-an-object" } } )
4388+ assert_equal 0 , calls
4389+ assert_nil @server . handle ( { jsonrpc : "2.0" , method : "custom/notify" , params : { _meta : { key : "v" } } } )
4390+ assert_equal 1 , calls
43654391 end
43664392
43674393 test "#handle tools/call mirrors non-object structuredContent when content is omitted or nil" do
0 commit comments