fix(client): deduplicate concurrent OAuth refreshes - #2757
fix(client): deduplicate concurrent OAuth refreshes#2757CharlesMcMillan wants to merge 3 commits into
Conversation
🦋 Changeset detectedLatest commit: 3b205e7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@claude review |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
Wrap complete auth recovery in an optional provider transaction. Serialize incompatible ordinary calls without dropping their options, while code exchange and forced reauthorization continue to bypass the queue. Normalize null error descriptions only at the client parser boundary.
|
@claude review |
|
Current head 3b205e7 has one failing check: client-conformance reports sse-retry as 2 passes plus a timing warning. The isolated scenario passes locally (503 ms reconnect vs 500 ms target), while the auth scenarios pass in CI. I cannot rerun the failed job with contributor permissions (GitHub requires repository admin rights). Could a maintainer rerun job 101554954460 / run 34058603161? No test suppression or unrelated SSE changes are included. |
|
Filed modelcontextprotocol/conformance#500 for the unrelated SSE timing warning. The follow-up will bound client-suite concurrency and isolate timing-sensitive scenarios without weakening the SSE check or adding it to expected failures. I added the link and plan to this PR description; it should not block the OAuth change. |
Summary
Prevent overlapping OAuth refresh calls from redeeming the same rotating refresh token. Equivalent calls sharing a provider share one pending result; calls with different auth options are serialized and execute their own discovery and validation. Authorization-code exchanges and forced reauthorization remain distinct operations.
Hosts sharing credentials across processes can implement the optional
withAuthTransactionprovider hook. It wraps the complete auth operation, including error recovery and persistence, so hosts can release ownership in onefinallyinstead of inferring completion from individual provider callbacks. No lock spans browser consent.The client decoder also treats
error_description: nullas omitted, preserving an authorization server'sinvalid_grantclassification. The public OAuth schema stays strict.Fixes #1760. Replaces #1813. Adapter integration: nicobailon/pi-mcp-adapter#528.
Verification
5119ee7f; published CI is checked separately for each PR head.Follow-up
The unrelated
sse-retryconformance warning is tracked in modelcontextprotocol/conformance#500 and should not block this OAuth fix. The proposed follow-up adds bounded client-suite concurrency, runs timing-sensitive SSE checks outside the concurrent pool, preserves the harness's suite and expected-failure logic, and saves detailed artifacts on failure. Once that support is released, the SDK can update its pinned conformance package in a separate PR.