fix: extend pending_verification bootstrap path to cover per_user_oauth clients - #3873
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR extends OAuth pending-verification handling to shared and ChangesPer-user OAuth pending verification
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant ConfigBootstrap
participant ClientManager
participant MCPRegistry
participant HTTPHandlers
ConfigBootstrap->>ClientManager: load OAuth client with pending configuration
ClientManager->>ClientManager: set PendingVerification state
MCPRegistry->>HTTPHandlers: initiate verification
HTTPHandlers-->>MCPRegistry: return authorization and completion URLs
MCPRegistry->>HTTPHandlers: complete OAuth verification
HTTPHandlers->>ClientManager: update verified connection
HTTPHandlers->>ConfigBootstrap: clear pending OAuth configuration
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
|
|
Confidence Score: 4/5The cleanup error path should be fixed before merging.
transports/bifrost-http/handlers/mcp.go Important Files Changed
Reviews (6): Last reviewed commit: "feat: add per user oauth mcp support for..." | Re-trigger Greptile |
ff11dc3 to
4d85b9c
Compare
2e6de8c to
41d8011
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
core/mcp/clientmanager.go (1)
358-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd table-driven coverage for the new
per_user_oauthbranch.The pending-verification gate now branches on two auth types, but no test changes are visible for this behavior change. Since
core/mcp/clientmanager_test.goexists in this package, consider adding a case assertingper_user_oauthclients withPendingOAuthConfigset land inMCPConnectionStatePendingVerification, alongside the existingoauthcase.As per path instructions, "review agent loops for bounded depth, deterministic tool execution behavior" and general Go guideline to apply "table-driven coverage for behavior changes."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/mcp/clientmanager.go` around lines 358 - 359, Add table-driven test coverage in clientmanager_test for the pending-verification branch in ClientManager behavior. Extend the existing auth-state tests to include a per_user_oauth case with PendingOAuthConfig set and assert it resolves to MCPConnectionStatePendingVerification, alongside the existing oauth coverage. Use the same test setup/helpers already used for the oauth branch so the new case exercises the config.PendingOAuthConfig gate and the AuthType check in the client manager logic.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 1620-1631: The OAuth bootstrap fallback in the config loader is
unreachable from the config-file path because the schema currently requires
oauth_config_id for oauth and per_user_oauth. Update the MCP schema validation
to allow the bootstrap-pending shape, or move the PendingOAuthConfig synthesis
in config.go behind a non-config.json source path so the runtime gate and
initiate-verification flow can actually reach it.
---
Nitpick comments:
In `@core/mcp/clientmanager.go`:
- Around line 358-359: Add table-driven test coverage in clientmanager_test for
the pending-verification branch in ClientManager behavior. Extend the existing
auth-state tests to include a per_user_oauth case with PendingOAuthConfig set
and assert it resolves to MCPConnectionStatePendingVerification, alongside the
existing oauth coverage. Use the same test setup/helpers already used for the
oauth branch so the new case exercises the config.PendingOAuthConfig gate and
the AuthType check in the client manager logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b70191eb-7cca-4fd2-8560-0df58a74ac26
📒 Files selected for processing (4)
core/mcp/clientmanager.gotransports/bifrost-http/handlers/mcp.gotransports/bifrost-http/lib/config.goui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
4d85b9c to
fd86d73
Compare
41d8011 to
dc2f30a
Compare
fd86d73 to
c26897d
Compare
dc2f30a to
ae90a7d
Compare
c26897d to
77e5f5f
Compare
ae90a7d to
32cf960
Compare
77e5f5f to
a5d0538
Compare
32cf960 to
8e33d96
Compare
5aa467f to
fd4d929
Compare
84d0fa9 to
b9a6764
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx`:
- Around line 226-242: Serialize concurrent bootstrap flows in the client
verification action so only one bootstrap can run at a time, preventing shared
oauthConfigId, mcpClientId, and "oauth_popup" state from being overwritten.
Update the relevant bootstrap/verification handler around the popup
initialization to disable or reject other bootstrap actions until the active
flow completes, then restore availability on success or failure. Add an E2E test
covering two initiation requests resolving out of order.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b194710c-5aa4-49f9-b82a-74c0ae7cb9f3
📒 Files selected for processing (6)
core/mcp/clientmanager.gotransports/bifrost-http/handlers/mcp.gotransports/bifrost-http/lib/config.gotransports/bifrost-http/lib/config_test.goui/app/workspace/mcp-registry/views/mcpClientSheet.tsxui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
- transports/bifrost-http/lib/config.go
- core/mcp/clientmanager.go
- transports/bifrost-http/handlers/mcp.go
- transports/bifrost-http/lib/config_test.go
| const isPerUserOauth = client.config.auth_type === "per_user_oauth"; | ||
| // Open a blank popup synchronously, before the initiateVerification | ||
| // await, so the click's transient user-activation is captured here | ||
| // rather than consumed by the network round-trip — otherwise the | ||
| // browser can block OAuth2Authorizer's later window.open entirely. | ||
| // OAuth2Authorizer navigates this handle once authorize_url is known. | ||
| const width = 600; | ||
| const height = 700; | ||
| const left = window.screen.width / 2 - width / 2; | ||
| const top = window.screen.height / 2 - height / 2; | ||
| const popup = window.open("", "oauth_popup", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`); | ||
| // Not needed for per_user_oauth: that flow shows a confirm step first | ||
| // and opens its own popup synchronously from that step's own button | ||
| // click, so pre-opening one here would just leak an unused window. | ||
| let popup: Window | null = null; | ||
| if (!isPerUserOauth) { | ||
| const width = 600; | ||
| const height = 700; | ||
| const left = window.screen.width / 2 - width / 2; | ||
| const top = window.screen.height / 2 - height / 2; | ||
| popup = window.open("", "oauth_popup", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- target file outline ---'
ast-grep outline ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
printf '%s\n' '--- relevant target sections ---'
sed -n '160,275p' ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
printf '%s\n' '--- all relevant symbols and popup usage ---'
rg -n -C 4 'bootstrapAuthorize|authorizingClients|oauth_popup|initialPopup|OAuth2Authorizer|initiateVerification' ui
printf '%s\n' '--- candidate OAuth2Authorizer files ---'
fd -i 'OAuth2Authorizer|oauth.*author' uiRepository: maximhq/bifrost
Length of output: 31198
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- row action guards and handler wiring ---'
sed -n '1,145p' ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
sed -n '620,665p' ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
printf '%s\n' '--- OAuth2Authorizer implementation ---'
sed -n '1,330p' ui/app/workspace/mcp-registry/views/oauth2Authorizer.tsx
printf '%s\n' '--- API mutation definition ---'
sed -n '245,275p' ui/lib/store/apis/mcpApi.tsRepository: maximhq/bifrost
Length of output: 18207
Serialize concurrent bootstrap flows or key state and popups per client.
Different rows can start verification at the same time. Both shared OAuth flows use the "oauth_popup" target, and bootstrapAuthorize stores only one flow. An out-of-order response can replace the active oauthConfigId and mcpClientId, leaving the other flow stranded.
Disable all bootstrap actions while one flow is active, or store flow state per client_id and use a unique popup name for each flow. Add an E2E test for two initiation requests that resolve out of order.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx` around lines 226 -
242, Serialize concurrent bootstrap flows in the client verification action so
only one bootstrap can run at a time, preventing shared oauthConfigId,
mcpClientId, and "oauth_popup" state from being overwritten. Update the relevant
bootstrap/verification handler around the popup initialization to disable or
reject other bootstrap actions until the active flow completes, then restore
availability on success or failure. Add an E2E test covering two initiation
requests resolving out of order.
b9a6764 to
9129d60
Compare
fd4d929 to
561a8a5
Compare
Merge activity
|
9129d60 to
a866cd8
Compare

Summary
Extends the
pending_verificationbootstrap flow to coverper_user_oauthclients in addition to sharedoauthclients. Previously, only shared OAuth clients declared inconfig.jsonwere parked inpending_verificationawaiting admin authorization. Per-user OAuth clients loaded from config were not handled the same way, meaning they could end up in an inconsistent state before an admin completed the verification step.Changes
pending_verificationgate inAddClientto apply to bothoauthandper_user_oauthauth types whenPendingOAuthConfigis set, replacing the previous shared-OAuth-only check.initiate-verificationendpoint now accepts bothoauthandper_user_oauthauth types instead of rejecting the latter.complete-oauthcallback handler now permits both OAuth-based auth types to complete through the endpoint, with downstream branching handling the per-user vs. shared distinction.config.json, OAuth-based clients (oauthorper_user_oauth) that have no inlineoauth_configblock and no existingoauth_config_idnow have an emptyOAuth2Configsynthesized so they consistently land inpending_verificationand theinitiate-verificationendpoint can run discovery and dynamic client registration at admin-click time.per_user_oauthclients inpending_verificationshow a "Verify" button and a description clarifying that the admin test login is a one-time setup step and each user will authenticate individually afterward. The success toast message is similarly differentiated.Type of change
Affected areas
How to test
per_user_oauthMCP client inconfig.jsonwith aconnection_stringbut nooauth_configblock.pending_verificationstate.pending_verificationand tools are discovered.oauthclient to confirm existing behavior is unchanged.Breaking changes
Security considerations
The admin verification flow for
per_user_oauthuses the upstream token only as a temporary credential to validate the OAuth configuration and discover tools, then revokes it. The token is not persisted or reused for end-user requests. No end-user credentials are stored as a result of the admin verification step.Checklist
docs/contributing/README.mdand followed the guidelines