From 35697507d54805a3b2c611c52e18374b53fd0c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B2=94=ED=99=98?= <95680257+bumhwan@users.noreply.github.com> Date: Thu, 3 Sep 2026 12:40:49 +0900 Subject: [PATCH] docs(server/auth): document that resourceServerUrl and resourceMetadataUrl are needed for MCP-compliant discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both options are optional in the types, but for an MCP server both are effectively required: without resourceServerUrl the Protected Resource Metadata is served at the root well-known with resource set to the origin (not the MCP endpoint), and without resourceMetadataUrl the 401 challenge has no resource_metadata parameter, which the MCP authorization spec requires. Clients that enforce RFC 9728 §3.3 literally (Gemini CLI, Antigravity CLI) abort discovery on the resulting documents while the reference client accepts them, so server authors get no signal. Spell this out in the JSDoc. No behaviour change. Refs #2751 Co-Authored-By: Claude Fable 5.1 --- packages/server-legacy/src/auth/router.ts | 8 ++++++++ packages/server/src/server/middleware/bearerAuth.ts | 11 ++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/server-legacy/src/auth/router.ts b/packages/server-legacy/src/auth/router.ts index 866615540b..e2b85e4fe0 100644 --- a/packages/server-legacy/src/auth/router.ts +++ b/packages/server-legacy/src/auth/router.ts @@ -57,6 +57,14 @@ export type AuthRouterOptions = { /** * The URL of the protected resource (RS) whose metadata we advertise. * If not provided, falls back to `baseUrl` and then to `issuerUrl` (AS=RS). + * + * Pass the MCP endpoint URL itself (e.g. `https://api.example.com/mcp`), not just the + * origin. RFC 9728 §3 places the metadata at + * `/.well-known/oauth-protected-resource/` and §3.3 requires its `resource` to be + * identical to the resource the client connected to. The `baseUrl` fallback therefore only + * yields a compliant document when the MCP endpoint is served at the origin root; clients + * that enforce §3.3 (Gemini CLI, Antigravity CLI) reject `resource: https://host/` when they + * connected to `https://host/mcp`, while the reference SDK client happens to accept it. */ resourceServerUrl?: URL; diff --git a/packages/server/src/server/middleware/bearerAuth.ts b/packages/server/src/server/middleware/bearerAuth.ts index 1169e21336..0c687fb0ff 100644 --- a/packages/server/src/server/middleware/bearerAuth.ts +++ b/packages/server/src/server/middleware/bearerAuth.ts @@ -44,9 +44,14 @@ export interface BearerAuthOptions { requiredScopes?: string[]; /** - * Optional Protected Resource Metadata URL to advertise in the - * `WWW-Authenticate` header on 401/403 responses, per - * {@link https://datatracker.ietf.org/doc/html/rfc9728 | RFC 9728}. + * Protected Resource Metadata URL to advertise in the `WWW-Authenticate` + * header on 401/403 responses, per + * {@link https://datatracker.ietf.org/doc/html/rfc9728 | RFC 9728} §5.1. + * + * The MCP authorization spec requires MCP servers to send it, so pass it for + * any protected MCP endpoint. When omitted, clients must guess the well-known + * location and strict clients can fail discovery; leave it out only for + * non-MCP or legacy deployments. * * Typically built with `getOAuthProtectedResourceMetadataUrl`, exported * from this package.