What did you do?
Sent notifications/cancelled for an in-flight tools/call, with a reason ("User requested cancellation"), to a server built on this SDK, over stdio. The tool handler blocks on ctx.Done() and logs context.Cause(ctx) when it fires.
What did you see?
The handler's context is cancelled, which is right, but context.Cause(ctx) is the bare context.Canceled and the reason string appears nowhere: not in the cause, not in the server's log. canceller.Preempt (mcp/transport.go) unmarshals CancelledParams, uses RequestID to find the request and discards Reason; Connection.Cancel (internal/jsonrpc2/conn.go) then cancels the request's context with a nil cause.
What did you expect to see?
The reason reaching the handler, and ideally logged by the SDK. The specification's cancellation page says "Implementations SHOULD log cancellation reasons for debugging", and nothing on the application side can do that today, since the value is dropped before any handler or middleware runs. #1100 already plumbed causes through the request context (context.WithCancelCause in acceptRequest, context.Cause in handleAsync), so the reason has a natural place to travel: as the cause of the cancellation.
What version of the Go MCP SDK are you using?
v1.7.0, and the behavior is the same at main (5bc078a).
What version of Go are you using (go version)?
go1.27.1 linux/amd64.
I have a small change ready that adds Connection.CancelCause, makes the canceller cancel with an error carrying the reason (unwrapping to context.Canceled, so errors.Is keeps working) and logs the id and reason at debug level through the logger the connection already carries, with tests on both the SDK client's own cancellation and a hand-written notification. I will open it as a PR against this issue. Found while building an MCP server on this SDK, where the missing reason was noticed in an audit of the server's cancellation handling.
What did you do?
Sent
notifications/cancelledfor an in-flighttools/call, with areason("User requested cancellation"), to a server built on this SDK, over stdio. The tool handler blocks onctx.Done()and logscontext.Cause(ctx)when it fires.What did you see?
The handler's context is cancelled, which is right, but
context.Cause(ctx)is the barecontext.Canceledand the reason string appears nowhere: not in the cause, not in the server's log.canceller.Preempt(mcp/transport.go) unmarshalsCancelledParams, usesRequestIDto find the request and discardsReason;Connection.Cancel(internal/jsonrpc2/conn.go) then cancels the request's context with a nil cause.What did you expect to see?
The reason reaching the handler, and ideally logged by the SDK. The specification's cancellation page says "Implementations SHOULD log cancellation reasons for debugging", and nothing on the application side can do that today, since the value is dropped before any handler or middleware runs. #1100 already plumbed causes through the request context (
context.WithCancelCauseinacceptRequest,context.CauseinhandleAsync), so the reason has a natural place to travel: as the cause of the cancellation.What version of the Go MCP SDK are you using?
v1.7.0, and the behavior is the same at
main(5bc078a).What version of Go are you using (
go version)?go1.27.1 linux/amd64.
I have a small change ready that adds
Connection.CancelCause, makes the canceller cancel with an error carrying the reason (unwrapping tocontext.Canceled, soerrors.Iskeeps working) and logs the id and reason at debug level through the logger the connection already carries, with tests on both the SDK client's own cancellation and a hand-written notification. I will open it as a PR against this issue. Found while building an MCP server on this SDK, where the missing reason was noticed in an audit of the server's cancellation handling.