- Author(s): Artem Bukhonov
- Champion: @benbrandt
Elevator pitch
Introduce a standardized per-request cancellation mechanism for the Agent Client Protocol, inspired by the Language Server Protocol (LSP), to enable a more granular cancellation of requests where individual JSON-RPC requests can be cancelled one by one.Status quo
The JSON-RPC specification doesn’t define any standard mechanism for request cancellation and leaves it up to the implementation. Currently, ACP has some ad-hoc cancellation mechanisms for specific features (like prompt turn cancellation viasession/cancel), but lacks a general-purpose, per-request cancellation mechanism.
This creates the following inconveniences:
- cancellation should be handled for each feature separately
- some languages that support handy cancellation mechanisms (C#, Kotlin, etc.) can’t implement general-purpose request cancellation using ACP low-level machinery, and rather developers should manually call per-feature cancellation methods
What we propose to do about it
Implement an optional$/cancel_request notification method (inspired by the Language Server Protocol) to both Agent and Client that uses JSON-RPC 2.0 notification format, allowing either party (client or agent) to cancel any outstanding request by its ID.
The mechanism will be:
- Optional: Not all implementations may support this feature, but it is recommended for those that do.
- Flexible: Provides two response options when cancellation is received:
- An error response with the standard cancellation error code (-32800)
- A valid response with partial or cancelled data (when meaningful partial results exist)
Shiny future
Once implemented, this enables:- SDK integration layer: Default mechanism that ACP SDKs can automatically wire to native language cancellation (C# CancellationToken, Kotlin Job, Go context.Context, JavaScript AbortController, etc.)
- Individual JSON-RPC request cancellation without affecting other concurrent requests
- Universal fallback for any request when feature-specific cancellation methods don’t exist
- Consistent cancellation behavior from both external
$/cancel_requestand internal cancellation triggers - Standard error response (
-32800) or partial results when requests are cancelled regardless of cancellation source
session/cancel notification in favor of the more general approach, as it would still provide the same functionality but with more flexibility and consistency.
Implementation details and plan
Protocol Changes
Cancellation Method
Add the$/cancel_request notification method to the JSON-RPC protocol:
Cancellation Behavior
Either party can send$/cancel_request to cancel requests. Notifications whose methods start with ‘/cancel_request` notification. If an agent or client receives notifications starting with ’$/’ it is free to ignore the notification.
The receiving party is NOT required to:
- Perform special handling for unsupported cancellation requests
- Return custom errors for unsupported
$/cancel_requestnotifications
Cancellation Processing
When a$/cancel_request notification is received by a supporting implementation, it:
- MUST cancel the corresponding request activity and all nested activities related to that request
- MAY finish sending any pending notifications before responding
- MUST send one of these responses for the original request:
- A valid response with appropriate data (such as partial results or cancellation marker)
- An error response with code
-32800(Request Cancelled)
Internal Cancellation
Requests can also be cancelled internally by the executing party without receiving$/cancel_request:
- Client-side examples: User closes IDE, switches to different project, file becomes unavailable
- Agent-side examples: LLM context limit reached, internal timeout, resource constraints
- Send the same
-32800(Cancelled) error response as if$/cancel_requestwas received - Ensure consistent behavior regardless of cancellation source
Error Code
Add standard JSON-RPC error code-32800 for cancelled requests:
- Code:
-32800 - Message: “Request cancelled”
- Meaning: Execution of the method was aborted either due to a cancellation request from the caller or because of resource constraints or shutdown.
Frequently asked questions
What alternative approaches did you consider, and why did you settle on this one?
The core need is to add granular cancellation as a general mechanism for individual JSON-RPC requests, while feature-specific cancellation methods (likesession/cancel) remain useful for cases requiring additional domain semantics.
We selected the LSP-style $/cancel_request approach because:
- Serves as a default cancellation layer that SDK implementations can easily map to native language cancellation mechanisms
- Proven pattern familiar to developers from LSP ecosystem
- Works across all JSON-RPC transports (HTTP, WebSocket, stdio, pipes)
- Provides universal fallback when feature-specific cancellation doesn’t exist
- Complements existing feature-specific methods rather than replacing them
How does this relate to existing cancellation mechanisms like session/cancel?
The $/cancel_request mechanism is complementary to feature-specific cancellation:
$/cancel_request: Generic cancellation for any JSON-RPC request by IDsession/cancel: Feature-specific cancellation with additional semantics (e.g., cancels entire prompt turn context, triggers specific cleanup logic)
session/cancel provide:
- Domain-specific semantics and behavior
- Structured cleanup for complex operations
- Context-aware cancellation logic
$/cancel_request provides:
- Default cancellation layer that bridges programming language cancellation mechanisms (C# CancellationToken, Kotlin Job, Go context.Context, etc.) with ACP
- Universal fallback for any request when no feature-specific method exists
- Simple ID-based targeting for SDK convenience
- Standardized error responses
$/cancel_request for simple per-request cancellation.
Note: it is possible that session/cancel could be replaced by the more generic $/cancel_request in future versions of the protocol.
Example: Cascading Cancellation Flow
What happens if a request completes before the cancellation is processed?
If a request completes normally before the cancellation notification is processed, the implementation should:- Send the normal response (not a cancellation error)
- Ignore the subsequent cancellation notification for that request ID
How should implementations handle cascading cancellation?
When a request is cancelled, implementations should:- Cancel the primary request activity
- Propagate cancellation to any nested/child requests
- Clean up resources associated with the entire request tree
- Send cancellation responses for all affected requests
Revision history
- 2025-11-13: Initial version converted from PR #183
- 2025-12-05: Updated with current implementation.
- 2025-12-09: Mirror LSP behavior.