@@ -144,6 +144,96 @@ def handle_request(request); end
144144 assert_nil response
145145 end
146146
147+ test "id-bearing notifications/cancelled is rejected with Method not found, not result: null" do
148+ response = @session . handle (
149+ jsonrpc : "2.0" ,
150+ id : 1001 ,
151+ method : Methods ::NOTIFICATIONS_CANCELLED ,
152+ )
153+
154+ assert_equal 1001 , response [ :id ]
155+ refute response . key? ( :result )
156+ assert_equal JsonRpcHandler ::ErrorCode ::METHOD_NOT_FOUND , response . dig ( :error , :code )
157+ end
158+
159+ test "id-bearing notifications/initialized is rejected with Method not found" do
160+ response = @session . handle (
161+ jsonrpc : "2.0" ,
162+ id : 1002 ,
163+ method : Methods ::NOTIFICATIONS_INITIALIZED ,
164+ )
165+
166+ assert_equal 1002 , response [ :id ]
167+ refute response . key? ( :result )
168+ assert_equal JsonRpcHandler ::ErrorCode ::METHOD_NOT_FOUND , response . dig ( :error , :code )
169+ end
170+
171+ test "id-bearing notifications/progress is rejected with Method not found" do
172+ response = @session . handle (
173+ jsonrpc : "2.0" ,
174+ id : 1003 ,
175+ method : Methods ::NOTIFICATIONS_PROGRESS ,
176+ params : { progressToken : "tok" , progress : 1 } ,
177+ )
178+
179+ assert_equal 1003 , response [ :id ]
180+ refute response . key? ( :result )
181+ assert_equal JsonRpcHandler ::ErrorCode ::METHOD_NOT_FOUND , response . dig ( :error , :code )
182+ end
183+
184+ test "well-formed notifications/initialized still receives no response" do
185+ response = @session . handle (
186+ jsonrpc : "2.0" ,
187+ method : Methods ::NOTIFICATIONS_INITIALIZED ,
188+ )
189+
190+ assert_nil response
191+ end
192+
193+ test "id-bearing notification mixed into a batch yields only its Method not found error" do
194+ responses = @session . handle ( [
195+ { jsonrpc : "2.0" , method : Methods ::NOTIFICATIONS_CANCELLED , params : { requestId : "x" } } ,
196+ { jsonrpc : "2.0" , id : 2001 , method : Methods ::NOTIFICATIONS_CANCELLED } ,
197+ { jsonrpc : "2.0" , id : 2002 , method : Methods ::PING } ,
198+ ] )
199+
200+ cancelled_error = responses . find { |response | response [ :id ] == 2001 }
201+ assert_equal JsonRpcHandler ::ErrorCode ::METHOD_NOT_FOUND , cancelled_error . dig ( :error , :code )
202+
203+ ping_response = responses . find { |response | response [ :id ] == 2002 }
204+ assert_equal ( { } , ping_response [ :result ] )
205+
206+ # The well-formed notification carries no id and contributes no response.
207+ assert_equal 2 , responses . size
208+ end
209+
210+ test "id-bearing custom notifications/* method is rejected with Method not found" do
211+ called = false
212+ @server . define_custom_method ( method_name : "notifications/custom" ) { called = true }
213+
214+ response = @session . handle (
215+ jsonrpc : "2.0" ,
216+ id : 3001 ,
217+ method : "notifications/custom" ,
218+ )
219+
220+ assert_equal JsonRpcHandler ::ErrorCode ::METHOD_NOT_FOUND , response . dig ( :error , :code )
221+ refute called
222+ end
223+
224+ test "well-formed custom notifications/* method is dispatched without a response" do
225+ called = false
226+ @server . define_custom_method ( method_name : "notifications/custom" ) { called = true }
227+
228+ response = @session . handle (
229+ jsonrpc : "2.0" ,
230+ method : "notifications/custom" ,
231+ )
232+
233+ assert_nil response
234+ assert called
235+ end
236+
147237 test "duplicate cancellation for the same in-flight request is idempotent" do
148238 @server . define_tool ( name : "slow_dup" ) do |server_context :|
149239 20 . times do
0 commit comments