From 7117f720891b3d0d2f22c876573f01184421b719 Mon Sep 17 00:00:00 2001 From: Rhys Sullivan Date: Wed, 10 Jun 2026 09:30:31 -0700 Subject: [PATCH] Advertise MCP OAuth scopes so spec-faithful clients get refresh tokens --- apps/cloud/src/mcp/oauth-metadata.ts | 5 ++++- e2e/cloud/mcp-protocol.test.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/cloud/src/mcp/oauth-metadata.ts b/apps/cloud/src/mcp/oauth-metadata.ts index 307c4dea1d..5ebd988c61 100644 --- a/apps/cloud/src/mcp/oauth-metadata.ts +++ b/apps/cloud/src/mcp/oauth-metadata.ts @@ -22,7 +22,10 @@ export const protectedResourceMetadataResponse = (organizationId: string | null resource: resourceUrlFor(organizationId), authorization_servers: [AUTHKIT_DOMAIN], bearer_methods_supported: ["header"], - scopes_supported: [], + // Spec-faithful clients (OpenCode, mcporter) request exactly what is + // advertised here; without offline_access they get no refresh token and + // silently sign out at every access-token expiry. + scopes_supported: ["openid", "profile", "email", "offline_access"], }); export const authorizationServerMetadataResponse: Effect.Effect = Effect.tryPromise({ diff --git a/e2e/cloud/mcp-protocol.test.ts b/e2e/cloud/mcp-protocol.test.ts index 86f878bf6d..04643725c3 100644 --- a/e2e/cloud/mcp-protocol.test.ts +++ b/e2e/cloud/mcp-protocol.test.ts @@ -150,7 +150,10 @@ scenario( resource: new URL("/mcp", target.baseUrl).toString(), authorization_servers: [expect.any(String)], bearer_methods_supported: ["header"], - scopes_supported: [], + // offline_access MUST stay advertised: spec-faithful clients request + // exactly this list, and it is what earns them a refresh token (the + // OpenCode daily re-auth bug). + scopes_supported: ["openid", "profile", "email", "offline_access"], }); // The advertised server must itself be discoverable — that is what lets