Skip to content

Feat/dpop server conformance fixture - #2631

Draft
gbshankar wants to merge 2 commits into
modelcontextprotocol:mainfrom
gbshankar:feat/dpop-server-conformance-fixture
Draft

Feat/dpop server conformance fixture#2631
gbshankar wants to merge 2 commits into
modelcontextprotocol:mainfrom
gbshankar:feat/dpop-server-conformance-fixture

Conversation

@gbshankar

Copy link
Copy Markdown

Motivation and Context

How Has This Been Tested?

Breaking Changes

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Implements the server half of SEP-1932: a hand-rolled WebCrypto DPoP
proof validator (packages/server/src/server/middleware/dpop.ts) covering
RFC 9449 Section 4.3's validation order and RFC 7638 JWK thumbprints
across all 10 asymmetric algs (ES256/384/512, RS256/384/512,
PS256/384/512, EdDSA) - no new dependency, keeps @modelcontextprotocol/
server runtime-neutral.

dpopAuth.ts adds verifyDpopToken/dpopAuthChallengeResponse/
requireDpopAuth mirroring the existing bearerAuth.ts trio, sharing the
WWW-Authenticate builder (extracted to authChallenge.ts) so Bearer and
DPoP challenges stay consistent. AuthInfo.cnf.jkt (core-internal) lets a
verifier surface RFC 9449 Section 6 token binding as a typed field.
verifyBearerToken now rejects a DPoP-bound token presented as Bearer
(RFC 9449 Section 7.1).

packages/middleware/express/src/auth/dpopAuth.ts adapts requireDpopAuth
for Express, reconstructing the request URI for htu from
req.protocol/host/originalUrl.

77 new unit + integration tests (real generated keys per algorithm, real
listening-server HTTP round trips for the Express adapter) - no unit
test synthesizes a fake CryptoKey.

Independent of the client-side DPoP PR (modelcontextprotocol#2629) - no shared files.
Adds the fixture and launcher for auth/dpop-server-validation
(conformance#395, open/unmerged - stacked on the now-merged modelcontextprotocol#394):

- src/dpopTestServer.ts: an MCP server gated by @modelcontextprotocol/
  express's requireDpopAuth (added in the parent PR), so the referee
  exercises the real SDK validator over the wire rather than a mock.
  Its own verifyAccessToken (independent WebCrypto JWT check against
  DPOP_ISSUER_JWK/DPOP_ISSUER/DPOP_AUDIENCE) is deliberately separate
  from @modelcontextprotocol/server's dpop.ts so a shared bug can't
  hide from the test.
- scripts/run-dpop-server-conformance.sh: generates a throwaway ES256
  issuer keypair, hands the public half to the fixture and the private
  half to the referee (which mints the tokens it probes with - see
  resolveIssuer() in conformance's src/scenarios/server/auth/dpop.ts),
  starts the fixture, runs the scenario, tears down.
- test:conformance:server:dpop script (both package.json files).

Status: NOT YET RUN end-to-end. auth/dpop-server-validation isn't in
the @modelcontextprotocol/conformance version this repo pins (needs
conformance#395 released, or a local link per test/conformance/
README.md's "Running Tests Against Local Conformance Repo"). No CI
leg is added here for the same reason - intentionally deferred, not
an oversight. dpopTestServer.ts typechecks/lints/formats clean; the
script itself has not been executed.

Stacked on the server DPoP validation PR (this branch is built on top
of it, so its commit is included here too).
@changeset-bot

changeset-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: aa5797a

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

This PR includes changesets to release 10 packages
Name Type
@modelcontextprotocol/server Minor
@modelcontextprotocol/express Major
@modelcontextprotocol/fastify Major
@modelcontextprotocol/hono Major
@modelcontextprotocol/node Major
@modelcontextprotocol/core Minor
@modelcontextprotocol/client Minor
@modelcontextprotocol/server-legacy Minor
@modelcontextprotocol/codemod Minor
@modelcontextprotocol/core-internal Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Aug 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2631

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2631

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2631

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2631

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2631

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2631

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2631

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2631

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2631

commit: aa5797a

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.

1 participant