History

Advertise MCP OAuth scopes so spec-faithful clients get refresh tokens (#951)

Rhys Sullivan committed 5 months ago

Commit 23b97ef1 parent 78902a92 files · +8 −2Browse files

Unified · Split

2 files
  1. apps/cloud/src/mcp/oauth-metadata.ts +4 −1
  2. e2e/cloud/mcp-protocol.test.ts +4 −1
apps/cloud/src/mcp/oauth-metadata.ts+4−1
@@ -22,7 +22,10 @@ export const protectedResourceMetadataResponse = (organizationId: string | null · 21 unmodified lines
22 resource: resourceUrlFor(organizationId),22 resource: resourceUrlFor(organizationId),
23 authorization_servers: [AUTHKIT_DOMAIN],23 authorization_servers: [AUTHKIT_DOMAIN],
24 bearer_methods_supported: ["header"],24 bearer_methods_supported: ["header"],
25 scopes_supported: [],25 // Spec-faithful clients (OpenCode, mcporter) request exactly what is
26 // advertised here; without offline_access they get no refresh token and
27 // silently sign out at every access-token expiry.
28 scopes_supported: ["openid", "profile", "email", "offline_access"],
26 });29 });
27 30
28export const authorizationServerMetadataResponse: Effect.Effect<Response> = Effect.tryPromise({31export const authorizationServerMetadataResponse: Effect.Effect<Response> = Effect.tryPromise({
e2e/cloud/mcp-protocol.test.ts+4−1
@@ -150,7 +150,10 @@ scenario( · 149 unmodified lines
150 resource: new URL("/mcp", target.baseUrl).toString(),150 resource: new URL("/mcp", target.baseUrl).toString(),
151 authorization_servers: [expect.any(String)],151 authorization_servers: [expect.any(String)],
152 bearer_methods_supported: ["header"],152 bearer_methods_supported: ["header"],
153 scopes_supported: [],153 // offline_access MUST stay advertised: spec-faithful clients request
154 // exactly this list, and it is what earns them a refresh token (the
155 // OpenCode daily re-auth bug).
156 scopes_supported: ["openid", "profile", "email", "offline_access"],
154 });157 });
155 158
156 // The advertised server must itself be discoverable — that is what lets159 // The advertised server must itself be discoverable — that is what lets