You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(server): derive scope-challenge resource_metadata from AuthInfo
Rework the scope-challenge configuration surface so the RFC 9728 metadata
URL is configured exactly once and every WWW-Authenticate header a server
emits is built by one formatter:
- Scope-challenge 403s now build their WWW-Authenticate header via the
bearer-auth formatter (buildWwwAuthenticateHeader, now exported from
bearerAuth.ts), giving identical parameter order and quoting to the
bearer-auth 401/403 answers. The formatter now quotes the scope and
resource_metadata parameter values too. The JSON-RPC error body is
unchanged.
- AuthInfo gains an optional resourceMetadataUrl field; requireBearerAuth /
verifyBearerToken stamp their configured resourceMetadataUrl onto the
AuthInfo they return, so the URL flows inward with the verified token.
The scope preflight reads it from there, falls back to the well-known
location for the token's RFC 8707 resource identifier, and omits the
parameter otherwise (matching the bearer-auth optional precedent).
- Remove ScopeChallengeConfig and the scopeChallenge option from
createMcpHandler and the Streamable HTTP transports: the preflight is
active whenever a registered primitive carries a scopeChallenge callback,
fixing the silent no-op when the handler-level config was omitted.
- Update the authorization guide, examples, conformance server, tests, and
the changeset for the single-config shape; add coverage for the
stamped-URL flow, the RFC 8707 fallback, and parameter omission.
@@ -125,7 +119,9 @@ The per-request factory itself receives the same value as `ctx.authInfo`, so it
125
119
126
120
## Enforce per-operation scopes
127
121
128
-
`requiredScopes` gates the whole endpoint. For scope step-up on an individual tool call, resource read, or prompt retrieval, set `scopeChallenge` on its registration and configure `scopeChallenge.resourceMetadataUrl` on `createMcpHandler` (or a directly constructed Streamable HTTP transport). The callback receives the full parsed request and verified `authInfo`. Return `undefined` to continue, or return the exact, complete scope set to send `403 insufficient_scope` before invocation or SSE. Throwing or rejecting fails closed.
122
+
`requiredScopes` gates the whole endpoint. For scope step-up on an individual tool call, resource read, or prompt retrieval, set `scopeChallenge` on its registration — no handler or transport configuration is needed. The callback receives the full parsed request and verified `authInfo`. Return `undefined` to continue, or return the exact, complete scope set to send `403 insufficient_scope` before invocation or SSE. Throwing or rejecting fails closed.
123
+
124
+
The challenge's `WWW-Authenticate` header is built by the same formatter as `requireBearerAuth`'s own `401`/`403` answers, and its `resource_metadata` parameter comes from the verified `AuthInfo`: the gate stamps its configured `resourceMetadataUrl` onto the `AuthInfo` it returns, so the metadata URL is configured exactly once — on `requireBearerAuth`. Without a stamped value the parameter falls back to the well-known location for the token's RFC 8707 `resource` identifier, or is omitted.
129
125
130
126
Use `requireScopes` for a static exact all-of check. Use a callback when the required scope set depends on the request:
131
127
@@ -172,5 +168,5 @@ The callback runs before the primitive's input schema is validated or transforme
172
168
-`requireBearerAuth` plus a `verifyAccessToken` you write turn an Express-mounted MCP route into an OAuth resource server; the SDK never issues tokens.
173
169
- Missing, invalid, or expired tokens get `401 invalid_token`; a token missing a `requiredScopes` entry gets `403 insufficient_scope`; both carry a `WWW-Authenticate: Bearer` challenge.
174
170
-`mcpAuthMetadataRouter` publishes the RFC 9728 document that challenge points at, plus a mirror of the AS metadata.
175
-
- Verified auth flows `req.auth` → `ctx.http.authInfo`; per-operation callbacks can trigger HTTP `403` scope step-up before invocation.
171
+
- Verified auth flows `req.auth` → `ctx.http.authInfo`; per-operation callbacks can trigger HTTP `403` scope step-up before invocation, advertising the metadata URL the gate stamped onto `AuthInfo`.
176
172
- The v1 Authorization Server helpers are frozen in `@modelcontextprotocol/server-legacy/auth`.
0 commit comments