From a80ce54b7893f50cf0166566181e1cd0ed24ae5d Mon Sep 17 00:00:00 2001 From: Mattsson <111893710+mattssonn@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:55:23 +0200 Subject: [PATCH] fix(mcp): eager-auth flag on the Grok connector links so Grok starts OAuth (#2167) * fix(mcp): eager-auth flag on the Grok connector links so Grok starts OAuth Live test after #2158: pasting the Grok URL into grok.com's custom connector dialog listed all 150+ tools and never opened the sign-in. Grok probes the URL without credentials, like claude.ai, and reads the lazy 200 on initialize as an authless server; only the 401 challenge starts OAuth (#2159 fixed the same thing for the claude.ai link). - lib/onboarding/checklist.ts: mcpServerUrl() builds the server URL with an optional eagerAuth flag; sideDoorServerUrl() gives the Grok side door auth=required and keeps ChatGPT lazy; claudeConnectorLink() reuses it. SIDE_DOORS / SideDoor move here from the component. Tests for all three. - NewUserChecklist copies the door-specific URL (now with a client marker). - ApiKeysPanel's Grok row copies the flagged URL, mirroring the Claude one. - auth-mode.ts comment records the second consumer; registry entry's Grok step carries the flag; DECISIONS. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LhTJcwgzmN3TsLR8tVHwdi Signed-off-by: Emil * docs(mcp): registry Claude.ai step carries auth=required too Review pass on #2167: the registry entry flagged the Grok install URL but left the Claude.ai step on the bare URL, which pre-fills "None" in claude.ai's dialog (#2159). Same file, same flag, now consistent. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LhTJcwgzmN3TsLR8tVHwdi Signed-off-by: Emil --------- Signed-off-by: Emil Co-authored-by: Claude Fable 5.1 --- DECISIONS.md | 1 + components/onboarding/NewUserChecklist.tsx | 15 +++---- components/settings/ApiKeysPanel.tsx | 5 ++- extensions/general/mcp-server/auth-mode.ts | 9 ++-- lib/onboarding/__tests__/checklist.test.ts | 36 ++++++++++++++++ lib/onboarding/checklist.ts | 49 ++++++++++++++++++---- registry/entries/gnubok-mcp.mdx | 4 +- 7 files changed, 96 insertions(+), 23 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index becafc8f..b310abdc 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1495,3 +1495,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-09-02] Removed the skattekonto drift email (skattekonto.drift_detected event, handler, /api/extensions/skatteverket/skattekonto/drift route, cron hook) instead of fixing it: it alerted on raw saldo-vs-1630 gaps that unbooked rows explain by construction (2026-09-02: Arcim 35 842 kr, 100% explained, while the Hem notice and reconciliation page said nothing was wrong), repeated every 24 h, and was the only surface of a May-2026 feature whose promised dashboard tile was never built. Since 2026-08-25 the reconciliation page and the Hem notice (detectSkvUnexplained, gated on unexplained_difference) are the surface. Considered gating the mail on unexplained_difference + once per episode (built, then dropped): after that gate it only fires on integrity findings the engine itself calls 'never a user task'. skattekonto_drift_tolerance stays (Hem notice reads it); stale skattekonto_drift_last_alert_at rows in extension_data are inert. [2026-09-02] parties phase 0, golden set stays out of git: the labelling sample is prod voucher text with person names (salary, expense claims) and the repo is public, so the draw SQL is versioned but the rows and labels live in gitignored dev_docs/parties/golden/. [2026-09-02] MCP eager-auth flag (`auth=required`) on the claude.ai connector links instead of reverting lazy auth: claude.ai's two-step Add-custom-connector dialog probes the URL without credentials and pre-fills Authentication "None" when the lazy handshake answers 200, which blocks the sign-in later; per Anthropic's docs a 401 is the only answer it reads as OAuth. The flag lives in the URL, so the links we control (Settings, onboarding checklist, both docs pages, website) get OAuth detected while the bare URL keeps lazy auth for Claude Code, the plugin, Cursor and ChatGPT, and existing connector records stay untouched. Rejected: keying eager auth off `client=claude-connector` (documented as telemetry-only) and sniffing the probe's user agent (fragile, undocumented). +[2026-09-02] Grok links carry auth=required like the claude.ai link (#2159), decided from a live test: on the lazy URL Grok's connector dialog listed all 150+ tools and never opened the sign-in, so it reads the 200 probe as an authless server exactly as claude.ai does. The flag lives in one helper (mcpServerUrl / sideDoorServerUrl in lib/onboarding/checklist.ts) so the settings row, the onboarding side door and the deep link cannot drift; ChatGPT stays lazy because its developer mode honours the 401 on the first protected call. diff --git a/components/onboarding/NewUserChecklist.tsx b/components/onboarding/NewUserChecklist.tsx index 680972a9..492fa818 100644 --- a/components/onboarding/NewUserChecklist.tsx +++ b/components/onboarding/NewUserChecklist.tsx @@ -17,6 +17,9 @@ import { checklistNumbers, claudeConnectorLink, completionPatchBody, + SIDE_DOORS, + sideDoorServerUrl, + type SideDoor, type VatDeadlineLine, } from '@/lib/onboarding/checklist' import { ENABLED_EXTENSION_IDS } from '@/lib/extensions/_generated/enabled-extensions' @@ -47,12 +50,6 @@ interface NewUserChecklistProps { sieSweep?: { auto_linked: number; suggested: number; unmatched: number; errors: number } | null } -/** Clients that get a collapsed "Using X?" side door under the Claude step. - * Each value keys the i18n strings step_claude__link / _steps and the - * telemetry step name. Order is display order. */ -const SIDE_DOORS = ['chatgpt', 'grok'] as const -type SideDoor = (typeof SIDE_DOORS)[number] - /** * Activation funnel events, mirroring the one existing product-event site * (lib/support/submit-feedback.ts): guarded, try/caught, no PII in @@ -276,8 +273,8 @@ export default function NewUserChecklist({ return open === door ? null : door }) } - const copyServerUrl = async () => { - const serverUrl = `${window.location.origin}/api/extensions/ext/mcp-server/mcp?tool_namespace=accounted` + const copyServerUrl = async (door: SideDoor) => { + const serverUrl = sideDoorServerUrl({ origin: window.location.origin, door }) try { await navigator.clipboard.writeText(serverUrl) setServerUrlCopied(true) @@ -495,7 +492,7 @@ export default function NewUserChecklist({

{t(`step_claude_${sideDoor}_steps`, { appName })}

-