Skip to content

feat(client/auth): RFC 9207 iss parameter validation (SEP-2468 reference impl)#1957

Draft
pcarleton wants to merge 43 commits intomainfrom
paulc/sep-2468-iss-validation
Draft

feat(client/auth): RFC 9207 iss parameter validation (SEP-2468 reference impl)#1957
pcarleton wants to merge 43 commits intomainfrom
paulc/sep-2468-iss-validation

Conversation

@pcarleton
Copy link
Copy Markdown
Member

Reference implementation for SEP-2468 / RFC 9207. Mirrors the approach in go-sdk#859.

finishAuth(code, iss?) validates the received iss against the cached AS metadata before exchanging the code, using the RFC 9207 §2.4 decision table keyed on authorization_response_iss_parameter_supported.

Behavioral note

Signature is additive, but when an AS advertises authorization_response_iss_parameter_supported: true and the host app does not pass iss, validation rejects per §2.4. Options considered:

  • (a) ship as-is, changelog note — hosts pass through iss from the redirect URL (this PR)
  • (b) only enforce when iss was explicitly passed — vulnerable to a strip-the-param attack, defeats the point
  • (c) one-release enforceIssuerValidation opt-in flag — adds API surface for a temporary state

Going with (a). Open to (c) if reviewers prefer a softer rollout.

felixweinberger and others added 30 commits December 19, 2025 15:45
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
…n tools are present (#1407)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…1.x backport) (#1382)

Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
* fix: add transport isolation guards to prevent cross-client data leaks

When a single McpServer or stateless transport is reused across multiple
client connections, responses can be routed to the wrong client due to
message ID collisions. This is a data leak vulnerability (CWE-362).

Two guards added:
- Protocol.connect() throws if already connected to a transport
- Stateless transport.handleRequest() throws if called more than once

Also fixes three examples that shared a single McpServer across sessions:
- standaloneSseWithGetStreamableHttp.ts
- ssePollingExample.ts
- elicitationFormExample.ts

Related: #820, #204, #243

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: correct misleading test name and add per-request cleanup

- Rename 'should reject second SSE stream even in stateless mode' to
  'should allow multiple SSE streams in stateless mode with per-request
  transports' since the test now asserts both streams succeed (status 200)
- Add mcpServer.close() after per-request handling in
  stateManagementStreamableHttp.test.ts to prevent resource leaks,
  matching the pattern used in streamableHttp.test.ts
- Remove unused mcpServers array that collected but never cleaned up
  per-request server instances

* thread abort through sendRequest and notification to prevent crosstalk

* test: remove dummy objects from stateless setupServer return

In stateless mode, setupServer() was creating unused McpServer and
StreamableHTTPServerTransport instances solely to satisfy the return
type. Make mcpServer/serverTransport optional in the return type and
simplify the stateless beforeEach/afterEach to only track server and
baseUrl.

* fix: use McpError for sendRequest abort guard and fix Hono example reuse

- sendRequest abort guard now throws McpError(ErrorCode.ConnectionClosed)
  instead of plain Error for consistency with the rest of the codebase
- Hono example updated to create fresh transport and server per request,
  fixing breakage from the stateless transport reuse guard

* fix: use separate resolvers per protocol in transport isolation test

Address review feedback: each protocol handler now has its own resolver
returning distinct data (responseForA vs responseForB), so the test
properly demonstrates that responses route to the correct transport.
Uses explicit 'handler entered' promises for deterministic synchronization.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Paul Carleton <paulcarletonjr@gmail.com>
Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
#1528)

Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
) (#757)

Co-authored-by: Paul Carleton <paulc@anthropic.com>
…n_endpoint_auth_methods_supported (#1611)

Co-authored-by: Basil Hosmer <basil@anthropic.com>
Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
…roller cleanup (#1462)

Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
LucaButBoring and others added 12 commits March 25, 2026 17:57
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
…1640)

Co-authored-by: JiangNan <1394485448@qq.com>
Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: mozmo15 <mozmo@mail.com>
Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
Examples are meant to be read and run from the repo via tsx, not
imported from the package. Excluding them from the prod/cjs build
configs means dist/{esm,cjs}/examples/ is no longer produced and
no longer ships in the npm tarball.

Follow-up to #1579 / #1553.
… attacks

Adds an optional `iss` argument to `finishAuth()` and validates it against
the cached authorization server metadata before exchanging the code, per
the RFC 9207 §2.4 decision table keyed on
`authorization_response_iss_parameter_supported`. Reference implementation
for SEP-2468.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

🦋 Changeset detected

Latest commit: 6f0bf49

The changes in this PR will be included in the next version bump.

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

await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
Aligns with the SEP-2468 spec text: when the AS doesn't advertise
authorization_response_iss_parameter_supported but iss is present, compare
rather than reject. Accommodates servers that emit iss before advertising it.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 24, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@1957

commit: 6f0bf49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.