@@ -44,6 +44,10 @@ def initialize( # rubocop:disable Metrics/ParameterLists
4444
4545 @transport = nil
4646 @capabilities = nil
47+
48+ # Track in-flight server-initiated requests for cancellation
49+ @in_flight_requests = { }
50+ @in_flight_mutex = Mutex . new
4751 end
4852
4953 def request ( body , **options )
@@ -342,6 +346,41 @@ def sampling_callback_enabled?
342346 def transport
343347 @transport ||= Native ::Transport . new ( @transport_type , self , config : @config )
344348 end
349+
350+ # Register a server-initiated request that can be cancelled
351+ # @param request_id [String] The ID of the request
352+ # @param cancellable_operation [CancellableOperation, nil] The operation that can be cancelled
353+ def register_in_flight_request ( request_id , cancellable_operation = nil )
354+ @in_flight_mutex . synchronize do
355+ @in_flight_requests [ request_id . to_s ] = cancellable_operation
356+ end
357+ end
358+
359+ # Unregister a completed or cancelled request
360+ # @param request_id [String] The ID of the request
361+ def unregister_in_flight_request ( request_id )
362+ @in_flight_mutex . synchronize do
363+ @in_flight_requests . delete ( request_id . to_s )
364+ end
365+ end
366+
367+ # Cancel an in-flight server-initiated request
368+ # @param request_id [String] The ID of the request to cancel
369+ # @return [Boolean] true if the request was found and cancelled, false otherwise
370+ def cancel_in_flight_request ( request_id ) # rubocop:disable Naming/PredicateMethod
371+ operation = nil
372+ @in_flight_mutex . synchronize do
373+ operation = @in_flight_requests [ request_id . to_s ]
374+ end
375+
376+ if operation . respond_to? ( :cancel )
377+ operation . cancel
378+ true
379+ else
380+ RubyLLM ::MCP . logger . warn ( "Request #{ request_id } cannot be cancelled or was already completed" )
381+ false
382+ end
383+ end
345384 end
346385 end
347386 end
0 commit comments