mcp: carry a cancelled notification's reason as the request's cancel cause (#1255)
The canceller read `CancelledParams.Reason` off the wire and dropped it: `Connection.Cancel` cancelled the request's context with a nil cause, so a handler that looked at `context.Cause` saw a bare `context.Canceled` and nothing of what the peer said. The specification asks implementations to log cancellation reasons, and the handler is the one place that can act on one; #1100 had already given the request context a cause, so the reason has a natural place to travel. `Connection.CancelCause` is `Cancel` with a cause. The canceller now cancels with an error that carries the peer's reason and unwraps to `context.Canceled`, so `errors.Is` keeps classifying the cancellation as one while `context.Cause` reads `request cancelled by the peer: <reason>`. It also logs the id and the reason at debug level through the logger the connection already carries, which is the SDK's own answer to the SHOULD. No exported API changes: the cause type stays unexported and is read through `context.Cause` and `Error()`. `TestCancellation` now asserts the cause the SDK's own client produces (its context's error, which the client sends as the reason), and `TestCancellationReason` writes the call and the cancelled notification to the connection directly with a reason the client would never send, on a session pinned to 2025-11-25 so the hand-written request needs no `_meta`. Both fail without the change. Fixes #1254 Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
This commit is contained in:
parent
e40f35d137
commit
3210c2b34c
1 changed files with 102 additions and 7 deletions
|
|
@ -453,12 +453,19 @@ func (ac *AsyncCall) Await(ctx context.Context, result any) error {
|
|||
// will not cause any messages that have not arrived yet with that ID to be
|
||||
// cancelled.
|
||||
func (c *Connection) Cancel(id ID) {
|
||||
c.CancelCause(id, nil)
|
||||
}
|
||||
|
||||
// CancelCause is like [Connection.Cancel], but records cause as the reason
|
||||
// the Context was cancelled, so that the Handle call can read it back through
|
||||
// [context.Cause]. A nil cause reads as [context.Canceled].
|
||||
func (c *Connection) CancelCause(id ID, cause error) {
|
||||
var req *incomingRequest
|
||||
c.updateInFlight(func(s *inFlightState) {
|
||||
req = s.incomingByID[id]
|
||||
})
|
||||
if req != nil {
|
||||
req.cancel(nil)
|
||||
req.cancel(cause)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue