diff --git a/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page.svelte b/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page@(root).svelte
similarity index 90%
rename from frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page.svelte
rename to frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page@(root).svelte
index 3750c56d97..830e545719 100644
--- a/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/+page@(root).svelte
@@ -1,3 +1,7 @@
+
{#if !redirectUriValid}
-
Error: invalid or unsafe redirect_uri
+
+ Error: invalid or unsafe redirect_uri
+
{:else if !isGateway && !workspaceId}
- Error: missing workspace_id
+
+ Error: missing workspace_id
+
{:else}
{#if success}
diff --git a/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/layoutReset.test.ts b/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/layoutReset.test.ts
new file mode 100644
index 0000000000..6ba4469e27
--- /dev/null
+++ b/frontend/src/routes/(root)/(logged)/oauth/mcp_authorize/layoutReset.test.ts
@@ -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')
+ })
+})
diff --git a/frontend/src/routes/(root)/+layout.svelte b/frontend/src/routes/(root)/+layout.svelte
index 0e404afbcc..4de44442a2 100644
--- a/frontend/src/routes/(root)/+layout.svelte
+++ b/frontend/src/routes/(root)/+layout.svelte
@@ -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.