Skip to content

[codex] fix MCP OAuth popup close handling#735

Merged
RhysSullivan merged 6 commits intomainfrom
codex/fix-mcp-sentry-oauth-popup
May 9, 2026
Merged

[codex] fix MCP OAuth popup close handling#735
RhysSullivan merged 6 commits intomainfrom
codex/fix-mcp-sentry-oauth-popup

Conversation

@RhysSullivan
Copy link
Copy Markdown
Owner

@RhysSullivan RhysSullivan commented May 9, 2026

Summary

Fixes MCP OAuth popup handling for providers such as Sentry that can make a live cross-origin popup appear closed to the opener.

  • Allows OAuth popup close polling to be disabled with closedPollMs: null.
  • Keeps close detection advisory: when popup.closed fires, result listeners stay active for a later callback.
  • Reports popup_closed_before_complete as a handled frontend warning so Sentry captures the signal with popup/session/provider metadata.
  • Keeps server-side OAuth sessions alive when popup.closed fires; only explicit cancel, callback completion/error, or TTL cleanup should end the session.
  • Adds regression coverage for disabled polling and for accepting a later result after a close signal.

Root Cause

The MCP OAuth UI cancelled the pending OAuth session as soon as popup.closed read true. COOP redirects can make a live popup look closed to the opener, so the server deleted the OAuth session and the later callback failed with OAuthSessionNotFoundError. The previous hardening kept the server session alive but still removed frontend result listeners on close; this now keeps those listeners active and reports the advisory close to Sentry.

Reference Notes

  • oidc-client-ts treats popup close as possibly “closed by user or isolated by redirect” and makes abort-on-close configurable.
  • Auth0 SPA JS exposes popup lifecycle escape hatches such as caller-provided popups and closePopup: false.
  • Firebase Auth adds grace around popup close because close can race with in-flight auth completion.

Validation

  • bun run --cwd packages/react test src/api/oauth-popup.test.ts
  • bun run --cwd packages/react typecheck
  • bunx oxlint -c .oxlintrc.jsonc packages/react/src/api/oauth-popup.ts packages/react/src/api/oauth-popup.test.ts packages/react/src/plugins/oauth-sign-in.tsx packages/plugins/mcp/src/react/AddMcpSource.tsx packages/plugins/mcp/src/react/McpSignInButton.tsx
  • bunx oxfmt --check packages/react/src/api/oauth-popup.ts packages/react/src/api/oauth-popup.test.ts packages/react/src/plugins/oauth-sign-in.tsx packages/plugins/mcp/src/react/AddMcpSource.tsx packages/plugins/mcp/src/react/McpSignInButton.tsx

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 9, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud 2e02d19 May 09 2026, 07:51 AM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 9, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 2e02d19 Commit Preview URL

Branch Preview URL
May 09 2026, 07:51 AM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 9, 2026

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@735

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@735

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@735

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@735

@executor-js/storage-core

npm i https://pkg.pr.new/@executor-js/storage-core@735

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@735

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@735

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@735

@executor-js/plugin-google-discovery

npm i https://pkg.pr.new/@executor-js/plugin-google-discovery@735

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@735

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@735

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@735

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@735

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@735

executor

npm i https://pkg.pr.new/executor@735

commit: 5e9024f

…rors

The MCP detect path required RFC 9728/8414 OAuth metadata to confirm a
401 Bearer challenge was MCP, which rejected real servers that
authenticate with static API keys (e.g. cubic.dev/api/mcp). Replace the
OAuth gate with a JSON-RPC envelope check on the probe response: the
body shape is what separates real MCP from unrelated OAuth-protected
APIs (Railway-style GraphQL, etc.).

Add a low-confidence URL-token fallback so non-canonical endpoints
(e.g. servers that omit WWW-Authenticate entirely, like ref.tools) and
unreachable hosts still surface as candidates when the path/host
includes the protocol token.

Replace the technical "Endpoint does not look like an MCP server: 401
without Bearer WWW-Authenticate" copy with actionable user-facing
messages keyed on a new `category` discriminant (auth-required vs
wrong-shape vs unreachable).
@RhysSullivan RhysSullivan marked this pull request as ready for review May 9, 2026 07:48
@RhysSullivan RhysSullivan merged commit 8b4e793 into main May 9, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant