fix: render the MCP OAuth consent page without a workspace (#10988)

Claude-Session: https://claude.ai/code/session_014EeEWKSqcnCEcPKe9uUuHC

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-05 10:05:15 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent b5ae12bdf2
commit ebfac29096
3 changed files with 28 additions and 3 deletions
@@ -1,3 +1,7 @@
<!-- `@(root)` skips the (logged) layout on purpose: that layout renders nothing but
"Loading user..." until `$userStore` is set, and `$userStore` is only ever filled in
for a chosen workspace. An MCP client sends the browser straight here after login, so
in gateway mode there is no workspace yet — picking one is what this page is for. -->
<script lang="ts">
import { page } from '$app/state'
import CenteredModal from '$lib/components/CenteredModal.svelte'
@@ -138,9 +142,13 @@
</script>
{#if !redirectUriValid}
<p class="text-center text-sm text-primary mb-6"> Error: invalid or unsafe redirect_uri </p>
<CenteredModal title="Authorization Request">
<p class="text-center text-sm text-primary"> Error: invalid or unsafe redirect_uri </p>
</CenteredModal>
{:else if !isGateway && !workspaceId}
<p class="text-center text-sm text-primary mb-6">Error: missing workspace_id</p>
<CenteredModal title="Authorization Request">
<p class="text-center text-sm text-primary">Error: missing workspace_id</p>
</CenteredModal>
{:else}
<CenteredModal title={success ? 'Authorization Approved' : 'Authorization Request'}>
{#if success}
@@ -0,0 +1,14 @@
import { readdirSync } from 'node:fs'
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
// Renaming the page back drops it into the (logged) layout, where it hangs on
// "Loading user..." with no type error and no other failing test — see the page header.
const routeDir = dirname(fileURLToPath(import.meta.url))
describe('mcp oauth consent route', () => {
it('escapes the (logged) layout', () => {
expect(readdirSync(routeDir)).toContain('+page@(root).svelte')
})
})
+4 -1
View File
@@ -147,7 +147,10 @@
} else {
if (
(!page.url.pathname.startsWith('/user/') || page.url.pathname.startsWith('/user/cli')) &&
!page.url.pathname.startsWith('/oauth/mcp_authorize') &&
// The MCP consent page carries its own workspace picker, so it is left to
// run without one. Nothing sets `$userStore` on this branch, which is why
// that page must stay outside the (logged) layout — see its `@(root)` name.
!page.url.pathname.startsWith(`${base}/oauth/mcp_authorize`) &&
// The hub import wizard asks for the destination itself, and may end in a
// workspace that does not exist yet — bouncing it to the picker would
// force the very choice it exists to make.