{"record":{"id":"f5457625d8ada390","repo":"tinyhumansai/openhuman","slug":"mcp-connectauth-oauthtimeout","errorCode":null,"errorMessage":"mcp.connectAuth.oauthTimeout","messagePattern":"mcp\\.connectAuth\\.oauthTimeout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/src/components/channels/mcp/ConnectAuthModal.tsx","lineNumber":297,"sourceCode":"    setBusy(true);\n    setError(null);\n    setOauthWaiting(true);\n    void (async () => {\n      try {\n        const url = await mcpClientsApi.oauthBegin(server.server_id);\n        await openUrl(url);\n        const started = Date.now();\n        const poll = async (): Promise<void> => {\n          const statuses = await mcpClientsApi.status();\n          const mine = statuses.find(s => s.server_id === server.server_id);\n          if (mine?.status === 'connected') {\n            const result = await mcpClientsApi.connect(server.server_id);\n            onConnected(result.tools ?? []);\n            onClose();\n            return;\n          }\n          if (Date.now() - started > 180000) {\n            throw new Error(t('mcp.connectAuth.oauthTimeout'));\n          }\n          window.setTimeout(() => {\n            void poll().catch(handlePollError);\n          }, 2500);\n        };\n        const handlePollError = (err: unknown) => {\n          setError(err instanceof Error ? err.message : String(err));\n          setOauthWaiting(false);\n          setBusy(false);\n        };\n        await poll().catch(handlePollError);\n      } catch (err) {\n        const msg = err instanceof Error ? err.message : String(err);\n        log('oauth failed: %s', msg);\n        setError(msg);\n        setOauthWaiting(false);\n        setBusy(false);\n      }","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/components/channels/mcp/ConnectAuthModal.tsx#L279-L315","documentation":"MCP OAuth connect flow: after opening the provider's authorize URL in the system browser, the modal polls mcpClientsApi.status() every 2.5s for up to 180s waiting for that server to report 'connected' (the OAuth callback completing core-side). Past 3 minutes it gives up with this localized timeout message.","triggerScenarios":"User never completes consent in the browser; the OAuth callback never reaches the core (redirect URI misconfigured, wrong browser account); server needs longer than 180s to become connected; polling error path ends the wait early.","commonSituations":"Browser blocked or user abandoned the consent tab; MCP server's OAuth client not registered for the loopback redirect; slow provider authorization backends.","solutions":["Retry the connect flow and complete consent promptly in the opened browser tab","Confirm the authorize URL actually opened (openUrl) and that the MCP server's redirect URI is correctly registered","After a timeout, check the server's status in the MCP list — if it shows connected, call connect again instead of re-authenticating"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before declaring timeout, do one final authoritative status check:\nconst statuses = await mcpClientsApi.status();\nconst mine = statuses.find(s => s.server_id === id);\nconst connected = mine?.status === 'connected';\nif (!connected) { /* only now show the timeout error */ }","typeGuard":"const isConnected = (s: { status?: string } | undefined): boolean =>\n  s?.status === 'connected';","tryCatchPattern":"try {\n  await pollUntilConnected(serverId, 180_000);\n} catch (e) {\n  if (e instanceof Error && e.message === t('mcp.connectAuth.oauthTimeout')) {\n    // keep modal open, offer Retry — re-auth is often all that is needed\n    setOauthWaiting(false);\n    return;\n  }\n  throw e;\n}","preventionTips":["Complete the consent screen promptly after the browser tab opens","Register loopback redirect URIs correctly on the MCP provider's OAuth client","On timeout, check the server list first — a late callback may have connected it"],"tags":["mcp","oauth","timeout","polling"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}