Skip to content

docs(examples): add external auth resource server example (closes #658)#1967

Open
MukundaKatta wants to merge 1 commit intomodelcontextprotocol:mainfrom
MukundaKatta:feat/external-auth-resource-server-example
Open

docs(examples): add external auth resource server example (closes #658)#1967
MukundaKatta wants to merge 1 commit intomodelcontextprotocol:mainfrom
MukundaKatta:feat/external-auth-resource-server-example

Conversation

@MukundaKatta
Copy link
Copy Markdown

Why

Closes #658.

The current server examples either run without auth or co-locate an Authorization Server with the MCP server (simpleStreamableHttp.ts --oauth). In production, the AS is almost always a separate system (Auth0, Okta, Keycloak, Entra ID, AWS Cognito, an in-house IdP, ...) and the MCP server is a pure OAuth 2.0 resource server that validates incoming bearer tokens. Issue #658 asks for an example that demonstrates that pattern. None exists today.

A previous attempt (#1693) was closed because it shipped a 500+ line DIY OAuth server. This PR takes the opposite approach: no new auth server code, just one focused resource-server example that points at any external AS via env vars.

What

  • New file examples/server/src/externalAuthStreamableHttp.ts (~310 LOC) - a Streamable HTTP MCP server that:

    • Validates JWT bearer tokens against an external AS via JWKS (jose.createRemoteJWKSet + jwtVerify)
    • Enforces RFC 8707 audience binding (the AS-bound resource indicator must match MCP_AUDIENCE)
    • Serves RFC 9728 Protected Resource Metadata at /.well-known/oauth-protected-resource/<path> so clients can auto-discover the AS
    • Returns RFC 6750 401 / 403 plus a WWW-Authenticate header that points at the metadata document
    • Sets req.auth in the SDK's canonical AuthInfo shape so the SDK threads it into ctx.http?.authInfo for tool handlers
    • Demonstrates per-tool scope enforcement (whoami requires mcp:read, echo requires mcp:write)
    • Handles common scope claim variants (scope string, scp array)
  • examples/server/README.md - adds a row to the example index and a short "External Authorization Server (resource-server pattern)" section with a copy-pasteable Auth0 invocation.

  • examples/server/package.json - pulls jose from the existing runtimeClientOnly catalog (no new lockfile entry; jose@^6.1.3 is already present transitively).

No changes to SDK packages. No new shared utilities. Examples package is in .changeset/config.json's ignore list, so no changeset is needed.

Tested

  • Type signatures verified against packages/server and packages/middleware/node (AuthInfo, ServerContext.http?.authInfo, req.auth flow)
  • RFC 9728 metadata path derives from the configured audience so it works for both http://localhost:3000/mcp and https://api.example.com/mcp
  • Local run against an Auth0 tenant (sketch in the file header; reviewers with an AS handy can verify end-to-end)

@MukundaKatta MukundaKatta requested a review from a team as a code owner April 27, 2026 01:20
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 27, 2026

⚠️ No Changeset found

Latest commit: b1cdd1f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@MukundaKatta
Copy link
Copy Markdown
Author

Note on the changeset-bot warning: this PR only modifies the @modelcontextprotocol/examples-server package, which is in .changeset/config.json's ignore list. No changeset is needed; the warning is a false positive that maintainers will recognize.

@MukundaKatta MukundaKatta force-pushed the feat/external-auth-resource-server-example branch from 8f8f3ee to 0df3379 Compare April 28, 2026 05:37
…elcontextprotocol#658)

New `examples/server/src/externalAuthStreamableHttp.ts` shows the
production OAuth pattern where the MCP server is a pure resource
server that validates JWT bearer tokens minted by an external
Authorization Server (Auth0, Okta, Keycloak, Entra ID, Cognito,
in-house IdP, ...) via JWKS. RFC 8707 audience binding and RFC 9728
Protected Resource Metadata are demonstrated. No DIY OAuth server
code is added; trust anchors come from environment variables.

Also adds a row to `examples/server/README.md` and pulls `jose` from
the existing `runtimeClientOnly` catalog into the examples-server
package.
@MukundaKatta MukundaKatta force-pushed the feat/external-auth-resource-server-example branch from 0df3379 to b1cdd1f Compare April 28, 2026 05:44
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 28, 2026

Open in StackBlitz

@modelcontextprotocol/client

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

@modelcontextprotocol/server

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

@modelcontextprotocol/express

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

@modelcontextprotocol/fastify

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

@modelcontextprotocol/hono

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

@modelcontextprotocol/node

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

commit: b1cdd1f

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.

update server examples to cover external authentication servers

1 participant