Skip to content

mcp/transport.go call() attempts to call Notify() on a failed connection #882

@smlx

Description

@smlx

Describe the bug
I am using mcp.StreamableClientTransport with an OAuthHandler. As documented, this handler will automatically be invoked by go-sdk on e.g. a 401 from the MCP endpoint.

My client implement an interactive OAuth2 authorization flow using the newly exposed APIs in v1.5.0-pre.

The behaviour I am seeing that I believe to be a bug is this:

  1. I configure a new MCP server endpoint in my client config.
  2. My client tries to use the MCP server via the StreamableClientTransport.
  3. It receives a 401 and calls Authorize() on my OAuthHandler.
  4. The context passed to Authorize() times out.
  5. In the switch statement in call(), the execution flow enters the case where ctx.Err() != nil. Here, conn.Notify is called. This Notify call, of course, receives a 401 which then calls Authorize() on my handler again.

In the case of my client, this prompts the user for interactive authorization again, even though the timeout has already cancelled the authorization request.

Relevant code is here:

go-sdk/mcp/transport.go

Lines 213 to 223 in 862d78a

call := conn.Call(ctx, method, params)
err := call.Await(ctx, result)
switch {
case errors.Is(err, jsonrpc2.ErrClientClosing), errors.Is(err, jsonrpc2.ErrServerClosing):
return fmt.Errorf("%w: calling %q: %v", ErrConnectionClosed, method, err)
case ctx.Err() != nil:
// Notify the peer of cancellation.
err := conn.Notify(xcontext.Detach(ctx), notificationCancelled, &CancelledParams{
Reason: ctx.Err().Error(),
RequestID: call.ID().Raw(),
})

To Reproduce
Steps to reproduce the behavior:

  1. Set up a StreamableClientTransport with an OAuthHandler.
  2. Use the transport without setting up authorization.
  3. Pass a context with a short timeout to Authorize(), and wait for it to expire before returning.

Expected behavior
I would expect cancelling the context passed to Authorize() to indicate that the connection should be abandoned and not to use it for any further communication.

Logs
n/a

Additional context
n/a

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Moderate issues, valuable feature requestsneeds investigationStatus unclear, requires more work and discussion

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions