Skip to content

feat: mcp per user oauth flow refactor - #3565

Merged
akshaydeo merged 1 commit into
devfrom
05-18-refactor_mcp_per_user_oauth_flow_refactor
May 20, 2026
Merged

feat: mcp per user oauth flow refactor#3565
akshaydeo merged 1 commit into
devfrom
05-18-refactor_mcp_per_user_oauth_flow_refactor

Conversation

@Pratham-Mishra04

@Pratham-Mishra04 Pratham-Mishra04 commented May 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Briefly explain the purpose of this PR and the problem it solves.

Changes

  • What was changed and why
  • Any notable design decisions or trade-offs

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

Describe the steps to validate this change. Include commands and expected outcomes.

# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

If adding new configs or environment variables, document them here.

Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

Breaking changes

  • Yes
  • No

If yes, describe impact and migration instructions.

Related issues

Link related issues and discussions. Example: Closes #123

Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added "Auth Sessions" tab to view, re-authenticate, and revoke OAuth sessions
    • New authentication landing page for completing OAuth flows
  • Improvements

    • Simplified OAuth callback handling with direct redirects
    • Removed OAuth consent UI in favor of streamlined identity management
    • Enhanced OAuth session tracking with mode-based identity support
    • Simplified MCP configuration by removing redundant URL override

Walkthrough

Refactors per-user OAuth to a mode-driven model (user/vk/session), migrates DB schema and store APIs, updates provider initiation/completion/refresh to bind identity by mode, adds a sweep worker, removes legacy per-user OAuth handlers, and adds MCP sessions HTTP API and UI.

Changes

Mode-driven Per-User OAuth and Sessions Management

Layer / File(s) Summary
Auth-mode contracts and context
core/schemas/bifrost.go, core/schemas/context.go, core/schemas/mcp.go
Adds MCPAuthMode, BifrostContextKeyMCPSessionID, BifrostContext.MCPAuthMode(), and new flow-state errors.
OAuth2Provider interface updates
core/schemas/oauth.go
Provider API refactored to mode-based lookups: GetUserAccessTokenByMode, InitiateUserOAuthFlow(..., flowMode), RefreshUserAccessToken(tokenID), removed legacy getters.
Core token resolution & utils
core/mcp/utils/utils.go
ResolvePerUserOAuthToken derives MCPAuthMode, resolves a single identity with identityForMCPAuthMode, calls GetUserAccessTokenByMode, validates oauthConfigID/redirectURI on reauth, and includes authorize URL in errors.
DB migrations & table models
framework/configstore/migrations.go, framework/configstore/tables/oauth.go, framework/configstore/tables/clientconfig.go
Migrations add auth discriminators/flow_mode/status, switch to session_id, drop legacy gateway/per-user server tables, hard-delete non-vk rows, and conditionally drop mcp_external_server_url. Table models updated to SessionID+discriminators and OauthUserSummary.
ConfigStore & RDB changes
framework/configstore/store.go, framework/configstore/rdb.go, framework/configstore/rdb_test.go
Store API refactored to canonical (mode, identity, mcpClientID) lookups, transactional token upsert, claim-by-state, admin lifecycle helpers (delete/list/mark needs_reauth), and updated mocks/tests.
OAuth provider logic
framework/oauth2/main.go
InitiateUserOAuthFlow upserts canonical per-user session keyed by (flowMode, identity, mcp_client), CompleteUserOAuthFlow binds identities per flow mode and creates token rows using SessionID, RefreshUserAccessToken uses tokenID and marks tokens needing reauth on permanent errors, BuildUpstreamAuthorizeURL reconstructs upstream authorize URLs with PKCE.
Sweep worker & idempotency
framework/oauth2/sync.go
New PerUserOAuthSweepWorker sweeps expired flows and orphan tokens on start and periodically; TokenRefreshWorker.Stop() made idempotent with sync.Once.
Remove legacy per-user OAuth handlers
transports/bifrost-http/handlers/oauth2_consent.go (deleted), transports/bifrost-http/handlers/oauth2_per_user.go (deleted), transports/bifrost-http/handlers/oauth2_metadata.go (deleted), transports/bifrost-http/handlers/oauth2.go
Deleted per-user authorization-server, consent, and metadata handlers; simplified OAuth callback handling to redirect-only per-user vs admin-test branching.
MCPSessions HTTP handler
transports/bifrost-http/handlers/mcp_sessions.go
New MCPSessionsHandler with listing, reauth start, revoke, flow detail, and flow start endpoints; unified wire model for token/flow rows and binding-key helpers.
Transport wiring & config lifecycle
transports/bifrost-http/lib/config.go, transports/bifrost-http/lib/ctx.go, transports/bifrost-http/server/server.go, transports/bifrost-http/handlers/config.go, transports/bifrost-http/handlers/governance.go
Register MCPSessionsHandler routes, add OAuthSweepWorker to Config init/close, stop validating/clearing MCPExternalServerURL overrides, ingest x-bf-mcp-session-id header into context, and reorder virtual-key deletion to DB-first.
Frontend pages, components & routing
ui/app/workspace/mcp-sessions/*, ui/app/workspace/mcp-registry/oauth-callback/*, ui/app/workspace/config/views/mcpView.tsx, ui/components/sidebar.tsx, ui/components/ui/alert.tsx
Add sessions list page, auth landing page, sessions table with actions and expiry handling, registry OAuth callback page, Advanced Settings UI (client URL only), sidebar entry, and an amber warning alert variant.
Frontend RTK Query API & types
ui/lib/store/apis/mcpSessionsApi.ts, ui/lib/types/mcpSessions.ts, ui/lib/store/apis/index.ts, ui/lib/store/apis/baseApi.ts, ui/lib/types/config.ts
Add mcpSessionsApi endpoints/hooks, add MCPSessions cache tag, define TS types for sessions and flows, and remove mcp_external_server_url from CoreConfig.
Client tool rebind logic
core/mcp/clientmanager.go, transports/bifrost-http/handlers/mcp.go
Rebuild ToolMap keys and Function.Name to use updated client-name prefix on client update and migrate persisted DiscoveredTools keys when present.
Minor/text updates
core/mcp/codemode/starlark/listfiles.go, ui/lib/store/apis/baseApi.ts
Update listToolFiles guidance to “CALL THIS TOOL FIRST”; prepareHeaders no longer overwrites existing Content-Type.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • danpiths
  • akshaydeo
  • roroghost17

Poem

🐰 I stitched modes into a nimble net,

user, vk, session — tidy set.
Sessions listed, reauth in sight,
sweepers tidy through the night.
Hop, click, and your OAuth’s right!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-18-refactor_mcp_per_user_oauth_flow_refactor

Pratham-Mishra04 commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch 2 times, most recently from cc1d3ec to 05cfa3e Compare May 18, 2026 13:14
@Pratham-Mishra04
Pratham-Mishra04 marked this pull request as ready for review May 18, 2026 13:15
@greptile-apps

greptile-apps Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 3/5

The OAuth refactor and new sessions API are well-structured, but the tool-key re-prefixing logic in the MCP client update handler corrupts persisted tool maps for clients with hyphenated names on every update.

The new handler code in mcp.go uses strings.Cut(oldKey, "-") splitting at the first hyphen rather than at the full old client-name boundary. For a client named github-mcp, every updateMCPClient call rewrites github-mcp-list_repos as github-mcp-mcp-list_repos, silently corrupting the DB. The same block copies DiscoveredToolNameMapping verbatim, leaving stale keys after a rename that break tool dispatch on restart.

transports/bifrost-http/handlers/mcp.go lines 939-956 (tool-key re-prefixing block) and framework/configstore/migrations.go (BeforeSave AuthMode guard promised in comment but absent in tables/oauth.go).

Important Files Changed

Filename Overview
transports/bifrost-http/handlers/mcp.go Adds tool key re-prefixing on rename, but uses strings.Cut at the first hyphen instead of trimming the full old-name prefix — corrupts DiscoveredTools for hyphenated client names and leaves DiscoveredToolNameMapping with stale keys.
framework/configstore/migrations.go Five new migrations for OAuth auth-mode columns, session-token→session-id rename, legacy table drops, and config-hash refresh. Migration ordering is correct but the oauth_user_sessions flow_mode backfill uses 'none' for session-less rows and the BeforeSave AuthMode guard promised in a comment is not yet implemented in the table hook.
framework/oauth2/main.go InitiateUserOAuthFlow and CompleteUserOAuthFlow refactored to the new mode-based model; correctly guards against clobbering claiming rows and handles deferred-fill user-mode flows.
framework/configstore/rdb.go New CRUD methods for per-user OAuth tokens and sessions; ListAllOauthUserTokens correctly returns all statuses including needs_reauth; GetOauthUserSessionByModeIdentityAndMCPClient has no status filter (handled at application layer in InitiateUserOAuthFlow).
transports/bifrost-http/handlers/mcp_sessions.go New sessions-tab API; list/reauth/revoke/flowDetail/flowStart handlers with correct mode-based identity routing and deferred-fill user-mode support.
core/schemas/context.go Adds MCPAuthMode() helper on BifrostContext with MCPAuthModeNone sentinel, addressing the previous concern about unauthenticated requests returning MCPAuthModeSession.
transports/bifrost-http/handlers/oauth2.go handleCallbackError now correctly distinguishes admin-test vs per-user flows using state lookup; internal error messages are no longer forwarded verbatim to the browser URL.
framework/oauth2/sync.go Adds PerUserOAuthSweepWorker for expired-flow and orphaned-token cleanup; TokenRefreshWorker.Stop() guarded with sync.Once to prevent double-close panic.
transports/bifrost-http/lib/ctx.go Adds x-bf-mcp-session-id header ingestion with a 255-char cap matching ParseSessionIDFromBaggage, addressing the previous unbounded-length concern.

Reviews (18): Last reviewed commit: "refactor: mcp per user oauth flow refact..." | Re-trigger Greptile

Comment thread transports/bifrost-http/handlers/oauth2.go
Comment thread core/schemas/context.go
Comment thread transports/bifrost-http/handlers/oauth2.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
core/mcp/utils/utils.go (1)

21-50: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't fail user-mode OAuth before creating the pending flow.

InitiateUserOAuthFlow now explicitly supports MCPAuthModeUser with no UserID in context yet, but this identity == "" path returns before that branch can run. That breaks externally initiated/user-not-yet-bound MCP auth by turning it into an immediate error instead of creating the pending flow row that gets stamped on callback. Only vk/session modes need a non-empty identity up front; user mode should skip lookup and fall through to flow initiation.

🤖 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/utils/utils.go` around lines 21 - 50, The current early return when
identity == "" blocks user-mode flows; change the logic in the block that calls
identityForMCPAuthMode(ctx, mode) so it only rejects missing identity for modes
that require it (e.g., VK/session modes) and does not return for
MCPAuthModeUser; i.e., only error when identity == "" && mode != MCPAuthModeUser
(or use an explicit list of modes that require identity). Keep the rest of the
flow intact so InitiateUserOAuthFlow can be called for user-mode even when
UserID/identity is not yet present; continue to call
oauth2Provider.GetUserAccessTokenByMode, BuildRedirectURIFromContext, and
InitiateUserOAuthFlow as before.
transports/bifrost-http/handlers/mcpserver.go (1)

72-76: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Duplicate tool filter registration.

The same filter is registered twice on globalMCPServer (lines 72 and 74-75). This appears to be a copy-paste error that could cause the filter to execute twice per tools/list request.

Proposed fix
 	// Register per-request tool filter so x-bf-mcp-include-clients and x-bf-mcp-include-tools are respected on tools/list
 	server.WithToolFilter(handler.makeIncludeClientsFilter())(handler.globalMCPServer)
 
-	// Register per-request tool filter so x-bf-mcp-include-clients and x-bf-mcp-include-tools are respected on tools/list
-	server.WithToolFilter(handler.makeIncludeClientsFilter())(handler.globalMCPServer)
-
 	if err := handler.SyncAllMCPServers(ctx); err != nil {
🤖 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 `@transports/bifrost-http/handlers/mcpserver.go` around lines 72 - 76, The same
tool filter is registered twice on globalMCPServer via
server.WithToolFilter(handler.makeIncludeClientsFilter()), causing it to run
twice; remove the duplicate call so only a single registration of
server.WithToolFilter(handler.makeIncludeClientsFilter()) on
handler.globalMCPServer remains (or replace the second call with the correct
filter if it was meant to be a different one), ensuring the per-request tool
filter is registered exactly once.
framework/configstore/rdb.go (1)

4711-4750: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle concurrent first-time token writes as a real upsert.

This still falls back to SELECT-then-CREATE on the miss path. Two same-identity callbacks can both miss existing, and one will fail on the unique index instead of replacing the row, which makes re-auth flaky under retries/concurrent callbacks. Use a conflict-aware insert or retry the create path by re-reading and Saveing on unique-violation.

🤖 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 `@framework/configstore/rdb.go` around lines 4711 - 4750, The current
Transaction in s.DB().WithContext(ctx).Transaction does a SELECT-then-CREATE and
can race: when lookupErr is gorm.ErrRecordNotFound two concurrent callers may
both try tx.Create(token) and one will hit a unique-constraint error; change the
miss path to do a conflict-aware upsert or retry-on-unique-violation.
Concretely, replace the tx.Create(token) branch with either a GORM OnConflict
clause (e.g., use tx.Clauses(clause.OnConflict{UpdateAll: true}).Create(token))
to perform an atomic upsert, or catch the unique-constraint error from
tx.Create, re-query the existing row via dbForUpdate(tx) (same WHERE logic using
token.UserID/VirtualKeyID/SessionID) and then set
token.ID/CreatedAt/LastRefreshedAt and call tx.Save(token) so the second writer
merges instead of failing.
🧹 Nitpick comments (4)
ui/app/_fallbacks/enterprise/components/mcp-sessions/dacFilterPill.tsx (1)

5-7: ⚡ Quick win

Rename this file to PascalCase to match UI component conventions.

The component export is correctly PascalCase, but the filename dacFilterPill.tsx is not. Please rename it to DACFilterPill.tsx (and update imports accordingly) for consistency with the TSX naming rule.

As per coding guidelines: ui/**/*.tsx: React component files must use PascalCase for component exports and filenames.

🤖 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/_fallbacks/enterprise/components/mcp-sessions/dacFilterPill.tsx`
around lines 5 - 7, The file name needs to be changed to PascalCase to match the
component export; rename the file from dacFilterPill.tsx to DACFilterPill.tsx
and update all imports that reference this file to the new filename (search for
imports referencing dacFilterPill and update them). Ensure the exported
component function DACFilterPill remains unchanged and that build/test imports
compile after the rename.
ui/app/_fallbacks/enterprise/components/mcp-sessions/grantedViaVKChips.tsx (1)

11-13: ⚡ Quick win

Use PascalCase for this TSX filename as well.

grantedViaVKChips.tsx should be renamed to GrantedViaVKChips.tsx to stay consistent with the component file naming convention.

As per coding guidelines: ui/**/*.tsx: React component files must use PascalCase for component exports and filenames.

🤖 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/_fallbacks/enterprise/components/mcp-sessions/grantedViaVKChips.tsx`
around lines 11 - 13, Rename the TSX file from grantedViaVKChips.tsx to
GrantedViaVKChips.tsx to match the component export GrantedViaVKChips and the
project's PascalCase convention; perform a git mv to preserve history, then
update any imports that reference the old filename (search for
"grantedViaVKChips" usages) so they point to "GrantedViaVKChips" and run the
build/typecheck to ensure no broken imports remain.
ui/lib/store/apis/mcpSessionsApi.ts (1)

22-25: ⚡ Quick win

Consider optimistic cache patching for revokeMCPSession to match patterns in this directory, but note reauthMCPSession cannot be optimistically patched.

The pattern of using onQueryStarted + updateQueryData for mutations in ui/lib/store/apis/ exists (see deleteRoutingRule), but is inconsistently applied across the codebase—deleteLogs and deleteMCPLogs also use only invalidatesTags.

For revokeMCPSession, implementing optimistic cache patching would improve UX by removing the deleted session from getMCPSessions cache immediately, avoiding a full refetch.

However, reauthMCPSession returns MCPSessionReauthResponse (an OAuth URL), not updated session data, so it cannot be optimistically patched. The invalidatesTags approach is appropriate for this mutation.

Also applies to: lines 28–31 (revokeMCPSession only; reauthMCPSession is unsuitable for optimistic patching)

🤖 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/lib/store/apis/mcpSessionsApi.ts` around lines 22 - 25, The review notes
that revokeMCPSession should follow the optimistic cache-patching pattern used
elsewhere (use onQueryStarted + updateQueryData) to remove the deleted session
from the getMCPSessions cache immediately, while reauthMCPSession should remain
using invalidatesTags because it returns an OAuth URL rather than updated
session data; therefore, modify the revokeMCPSession mutation to implement
onQueryStarted that patches getMCPSessions (remove the session by id and roll
back on error), referencing the revokeMCPSession mutation and getMCPSessions
cache-updater, and leave reauthMCPSession as-is (invalidatesTags only).
transports/bifrost-http/lib/config.go (1)

3080-3085: 💤 Low value

Consider making the OAuth sweep retention period configurable.

The 30-day retention period is currently hardcoded. While this is a reasonable default and clearly documented, consider allowing configuration via FrameworkConfig or an environment variable in a future iteration to give operators control over orphan cleanup policy.

Current implementation is correct and safe for this refactor.

🤖 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 `@transports/bifrost-http/lib/config.go` around lines 3080 - 3085, The
hardcoded 30-day retention in the call to oauth2.NewPerUserOAuthSweepWorker
should be made configurable: add a retention field (e.g., OAuthSweepRetention
time.Duration) to the FrameworkConfig (or read from an ENV var with a
30*24*time.Hour default), plumb that value into config.OAuthSweepWorker creation
instead of the literal 30*24*time.Hour, and ensure any config
initialization/validation sets the default when unset; update references to
NewPerUserOAuthSweepWorker and config.OAuthSweepWorker initialization to use the
new configurable retention.
🤖 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 `@framework/configstore/migrations.go`:
- Around line 7646-7651: The partial unique indexes
idx_oauth_user_tokens_user_mcp and idx_oauth_user_tokens_vk_mcp on table
oauth_user_tokens currently only exclude NULLs, but the backfill treats empty
string ('') as unset so rows with user_id = '' or virtual_key_id = '' will still
be indexed and can cause uniqueness failures; update the CREATE UNIQUE INDEX
predicates to also exclude empty strings (e.g. add "AND user_id <> ''" for
idx_oauth_user_tokens_user_mcp and "AND virtual_key_id <> ''" for
idx_oauth_user_tokens_vk_mcp) so only meaningful identities participate in the
unique index.
- Around line 7683-7690: The CASE updating oauth_user_sessions.flow_mode
incorrectly maps legacy session-backed rows to 'none'; modify the SQL in the
migration (the tx.Exec(...) block) to include a WHEN branch that sets 'session'
when session_token_hash IS NOT NULL AND session_token_hash != '' (place this
check before the ELSE), so existing session-mode records are backfilled
correctly prior to migrationReplaceOauthSessionTokenWithSessionID.
- Around line 7762-7784: After adding the SessionID column on
TableOauthUserSession, create the corresponding index by calling
mg.CreateIndex(&tables.TableOauthUserSession{}, "SessionID") (and check/return
any error) so the new column gets the same indexed lookup as before; place this
call immediately after the AddColumn block for SessionID and before finishing
the migration (mirroring how the oauth_user_tokens migration recreates its
index).

In `@framework/configstore/rdb.go`:
- Around line 4631-4652: The lookup
GetOauthUserSessionByModeIdentityAndMCPClient currently returns rows stuck in
status "claiming" and must ignore/expire stale claiming rows; update the query
in GetOauthUserSessionByModeIdentityAndMCPClient to exclude sessions whose
status == "claiming" unless their last-update timestamp is older than the
claiming timeout (use a shared ClaimExpiryDuration or config constant and
compare against updated_at/claimed_at), so only genuinely expired claiming rows
are returned; apply the identical change to the other analogous lookup (the
block at the other occurrence around lines 5038-5046) and ensure any error
messages remain unchanged.

In `@framework/oauth2/sync.go`:
- Around line 182-184: The Stop method on PerUserOAuthSweepWorker closes
w.stopCh unguarded which can panic if Stop is called multiple times; make Stop
idempotent by adding and using a sync.Once (e.g., a field like stopOnce
sync.Once on PerUserOAuthSweepWorker) and call stopOnce.Do(func(){
close(w.stopCh) }) inside the Stop method (retain the existing logger nil-check
after the guarded close). This mirrors the pattern used in
framework/tracing/store.go where channel closes are protected by sync.Once.

In `@transports/bifrost-http/handlers/mcp_sessions.go`:
- Around line 376-380: BuildUpstreamAuthorizeURL can return errors for
stale/expired/not-pending flows but the handler currently maps all failures to
500; update the error handling in the mcp_sessions.go block that calls
h.store.OAuthProvider.BuildUpstreamAuthorizeURL(ctx, flowID) so that it checks
the returned error for the flow-stale conditions (e.g., compare against the
provider's sentinel errors like ErrFlowExpired, ErrFlowNotPending or inspect an
exported error code/type) and when matched return a 4xx response (410 Gone or
400 Bad Request) via SendError instead of 500; keep logging (logger.Error) but
include the error details and still return 500 only for unexpected/internal
errors.
- Around line 77-99: The code currently treats identity == "" as a signal to use
the admin (ListAll...) branch regardless of auth mode; change the guard so that
the admin branch is only taken when no auth mode is configured (mode == ""), and
when mode != "" but identity == "" the handler fails closed (return an
unauthorized/identity resolution error or empty result) instead of calling
ListAllOauthUserTokens/ListAllPendingOauthUserSessions; update the branch around
callerModeAndIdentity(bfCtx) (checking mode and identity) to call
ListOauthUserTokensByMode/ListOauthUserSessionsByMode when mode != "" and
identity present, only call the ListAll* functions when mode == "" and identity
== "", and return an error when mode != "" && identity == "".

In `@ui/app/workspace/config/views/mcpView.tsx`:
- Around line 279-283: The new AccordionTrigger element for the "Advanced
Settings" section is missing a stable test selector; add a data-testid attribute
to the AccordionTrigger (the JSX element with <AccordionTrigger> that is inside
the AccordionItem value="advanced-settings") using the 3-part convention, e.g.
data-testid="mcp-settings-advanced-trigger", so E2E tests can reliably target
this interactive control.

In `@ui/app/workspace/mcp-sessions/auth/page.tsx`:
- Around line 135-140: Add stable data-testid attributes to the new interactive
auth controls so E2E tests can select them: add data-testid="auth-button" on the
primary Button that calls handleAuthenticate (handles both Authenticate and
Re-authenticate states), add data-testid="sessions-tab-link" on the
SessionsTabLink component, and add data-testid="sign-in-button" on the sign-in
control (the button/link that triggers sign-in in the same file — also apply
identical data-testid additions for the duplicate auth/sign-in controls around
lines 244-271). Ensure the attributes are added directly to the React elements
(Button, SessionsTabLink, sign-in button) without changing their behavior.
- Around line 222-233: The formatExpiry helper can produce "in NaN minutes"
because new Date(iso).getTime() returns NaN for invalid strings; update
formatExpiry to validate the parsed time (e.g., const t = d.getTime() and if
(Number.isNaN(t) ) return iso) before computing diffMs and minutes so invalid
ISO inputs fall back to the original iso string; keep the existing
negative/difference logic intact and reference the formatExpiry function when
making the change.

In `@ui/app/workspace/mcp-sessions/oauth-callback/page.tsx`:
- Around line 52-54: The new interactive "Back to MCP sessions" control (the
Button component using asChild wrapping the Link with
to="/workspace/mcp-sessions") needs a data-testid added to satisfy E2E
conventions; add a data-testid prop (for example
data-testid="back-to-mcp-sessions") to the interactive element (either on the
Link or passed through Button when using asChild) so the selector targets this
new control (refer to the Button and Link instances in the
oauth-callback/page.tsx snippet).

In `@ui/app/workspace/mcp-sessions/views/sessionsTable.tsx`:
- Around line 71-82: Add stable data-testid attributes to the new MCP session
interactive elements so E2E can target them: add data-testid to the dialog
buttons rendered by AlertDialogCancel and AlertDialogAction (e.g.
"mcp-session-revoke-cancel" and "mcp-session-revoke-confirm") while keeping the
existing onClick handler confirmRevoke; add a stable data-testid on the row
actions trigger component used to open the menu (e.g.
"mcp-session-row-actions-<sessionId>" or similar unique id bound to the row) and
add data-testid attributes to the menu items for Revoke and Re-auth flows (e.g.
"mcp-session-revoke-menu-item" and "mcp-session-reauth-menu-item"); ensure the
ids include the session identifier where appropriate for uniqueness and attach
them directly to the rendered interactive elements (AlertDialogCancel,
AlertDialogAction, the row-actions trigger, and the corresponding menu item
components).
- Around line 301-334: Both formatRelativePast and formatAccessExpiry need to
guard against invalid timestamps because new Date(...).getTime() can be NaN (it
doesn’t throw); update formatRelativePast(iso: string) to compute const t = new
Date(iso).getTime() and if Number.isNaN(t) return iso, then use diffMs =
Date.now() - t; similarly in formatAccessExpiry(row: MCPSessionRow) compute
const t = new Date(row.expires_at).getTime() and if Number.isNaN(t) return
row.expires_at, then use diffMs = t - Date.now() and continue existing
logic—this prevents "NaNd" or "in NaN min" outputs.

---

Outside diff comments:
In `@core/mcp/utils/utils.go`:
- Around line 21-50: The current early return when identity == "" blocks
user-mode flows; change the logic in the block that calls
identityForMCPAuthMode(ctx, mode) so it only rejects missing identity for modes
that require it (e.g., VK/session modes) and does not return for
MCPAuthModeUser; i.e., only error when identity == "" && mode != MCPAuthModeUser
(or use an explicit list of modes that require identity). Keep the rest of the
flow intact so InitiateUserOAuthFlow can be called for user-mode even when
UserID/identity is not yet present; continue to call
oauth2Provider.GetUserAccessTokenByMode, BuildRedirectURIFromContext, and
InitiateUserOAuthFlow as before.

In `@framework/configstore/rdb.go`:
- Around line 4711-4750: The current Transaction in
s.DB().WithContext(ctx).Transaction does a SELECT-then-CREATE and can race: when
lookupErr is gorm.ErrRecordNotFound two concurrent callers may both try
tx.Create(token) and one will hit a unique-constraint error; change the miss
path to do a conflict-aware upsert or retry-on-unique-violation. Concretely,
replace the tx.Create(token) branch with either a GORM OnConflict clause (e.g.,
use tx.Clauses(clause.OnConflict{UpdateAll: true}).Create(token)) to perform an
atomic upsert, or catch the unique-constraint error from tx.Create, re-query the
existing row via dbForUpdate(tx) (same WHERE logic using
token.UserID/VirtualKeyID/SessionID) and then set
token.ID/CreatedAt/LastRefreshedAt and call tx.Save(token) so the second writer
merges instead of failing.

In `@transports/bifrost-http/handlers/mcpserver.go`:
- Around line 72-76: The same tool filter is registered twice on globalMCPServer
via server.WithToolFilter(handler.makeIncludeClientsFilter()), causing it to run
twice; remove the duplicate call so only a single registration of
server.WithToolFilter(handler.makeIncludeClientsFilter()) on
handler.globalMCPServer remains (or replace the second call with the correct
filter if it was meant to be a different one), ensuring the per-request tool
filter is registered exactly once.

---

Nitpick comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 3080-3085: The hardcoded 30-day retention in the call to
oauth2.NewPerUserOAuthSweepWorker should be made configurable: add a retention
field (e.g., OAuthSweepRetention time.Duration) to the FrameworkConfig (or read
from an ENV var with a 30*24*time.Hour default), plumb that value into
config.OAuthSweepWorker creation instead of the literal 30*24*time.Hour, and
ensure any config initialization/validation sets the default when unset; update
references to NewPerUserOAuthSweepWorker and config.OAuthSweepWorker
initialization to use the new configurable retention.

In `@ui/app/_fallbacks/enterprise/components/mcp-sessions/dacFilterPill.tsx`:
- Around line 5-7: The file name needs to be changed to PascalCase to match the
component export; rename the file from dacFilterPill.tsx to DACFilterPill.tsx
and update all imports that reference this file to the new filename (search for
imports referencing dacFilterPill and update them). Ensure the exported
component function DACFilterPill remains unchanged and that build/test imports
compile after the rename.

In `@ui/app/_fallbacks/enterprise/components/mcp-sessions/grantedViaVKChips.tsx`:
- Around line 11-13: Rename the TSX file from grantedViaVKChips.tsx to
GrantedViaVKChips.tsx to match the component export GrantedViaVKChips and the
project's PascalCase convention; perform a git mv to preserve history, then
update any imports that reference the old filename (search for
"grantedViaVKChips" usages) so they point to "GrantedViaVKChips" and run the
build/typecheck to ensure no broken imports remain.

In `@ui/lib/store/apis/mcpSessionsApi.ts`:
- Around line 22-25: The review notes that revokeMCPSession should follow the
optimistic cache-patching pattern used elsewhere (use onQueryStarted +
updateQueryData) to remove the deleted session from the getMCPSessions cache
immediately, while reauthMCPSession should remain using invalidatesTags because
it returns an OAuth URL rather than updated session data; therefore, modify the
revokeMCPSession mutation to implement onQueryStarted that patches
getMCPSessions (remove the session by id and roll back on error), referencing
the revokeMCPSession mutation and getMCPSessions cache-updater, and leave
reauthMCPSession as-is (invalidatesTags only).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a9d4ac5-f8a4-4862-8b1d-426f7d7a8ce0

📥 Commits

Reviewing files that changed from the base of the PR and between 89a99f0 and 05cfa3e.

📒 Files selected for processing (42)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/_fallbacks/enterprise/components/mcp-sessions/dacFilterPill.tsx
  • ui/app/_fallbacks/enterprise/components/mcp-sessions/grantedViaVKChips.tsx
  • ui/app/_fallbacks/enterprise/components/mcp-sessions/userDisplay.tsx
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/sidebar.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (8)
  • transports/bifrost-http/handlers/oauth2_consent.go
  • ui/lib/types/config.ts
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • framework/configstore/rdb_test.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/config.go

Comment thread framework/configstore/migrations.go Outdated
Comment thread framework/configstore/migrations.go
Comment thread framework/configstore/migrations.go
Comment thread framework/configstore/rdb.go
Comment thread framework/oauth2/sync.go Outdated
Comment thread ui/app/workspace/mcp-sessions/auth/page.tsx
Comment thread ui/app/workspace/mcp-sessions/auth/page.tsx
Comment thread ui/app/workspace/mcp-sessions/oauth-callback/page.tsx Outdated
Comment thread ui/app/workspace/mcp-sessions/views/sessionsTable.tsx Outdated
Comment thread ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 05cfa3e to 9bab60b Compare May 19, 2026 14:23
Comment thread transports/bifrost-http/handlers/mcp_sessions.go
Comment thread framework/configstore/rdb.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
framework/configstore/rdb.go (1)

4780-4819: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

The new "upsert" path still races on first insert.

When no row exists yet, the SELECT ... FOR UPDATE locks nothing. Two concurrent callbacks/reauths for the same (identity, mcp_client_id) can both miss, both hit Create, and one will fail on the unique constraint instead of converging on a single row. Use a real ON CONFLICT DO UPDATE path here, or retry the locked read/update path after a duplicate-key insert error.

🤖 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 `@framework/configstore/rdb.go` around lines 4780 - 4819, The upsert currently
does a SELECT ... FOR UPDATE via dbForUpdate inside the Transaction and falls
back to tx.Create which races on first insert; change this to a true DB-level
upsert or retry-on-duplicate-key: either replace the lookup+Create path with a
single ON CONFLICT DO UPDATE upsert using GORM's
Clauses(clause.OnConflict{UpdateAll: true} or a specific SET list) against
tables.TableOauthUserToken, or keep the SELECT/LOCK flow but catch a
unique-constraint error from tx.Create and in that case re-run the locked lookup
(dbForUpdate(...).First(&existing)) and then tx.Save(token) to update the
existing row; adjust tx.Save/tx.Create usage accordingly inside
s.DB().WithContext(ctx).Transaction to ensure only one row is created for
(user_id|virtual_key_id|session_id, mcp_client_id).
♻️ Duplicate comments (1)
framework/configstore/migrations.go (1)

7772-7779: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Backfill flow_mode for legacy session rows too.

At this point session_token_hash/session_id is still the only way to recognize session-backed rows. Falling through to 'none' means the immediately following migrationDropNonVKOauthUserRows will delete valid session-mode records instead of just the bindings you intend to retire.

🤖 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 `@framework/configstore/migrations.go` around lines 7772 - 7779, The UPDATE
that sets flow_mode in migrations.go currently falls back to 'none' and thus
will misclassify legacy session-backed rows; modify the CASE in the tx.Exec(...)
SQL (the block that updates oauth_user_sessions) to include a WHEN that checks
for session_token_hash IS NOT NULL OR session_id IS NOT NULL (and not empty if
applicable) and sets flow_mode = 'session' for those rows before the ELSE branch
so legacy session records are backfilled correctly.
🧹 Nitpick comments (3)
ui/app/workspace/mcp-sessions/page.tsx (1)

3-3: ⚡ Quick win

Use @/... alias import instead of a relative path.

Please switch this import to the UI alias pattern for consistency with the rest of the codebase.

Suggested change
-import SessionsTable from "./views/sessionsTable";
+import SessionsTable from "`@/app/workspace/mcp-sessions/views/sessionsTable`";

Based on learnings, in the UI codebase prefer alias imports using @/... over relative imports in TS/TSX files under ui/.

🤖 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-sessions/page.tsx` at line 3, Replace the relative
import of SessionsTable in page.tsx with the UI alias import pattern: update the
import statement that currently reads import SessionsTable from
"./views/sessionsTable" to use the '`@/`...' alias (import SessionsTable from
"`@/`..." pointing to the same views/sessionsTable module) so the file uses the
project-wide UI alias convention for TSX imports.
transports/bifrost-http/handlers/governance.go (2)

1431-1445: 🏗️ Heavy lift

Consider aligning deletion order across all entity handlers.

The new cleanup order (DB deletion → in-memory removal) in deleteVirtualKey follows the safer pattern also used in deleteRoutingRule (line 3554): persist the DB change first, then update in-memory state as a non-fatal operation. However, deleteTeam (line 1926) and deleteCustomer (line 2307) still use the old order (in-memory first, then DB).

The new pattern is preferable because:

  • DB becomes the definitive source of truth before in-memory state changes
  • If DB deletion fails, in-memory state remains untouched
  • In-memory cleanup failures after successful DB deletion are safely logged without blocking the operation

Recommend updating deleteTeam and deleteCustomer to follow the same pattern for consistency and to ensure all deletion handlers treat the database as the authoritative source.

🤖 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 `@transports/bifrost-http/handlers/governance.go` around lines 1431 - 1445,
Standardize deletion order across handlers: follow the pattern used in
deleteVirtualKey and deleteRoutingRule—perform the persistent deletion via
configStore (e.g., configStore.DeleteTeam / configStore.DeleteCustomer) first,
handle configstore.ErrNotFound appropriately, then perform in-memory cleanup
(e.g., governanceManager.RemoveTeam / governanceManager.RemoveCustomer) as a
best-effort non-fatal step and log any removal errors without returning failure;
update deleteTeam and deleteCustomer to mirror deleteVirtualKey's flow and
logging behavior so the DB remains the source of truth and in-memory failures do
not block the successful API response.

1443-1443: ⚡ Quick win

Complete the error-handling comment.

The comment on line 1443 is incomplete: "But we ignore this error because its not" ends mid-sentence. The same incomplete comment appears at lines 1929 (deleteTeam) and 2309 (deleteCustomer).

Complete the explanation or adopt the clearer pattern from deleteRoutingRule (line 3564): "non-fatal: DB already updated".

📝 Suggested fix for all three locations
-		// But we ignore this error because its not
+		// In-memory removal is non-fatal: DB deletion already succeeded
 		logger.Error("failed to remove virtual key: %v", err)

Apply the same fix at lines 1929 and 2309.

🤖 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 `@transports/bifrost-http/handlers/governance.go` at line 1443, Replace the
incomplete comment "But we ignore this error because its not" with a clear
non-fatal explanation matching the pattern used in deleteRoutingRule: e.g.,
"non-fatal: DB already updated". Do this for the three occurrences in
governance.go: the comment at line ~1443 and the ones in the deleteTeam and
deleteCustomer functions (the existing deleteRoutingRule comment can be used as
the reference wording).
🤖 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 `@framework/configstore/migrations.go`:
- Around line 7993-8009: The Rollback implementation for the migration (the
Rollback func that uses tx.Exec to ALTER TABLE and recreate oauth_per_user_*
tables) is unsafe because it fakes table restoration; replace that logic with an
explicit irreversible error: remove the best-effort ALTER/CREATE statements and
have Rollback immediately return fmt.Errorf("irreversible migration: legacy
oauth_per_user schema not restorable") (or similar) so downgrades fail fast
unless the real legacy schema and data restoration is implemented; ensure the
function signature and returned error type remain compatible with the current
migration framework.

In `@framework/configstore/rdb.go`:
- Around line 4721-4727: Update the outdated comment on
GetOauthUserSessionByModeIdentityAndMCPClient to remove the mention of hashing
the session token for lookups and clearly state that for AuthModeSession the
store now queries session_id directly (no hashing), and make the same
clarification in the corresponding helper comments around the later block (the
other session-mode helper in the same file). Ensure the per-mode identity
mapping lines (AuthModeUser, AuthModeVK, AuthModeSession) accurately reflect
current behavior and mention that session lookups/deletes use the raw/session_id
column rather than a hashed value.
- Around line 4954-4968: ListAllOauthUserTokens currently filters statuses to
only "active" (and "orphaned") so tokens set to "needs_reauth" (by
MarkOauthUserTokenNeedsReauthByID) are excluded; update the statuses slice and
the Where("status IN ?", statuses) usage in ListAllOauthUserTokens to include
"needs_reauth" (or conditionally include it if desired) so those rows appear in
the sessions listing, ensuring Preload and Order calls remain unchanged.

In `@transports/bifrost-http/handlers/mcp_sessions.go`:
- Around line 83-98: The list handler currently returns all sessions because no
DAC QueryScope or caller identity is applied; fix by extracting the caller
identity from the request context (the auth info injected by middleware) and set
a QueryScope in ctx before calling h.store.ConfigStore.ListAllOauthUserTokens
and ListAllPendingOauthUserSessions so the store returns only visible rows, or
if setting QueryScope is not possible, post-filter the returned slices
(flows/tokens) by comparing each row's owner/team fields to the caller identity
(use the same visibility rules used elsewhere), then continue to call tokenRow()
/ flowRow() only on the filtered set; update list() to perform one of these two
actions and ensure any context helper used to set/query scope (the ScopedDB(ctx)
path) sees the new QueryScope.

---

Outside diff comments:
In `@framework/configstore/rdb.go`:
- Around line 4780-4819: The upsert currently does a SELECT ... FOR UPDATE via
dbForUpdate inside the Transaction and falls back to tx.Create which races on
first insert; change this to a true DB-level upsert or retry-on-duplicate-key:
either replace the lookup+Create path with a single ON CONFLICT DO UPDATE upsert
using GORM's Clauses(clause.OnConflict{UpdateAll: true} or a specific SET list)
against tables.TableOauthUserToken, or keep the SELECT/LOCK flow but catch a
unique-constraint error from tx.Create and in that case re-run the locked lookup
(dbForUpdate(...).First(&existing)) and then tx.Save(token) to update the
existing row; adjust tx.Save/tx.Create usage accordingly inside
s.DB().WithContext(ctx).Transaction to ensure only one row is created for
(user_id|virtual_key_id|session_id, mcp_client_id).

---

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 7772-7779: The UPDATE that sets flow_mode in migrations.go
currently falls back to 'none' and thus will misclassify legacy session-backed
rows; modify the CASE in the tx.Exec(...) SQL (the block that updates
oauth_user_sessions) to include a WHEN that checks for session_token_hash IS NOT
NULL OR session_id IS NOT NULL (and not empty if applicable) and sets flow_mode
= 'session' for those rows before the ELSE branch so legacy session records are
backfilled correctly.

---

Nitpick comments:
In `@transports/bifrost-http/handlers/governance.go`:
- Around line 1431-1445: Standardize deletion order across handlers: follow the
pattern used in deleteVirtualKey and deleteRoutingRule—perform the persistent
deletion via configStore (e.g., configStore.DeleteTeam /
configStore.DeleteCustomer) first, handle configstore.ErrNotFound appropriately,
then perform in-memory cleanup (e.g., governanceManager.RemoveTeam /
governanceManager.RemoveCustomer) as a best-effort non-fatal step and log any
removal errors without returning failure; update deleteTeam and deleteCustomer
to mirror deleteVirtualKey's flow and logging behavior so the DB remains the
source of truth and in-memory failures do not block the successful API response.
- Line 1443: Replace the incomplete comment "But we ignore this error because
its not" with a clear non-fatal explanation matching the pattern used in
deleteRoutingRule: e.g., "non-fatal: DB already updated". Do this for the three
occurrences in governance.go: the comment at line ~1443 and the ones in the
deleteTeam and deleteCustomer functions (the existing deleteRoutingRule comment
can be used as the reference wording).

In `@ui/app/workspace/mcp-sessions/page.tsx`:
- Line 3: Replace the relative import of SessionsTable in page.tsx with the UI
alias import pattern: update the import statement that currently reads import
SessionsTable from "./views/sessionsTable" to use the '`@/`...' alias (import
SessionsTable from "`@/`..." pointing to the same views/sessionsTable module) so
the file uses the project-wide UI alias convention for TSX imports.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 844e4b7c-3bff-4563-8d4c-65c5ac3a86a6

📥 Commits

Reviewing files that changed from the base of the PR and between 05cfa3e and 9bab60b.

📒 Files selected for processing (41)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/sidebar.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (8)
  • ui/lib/types/config.ts
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • framework/configstore/rdb_test.go
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/config.go
✅ Files skipped from review due to trivial changes (1)
  • ui/lib/store/apis/baseApi.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • ui/app/workspace/mcp-sessions/layout.tsx
  • core/schemas/context.go
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • core/schemas/bifrost.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/mcpserver.go
  • framework/oauth2/sync.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/lib/store/apis/index.ts
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/components/sidebar.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/ui/alert.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • core/mcp/utils/utils.go
  • ui/lib/store/apis/mcpSessionsApi.ts
  • transports/bifrost-http/lib/config.go
  • framework/configstore/tables/oauth.go

Comment thread framework/configstore/migrations.go Outdated
Comment thread framework/configstore/migrations.go
Comment thread framework/configstore/rdb.go
Comment thread framework/configstore/rdb.go Outdated
Comment thread transports/bifrost-http/handlers/mcp_sessions.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 9bab60b to 3b6be1e Compare May 19, 2026 15:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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 `@framework/configstore/migrations.go`:
- Around line 8056-8120: This migration mixes a heavy SELECT/UPDATE backfill of
config_hash with an ALTER TABLE DROP COLUMN in the same migration (the Migrate
func), which can lock config_client; split this into two migrations like
migrationDropAllowDirectKeysColumn / migrationDropAllowDirectKeysColumnDDL: keep
the backfill logic (the tx.Find loop that regenerates and updates config_hash
using ClientConfig.GenerateClientConfigHash and tx.Model(&cc).Update) in one
migration that performs only the row updates, and move the ALTER TABLE DROP
COLUMN mcp_external_server_url into a separate migration that runs the DDL only
(non-transactional/DDL migration variant) so the expensive row updates and the
DROP COLUMN do not run in the same transaction or migration step.
- Around line 7725-7753: The migration currently constructs partialUniques and
will fail if duplicate (identity, mcp_client_id) rows exist; before executing
the CREATE UNIQUE INDEX statements (idx_oauth_user_tokens_user_mcp,
idx_oauth_user_tokens_vk_mcp and the session-based index), add a deduplication
step that finds duplicate groups in oauth_user_tokens grouped by (user_id,
mcp_client_id) and (virtual_key_id, mcp_client_id) (and the sessionCol variant
when sessionCol != ""), and collapse them (e.g. keep the single canonical row
per group by newest/highest id or archive duplicates into a separate table and
delete the extras) so no more than one row per unique key remains; perform this
dedupe inside the same tx before iterating partialUniques so the subsequent
tx.Exec(...) CREATE UNIQUE INDEX calls succeed.

In `@framework/configstore/tables/oauth.go`:
- Around line 166-170: Validate and enforce the FlowMode invariants inside
TableOauthUserSession.BeforeSave by (1) ensuring each flow_mode value only has
its allowed identity field set—'session' requires SessionID and disallows
VirtualKeyID/UserID, 'vk' requires VirtualKeyID and disallows SessionID/UserID,
'user' requires UserID and disallows SessionID/VirtualKeyID—and return an error
if the combination is invalid, and (2) prevent changes to FlowMode on updates by
comparing the existing DB row's FlowMode to the current struct and rejecting any
modification; apply the same validation logic to the related
BeforeSave/BeforeUpdate hooks referenced near the other oauth user session
handling block so invariants are enforced on both create and update paths.
- Around line 229-234: The BeforeSave hook must enforce the one-identity-per-row
contract for TableOauthUserToken: validate that AuthMode is one of "session",
"vk", or "user" and that exactly the matching identity column is present (for
"session" SessionID is non-empty and VirtualKeyID/UserID are nil/empty; for "vk"
VirtualKeyID is non-nil/non-empty and SessionID/UserID are nil/empty; for "user"
UserID is non-nil/non-empty and SessionID/VirtualKeyID are nil/empty). Update
TableOauthUserToken.BeforeSave to perform this check and return an error if the
shape is invalid; include the field names SessionID, VirtualKeyID, UserID and
AuthMode in the validation logic. Apply the same validation to the other
lifecycle hook(s) that handle persistence for TableOauthUserToken (the similar
block referenced around lines 258-271) so the invariant is enforced on
create/update paths.

In `@transports/bifrost-http/handlers/oauth2.go`:
- Around line 114-116: The code sets oauthConfig.Status = "failed" and calls
h.store.ConfigStore.UpdateOauthConfig(context.Background(), oauthConfig) but
ignores the returned error; modify the call to capture the error from
UpdateOauthConfig and log it (including the error value and relevant context
such as oauthConfig.ID or client name) via the existing logger (e.g., h.logger
or processLogger) so failures to persist the status are visible for debugging
when h.store.ConfigStore.UpdateOauthConfig(...) returns an error.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6608334f-5dc4-440b-8343-ab0dde1c7725

📥 Commits

Reviewing files that changed from the base of the PR and between 9bab60b and 3b6be1e.

📒 Files selected for processing (29)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (5)
  • ui/lib/types/config.ts
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/clientconfig.go
  • framework/configstore/rdb_test.go
  • transports/bifrost-http/handlers/config.go
🚧 Files skipped from review as they are similar to previous changes (18)
  • transports/bifrost-http/handlers/governance.go
  • core/schemas/mcp.go
  • core/schemas/bifrost.go
  • transports/bifrost-http/lib/ctx.go
  • ui/components/ui/alert.tsx
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • core/mcp/utils/utils.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/lib/config.go
  • framework/oauth2/sync.go
  • core/schemas/context.go
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/lib/config_test.go
  • framework/oauth2/main.go
  • core/schemas/oauth.go
  • framework/configstore/rdb.go

Comment thread framework/configstore/migrations.go Outdated
Comment thread framework/configstore/migrations.go Outdated
Comment thread framework/configstore/tables/oauth.go
Comment thread framework/configstore/tables/oauth.go
Comment thread transports/bifrost-http/handlers/oauth2.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 3b6be1e to 8b3deb7 Compare May 19, 2026 16:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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 `@framework/configstore/migrations.go`:
- Around line 7671-7821: The dedupe SQL (dedupeStmts) and the partialUniques
index statements must be constrained by auth_mode so rows that contain multiple
identity columns only participate in the intended uniqueness/dedupe domain;
update each dedupe DELETE and each CREATE UNIQUE INDEX predicate to include the
matching auth_mode filter (e.g. for the user partition/index add "AND auth_mode
= 'user'" / WHERE auth_mode = 'user', for vk use 'vk', for session use
'session'), using the existing variables sessionCol, dedupeStmts and
partialUniques and leaving the backfillSQL unchanged; this ensures dedupe keeps
the correct winner and CREATE UNIQUE INDEX succeeds prior to
migrationDropNonVKOauthUserRows.

In `@transports/bifrost-http/handlers/oauth2.go`:
- Around line 79-80: The logger.Error calls in
transports/bifrost-http/handlers/oauth2.go are emitting raw OAuth `state` values
(e.g., the call that currently logs "[oauth] per-user callback completion
failed: state=%s err=%v" along with similar logger.Error uses later), which must
be removed; update those logger.Error invocations to omit the raw state and
instead log only non-sensitive context and the error (perUserErr), or log a
deterministic safe surrogate (e.g., a short hash or the literal "<redacted>") if
you need to correlate attempts. Apply the same change for all occurrences of
logger.Error that include `state` and ensure redirects (ctx.Redirect calls)
remain unchanged except for not relying on logged state.
- Line 77: Replace usage of context.Background() with the incoming fasthttp
request context variable (ctx) when calling request-scoped methods: pass ctx
into h.oauthProvider.CompleteUserOAuthFlow(...) instead of context.Background(),
and do the same for subsequent store/OAuth calls in this handler (calls on
h.store and any other methods invoked around the CompleteUserOAuthFlow call and
in the blocks around lines 89 and 111-116). Ensure you propagate the same ctx so
cancellation, tracing and request-scoped values from *fasthttp.RequestCtx flow
through CompleteUserOAuthFlow and the store method calls.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1ed179c8-e44b-41c7-849c-6e3c2f069cf9

📥 Commits

Reviewing files that changed from the base of the PR and between 3b6be1e and 8b3deb7.

📒 Files selected for processing (29)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (5)
  • ui/lib/types/config.ts
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/clientconfig.go
  • framework/configstore/rdb_test.go
  • transports/bifrost-http/handlers/config.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • core/schemas/mcp.go
  • transports/bifrost-http/lib/ctx.go
  • core/schemas/context.go
  • core/schemas/bifrost.go
  • ui/lib/types/mcpSessions.ts
  • transports/bifrost-http/handlers/mcpserver.go
  • core/mcp/utils/utils.go
  • ui/app/workspace/config/views/mcpView.tsx
  • framework/oauth2/sync.go
  • core/schemas/oauth.go
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/lib/config_test.go
  • framework/configstore/tables/oauth.go
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • framework/configstore/store.go
  • framework/oauth2/main.go
  • framework/configstore/rdb.go

Comment thread framework/configstore/migrations.go
Comment thread transports/bifrost-http/handlers/oauth2.go Outdated
Comment thread transports/bifrost-http/handlers/oauth2.go Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 8b3deb7 to 0c200e7 Compare May 19, 2026 16:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
framework/configstore/migrations.go (1)

7972-7976: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the recreated session index scoped to session-mode rows.

This reintroduces the cross-mode collision the previous migration just fixed: any row with a populated session_id now participates in idx_oauth_user_tokens_session_mcp, even when its winning identity is user or vk.

Suggested fix
 				if err := tx.Exec(`
 					CREATE UNIQUE INDEX IF NOT EXISTS idx_oauth_user_tokens_session_mcp
 						ON oauth_user_tokens (session_id, mcp_client_id)
-						WHERE session_id IS NOT NULL AND session_id != ''
+						WHERE auth_mode = 'session' AND session_id IS NOT NULL AND session_id != ''
 				`).Error; err != nil {
 					return fmt.Errorf("create idx_oauth_user_tokens_session_mcp on session_id: %w", err)
 				}
🤖 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 `@framework/configstore/migrations.go` around lines 7972 - 7976, The recreated
unique index idx_oauth_user_tokens_session_mcp on oauth_user_tokens is too broad
and must be limited to session-mode rows; update the WHERE clause in the tx.Exec
that creates idx_oauth_user_tokens_session_mcp to include the session-mode
predicate (e.g. AND winning_identity = 'session') so only rows where
winning_identity == 'session' participate (keep the existing session_id IS NOT
NULL AND session_id != '' checks and add the winning_identity = 'session'
condition).
🧹 Nitpick comments (1)
transports/bifrost-http/lib/config.go (1)

3163-3168: 💤 Low value

Consider extracting the orphan retention duration to a named constant.

The 30*24*time.Hour magic number represents a policy decision (30-day orphan retention). Extracting it to a package-level constant would improve readability and make future adjustments easier to locate.

♻️ Suggested refactor
+// DefaultOAuthOrphanRetention is the default duration after which orphaned
+// per-user OAuth token rows are reaped by the sweep worker.
+const DefaultOAuthOrphanRetention = 30 * 24 * time.Hour
+
 // Start per-user OAuth sweep worker: expires stale pending flows and reaps
 // long-orphaned token rows. Orphan retention defaults to 30 days.
-config.OAuthSweepWorker = oauth2.NewPerUserOAuthSweepWorker(config.OAuthProvider, 30*24*time.Hour, logger)
+config.OAuthSweepWorker = oauth2.NewPerUserOAuthSweepWorker(config.OAuthProvider, DefaultOAuthOrphanRetention, logger)
🤖 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 `@transports/bifrost-http/lib/config.go` around lines 3163 - 3168, Extract the
30*24*time.Hour literal into a package-level constant (e.g., const
OAuthOrphanRetention = 30*24*time.Hour) and use that constant when calling
oauth2.NewPerUserOAuthSweepWorker in the config initialization (replace the
literal in the config.OAuthSweepWorker assignment); keep the constant near the
top of the file so the orphan retention policy is easy to find and adjust in the
future.
🤖 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.

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 7972-7976: The recreated unique index
idx_oauth_user_tokens_session_mcp on oauth_user_tokens is too broad and must be
limited to session-mode rows; update the WHERE clause in the tx.Exec that
creates idx_oauth_user_tokens_session_mcp to include the session-mode predicate
(e.g. AND winning_identity = 'session') so only rows where winning_identity ==
'session' participate (keep the existing session_id IS NOT NULL AND session_id
!= '' checks and add the winning_identity = 'session' condition).

---

Nitpick comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 3163-3168: Extract the 30*24*time.Hour literal into a
package-level constant (e.g., const OAuthOrphanRetention = 30*24*time.Hour) and
use that constant when calling oauth2.NewPerUserOAuthSweepWorker in the config
initialization (replace the literal in the config.OAuthSweepWorker assignment);
keep the constant near the top of the file so the orphan retention policy is
easy to find and adjust in the future.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ecdf56db-2ad9-4554-9829-52e3c2e2f0f7

📥 Commits

Reviewing files that changed from the base of the PR and between 8b3deb7 and 0c200e7.

📒 Files selected for processing (29)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (5)
  • ui/lib/types/config.ts
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/rdb_test.go
  • transports/bifrost-http/handlers/config.go
  • framework/configstore/clientconfig.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • core/schemas/mcp.go
  • ui/components/ui/alert.tsx
  • core/schemas/context.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/governance.go
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • core/schemas/bifrost.go
  • ui/lib/types/mcpSessions.ts
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • transports/bifrost-http/handlers/oauth2.go
  • ui/app/workspace/config/views/mcpView.tsx
  • transports/bifrost-http/handlers/mcpserver.go
  • core/mcp/utils/utils.go
  • framework/oauth2/sync.go
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • core/schemas/oauth.go
  • framework/configstore/tables/oauth.go
  • framework/configstore/store.go
  • framework/oauth2/main.go
  • framework/configstore/rdb.go

@roroghost17
roroghost17 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 0c200e7 to f649709 Compare May 19, 2026 18:46
@roroghost17 roroghost17 mentioned this pull request May 19, 2026
7 tasks

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
framework/configstore/migrations.go (2)

7972-7976: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the recreated session index scoped to auth_mode = 'session'.

The previous migration deliberately partitions every identity-domain unique index by auth_mode. Recreating idx_oauth_user_tokens_session_mcp without that predicate reopens cross-mode collisions for any row that carries a non-empty session_id outside session mode.

Suggested fix
 				if err := tx.Exec(`
 					CREATE UNIQUE INDEX IF NOT EXISTS idx_oauth_user_tokens_session_mcp
 						ON oauth_user_tokens (session_id, mcp_client_id)
-						WHERE session_id IS NOT NULL AND session_id != ''
+						WHERE auth_mode = 'session' AND session_id IS NOT NULL AND session_id != ''
 				`).Error; err != nil {
 					return fmt.Errorf("create idx_oauth_user_tokens_session_mcp on session_id: %w", err)
 				}
🤖 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 `@framework/configstore/migrations.go` around lines 7972 - 7976, Recreate the
unique index idx_oauth_user_tokens_session_mcp on table oauth_user_tokens so it
is still scoped to session-mode rows; update the tx.Exec call that creates
idx_oauth_user_tokens_session_mcp to include the predicate "WHERE auth_mode =
'session' AND session_id IS NOT NULL AND session_id != ''" (keeping
mcp_client_id and session_id as the indexed columns) so cross-mode collisions
are not reintroduced.

7920-7942: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Recreate the oauth_user_sessions.session_id index after the column swap.

After dropping idx_oauth_user_sessions_session_token_hash, this migration never creates the replacement index for session_id. AddColumn only adds the column, so lookups on the new identifier fall back to a full scan.

Suggested fix
 			if !mg.HasColumn(&tables.TableOauthUserSession{}, "session_id") {
 				if err := mg.AddColumn(&tables.TableOauthUserSession{}, "SessionID"); err != nil {
 					return fmt.Errorf("add session_id to oauth_user_sessions: %w", err)
 				}
 			}
+			if !mg.HasIndex(&tables.TableOauthUserSession{}, "idx_oauth_user_sessions_session_id") {
+				if err := mg.CreateIndex(&tables.TableOauthUserSession{}, "SessionID"); err != nil {
+					return fmt.Errorf("create session_id index on oauth_user_sessions: %w", err)
+				}
+			}
 			// The legacy session_token_hash column had a uniqueIndex declared
 			// via gorm tag; GORM names it something like
 			// "idx_oauth_user_sessions_session_token_hash". DROP COLUMN drops

Expected result: framework/configstore/tables/oauth.go shows SessionID is indexed, while this migration currently has no matching CreateIndex call.

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- oauth session schema ---'
rg -n -C2 'SessionID|session_id|session_token_hash' framework/configstore/tables/oauth.go

printf '\n%s\n' '--- migration index handling ---'
rg -n -C3 'replace_oauth_session_token_with_session_id|CreateIndex|idx_oauth_user_sessions_session_token_hash|session_id' framework/configstore/migrations.go
🤖 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 `@framework/configstore/migrations.go` around lines 7920 - 7942, The migration
adds SessionID to tables.TableOauthUserSession but never creates the
corresponding index, so after dropping
idx_oauth_user_sessions_session_token_hash you should create a new index on the
session_id column; update the migration (the block using
mg.HasColumn(&tables.TableOauthUserSession{}, "session_id"), mg.AddColumn, and
tx.Exec(...drop legacy index...)) to call the appropriate GORM index creation
(e.g., mg.CreateIndex or tx.Exec to CREATE INDEX CONCURRENTLY IF NOT EXISTS
idx_oauth_user_sessions_session_id ON oauth_user_sessions(session_id)) for
SessionID so lookups use the new index.
🤖 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/lib/types/mcpSessions.ts`:
- Around line 8-16: Update the comment above MCPSessionStatus to document flow
statuses as "pending" | "authorized" | "failed" | "expired" (not
"needs_reauth"), and change the MCPFlowDetail.status union type to "pending" |
"authorized" | "failed" | "expired" so flow statuses match the backend
TableOauthUserSession; leave token-only statuses (e.g., "needs_reauth" if used
by TableOauthUserToken) out of MCPFlowDetail.status and ensure
MCPSessionStatus/comment clearly separates token vs flow status sets.

---

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 7972-7976: Recreate the unique index
idx_oauth_user_tokens_session_mcp on table oauth_user_tokens so it is still
scoped to session-mode rows; update the tx.Exec call that creates
idx_oauth_user_tokens_session_mcp to include the predicate "WHERE auth_mode =
'session' AND session_id IS NOT NULL AND session_id != ''" (keeping
mcp_client_id and session_id as the indexed columns) so cross-mode collisions
are not reintroduced.
- Around line 7920-7942: The migration adds SessionID to
tables.TableOauthUserSession but never creates the corresponding index, so after
dropping idx_oauth_user_sessions_session_token_hash you should create a new
index on the session_id column; update the migration (the block using
mg.HasColumn(&tables.TableOauthUserSession{}, "session_id"), mg.AddColumn, and
tx.Exec(...drop legacy index...)) to call the appropriate GORM index creation
(e.g., mg.CreateIndex or tx.Exec to CREATE INDEX CONCURRENTLY IF NOT EXISTS
idx_oauth_user_sessions_session_id ON oauth_user_sessions(session_id)) for
SessionID so lookups use the new index.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f05b1fa2-ec9a-49b9-9d4b-adc17c36cfa1

📥 Commits

Reviewing files that changed from the base of the PR and between 0c200e7 and f649709.

📒 Files selected for processing (41)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/sidebar.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (8)
  • framework/configstore/tables/clientconfig.go
  • ui/lib/types/config.ts
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • framework/configstore/rdb_test.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/oauth2_consent.go
🚧 Files skipped from review as they are similar to previous changes (30)
  • ui/lib/store/apis/index.ts
  • core/schemas/mcp.go
  • ui/components/ui/alert.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/config/views/mcpView.tsx
  • core/schemas/bifrost.go
  • core/mcp/utils/utils.go
  • ui/lib/store/apis/baseApi.ts
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/governance.go
  • framework/oauth2/sync.go
  • core/schemas/context.go
  • ui/components/sidebar.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • transports/bifrost-http/handlers/mcpserver.go
  • framework/configstore/tables/oauth.go
  • core/schemas/oauth.go
  • ui/lib/store/apis/mcpSessionsApi.ts
  • transports/bifrost-http/handlers/oauth2.go
  • framework/oauth2/main.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • framework/configstore/rdb.go
  • framework/configstore/store.go

Comment thread ui/lib/types/mcpSessions.ts
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from f649709 to da09599 Compare May 19, 2026 19:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
framework/configstore/migrations.go (1)

7920-7933: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Recreate the dropped lookup index on oauth_user_sessions.session_id.

Line 7920 adds session_id, and Line 7930 drops the old session_token_hash index, but this migration never creates the replacement index on the new lookup column. AddColumn does not materialize struct-tag indexes, so upgraded databases lose indexed session_id lookups here.

#!/bin/bash
set -euo pipefail

printf '--- TableOauthUserSession schema ---\n'
rg -n -C3 'type TableOauthUserSession struct|SessionID' framework/configstore/tables/oauth.go

printf '\n--- MigrationReplaceOauthSessionTokenWithSessionID ---\n'
sed -n '7918,7980p' framework/configstore/migrations.go

Expected result: TableOauthUserSession.SessionID is indexed in the table schema, while this migration only adds the column and drops the legacy session_token_hash index without a matching CreateIndex(&tables.TableOauthUserSession{}, "SessionID").

🤖 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 `@framework/configstore/migrations.go` around lines 7920 - 7933, The migration
adds the session_id column on TableOauthUserSession but never recreates the
lookup index after dropping the old session_token_hash index; update the
migration (the block using mg.HasColumn(&tables.TableOauthUserSession{},
"session_id") / mg.AddColumn) to call
mg.CreateIndex(&tables.TableOauthUserSession{}, "SessionID") (or the equivalent
migrator.CreateIndex) after the DROP INDEX step and after confirming the column
exists so that SessionID is indexed for lookups; ensure you use the same
struct/field name TableOauthUserSession.SessionID and handle/return any error
from CreateIndex similarly to the existing error handling.
🤖 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.

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 7920-7933: The migration adds the session_id column on
TableOauthUserSession but never recreates the lookup index after dropping the
old session_token_hash index; update the migration (the block using
mg.HasColumn(&tables.TableOauthUserSession{}, "session_id") / mg.AddColumn) to
call mg.CreateIndex(&tables.TableOauthUserSession{}, "SessionID") (or the
equivalent migrator.CreateIndex) after the DROP INDEX step and after confirming
the column exists so that SessionID is indexed for lookups; ensure you use the
same struct/field name TableOauthUserSession.SessionID and handle/return any
error from CreateIndex similarly to the existing error handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95cf3fe6-782c-4508-a805-416c044f87de

📥 Commits

Reviewing files that changed from the base of the PR and between f649709 and da09599.

📒 Files selected for processing (41)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/sidebar.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (8)
  • transports/bifrost-http/handlers/oauth2_consent.go
  • framework/configstore/tables/clientconfig.go
  • ui/lib/types/config.ts
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • framework/configstore/rdb_test.go
✅ Files skipped from review due to trivial changes (1)
  • ui/components/ui/alert.tsx
🚧 Files skipped from review as they are similar to previous changes (31)
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/lib/store/apis/index.ts
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • transports/bifrost-http/server/server.go
  • ui/components/sidebar.tsx
  • core/schemas/mcp.go
  • core/schemas/context.go
  • transports/bifrost-http/lib/ctx.go
  • core/mcp/utils/utils.go
  • transports/bifrost-http/handlers/governance.go
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/lib/types/mcpSessions.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • transports/bifrost-http/handlers/mcpserver.go
  • core/schemas/bifrost.go
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • framework/configstore/tables/oauth.go
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/config/views/mcpView.tsx
  • framework/oauth2/sync.go
  • framework/configstore/store.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • ui/lib/store/apis/baseApi.ts
  • core/schemas/oauth.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • framework/oauth2/main.go
  • framework/configstore/rdb.go

@roroghost17
roroghost17 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from da09599 to 791502b Compare May 19, 2026 19:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
framework/configstore/migrations.go (1)

7918-7943: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Recreate the oauth_user_sessions.session_id index during the column swap.

This drops the old session_token_hash index but never adds the replacement on session_id, so upgraded databases lose indexed session lookups.

💡 Minimal fix
 			if mg.HasTable(&tables.TableOauthUserSession{}) {
 				if !mg.HasColumn(&tables.TableOauthUserSession{}, "session_id") {
 					if err := mg.AddColumn(&tables.TableOauthUserSession{}, "SessionID"); err != nil {
 						return fmt.Errorf("add session_id to oauth_user_sessions: %w", err)
 					}
 				}
+				if err := tx.Exec(`
+					CREATE INDEX IF NOT EXISTS idx_oauth_user_sessions_session_id
+						ON oauth_user_sessions (session_id)
+				`).Error; err != nil {
+					return fmt.Errorf("create session_id index on oauth_user_sessions: %w", err)
+				}
 				// The legacy session_token_hash column had a uniqueIndex declared
 				// via gorm tag; GORM names it something like
 				// "idx_oauth_user_sessions_session_token_hash". DROP COLUMN drops
🤖 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 `@framework/configstore/migrations.go` around lines 7918 - 7943, After adding
SessionID in the oauth_user_sessions migration block (the code that checks
mg.HasTable(&tables.TableOauthUserSession{}), mg.AddColumn, and drops the old
session_token_hash/index), recreate the replacement index on the new SessionID
column so session lookups remain indexed: add a step after adding the column
(and after dropping the old index/columns) to create an index on session_id (use
the same uniqueness semantics as the original uniqueIndex on
session_token_hash), e.g. execute a CREATE INDEX IF NOT EXISTS (or use the
migration helper equivalent) named similarly (e.g.
idx_oauth_user_sessions_session_id) via tx.Exec or the mg helper so upgraded
databases regain the index. Ensure you reference TableOauthUserSession/SessionID
when adding the index and handle errors consistently with the surrounding
fmt.Errorf style.
🧹 Nitpick comments (1)
ui/lib/store/apis/mcpSessionsApi.ts (1)

10-10: ⚡ Quick win

Use the @/lib/* alias for baseApi import consistency.

Line 10 should follow the UI alias convention instead of a relative path.

Suggested diff
-import { baseApi } from "./baseApi";
+import { baseApi } from "`@/lib/store/apis/baseApi`";
Based on learnings: "In the Bifrost codebase, prefer using the `@/lib` path alias for imports instead of relative paths from within the ui/lib directory."
🤖 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/lib/store/apis/mcpSessionsApi.ts` at line 10, The import in mcpSessionsApi
uses a relative path; update the import of baseApi in
ui/lib/store/apis/mcpSessionsApi.ts to use the project alias (change the import
that currently reads import { baseApi } from "./baseApi" to use the "`@/lib`"
alias, e.g. import { baseApi } from "`@/lib/baseApi`") so it follows the codebase
convention and stays consistent with other modules that reference baseApi.
🤖 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 `@framework/configstore/migrations.go`:
- Around line 7684-7703: The backfill SQL in migrations.go incorrectly sets ELSE
'vk' which classifies identity-less rows as vk; update both backfillSQL branches
(the ones referencing sessionCol and the else branch) to use ELSE NULL (unquoted
NULL) for auth_mode instead of 'vk' so rows with no user_id, virtual_key_id, or
session identifier are not treated as vk and can be removed by
migrationDropNonVKOauthUserRows; locate the string construction around
sessionCol, backfillSQL, and oauth_user_tokens and replace the final ELSE 'vk'
with ELSE NULL in both templated SQL blocks.

In `@ui/lib/store/apis/mcpSessionsApi.ts`:
- Around line 22-25: Replace the invalidatesTags approach in the MCP mutations
with an optimistic cache patch using onQueryStarted + dispatch(updateQueryData)
for the MCPSessions list: in the reauthMCPSession mutation (and the other
mutation at lines 28-31), implement onQueryStarted that calls patchResult =
dispatch(api.util.updateQueryData('getMCPSessions'/* or the actual query
endpoint name */, undefined, draft => { apply the same state change you expect
from the mutation to the draft })), then await the mutation, call
patchResult.undo() on error (or finalize commit on success). Ensure you
reference the MCPSessions query name used by the slice, perform rollback on
exception, and remove invalidatesTags from these mutations.

---

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 7918-7943: After adding SessionID in the oauth_user_sessions
migration block (the code that checks
mg.HasTable(&tables.TableOauthUserSession{}), mg.AddColumn, and drops the old
session_token_hash/index), recreate the replacement index on the new SessionID
column so session lookups remain indexed: add a step after adding the column
(and after dropping the old index/columns) to create an index on session_id (use
the same uniqueness semantics as the original uniqueIndex on
session_token_hash), e.g. execute a CREATE INDEX IF NOT EXISTS (or use the
migration helper equivalent) named similarly (e.g.
idx_oauth_user_sessions_session_id) via tx.Exec or the mg helper so upgraded
databases regain the index. Ensure you reference TableOauthUserSession/SessionID
when adding the index and handle errors consistently with the surrounding
fmt.Errorf style.

---

Nitpick comments:
In `@ui/lib/store/apis/mcpSessionsApi.ts`:
- Line 10: The import in mcpSessionsApi uses a relative path; update the import
of baseApi in ui/lib/store/apis/mcpSessionsApi.ts to use the project alias
(change the import that currently reads import { baseApi } from "./baseApi" to
use the "`@/lib`" alias, e.g. import { baseApi } from "`@/lib/baseApi`") so it
follows the codebase convention and stays consistent with other modules that
reference baseApi.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c6709b71-96ae-4508-93f3-336283c691db

📥 Commits

Reviewing files that changed from the base of the PR and between da09599 and 791502b.

📒 Files selected for processing (41)
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/sidebar.tsx
  • ui/components/ui/alert.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpSessionsApi.ts
  • ui/lib/types/config.ts
  • ui/lib/types/mcpSessions.ts
💤 Files with no reviewable changes (8)
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • framework/configstore/rdb_test.go
  • ui/lib/types/config.ts
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/config.go
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
🚧 Files skipped from review as they are similar to previous changes (28)
  • ui/lib/store/apis/index.ts
  • ui/app/workspace/mcp-sessions/oauth-callback/layout.tsx
  • ui/app/workspace/mcp-sessions/auth/layout.tsx
  • core/schemas/mcp.go
  • transports/bifrost-http/server/server.go
  • ui/components/sidebar.tsx
  • transports/bifrost-http/handlers/governance.go
  • core/schemas/context.go
  • ui/lib/types/mcpSessions.ts
  • core/schemas/bifrost.go
  • core/schemas/oauth.go
  • ui/components/ui/alert.tsx
  • transports/bifrost-http/lib/ctx.go
  • ui/lib/store/apis/baseApi.ts
  • core/mcp/utils/utils.go
  • ui/app/workspace/mcp-sessions/oauth-callback/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • framework/oauth2/sync.go
  • framework/configstore/tables/oauth.go
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • framework/configstore/store.go
  • framework/configstore/rdb.go
  • framework/oauth2/main.go

Comment thread framework/configstore/migrations.go
Comment thread ui/lib/store/apis/mcpSessionsApi.ts
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 791502b to bb4e5d4 Compare May 19, 2026 20:10
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch from 6d1fd81 to fc6475d Compare May 20, 2026 10:18
Comment thread transports/bifrost-http/handlers/mcp.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
core/schemas/context.go (1)

302-325: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Protect MCP auth identity source keys from restricted-write overrides.

Line 315, Line 318, and Line 321 read identity from context for OAuth lookup mode, but those keys are still writable when restricted writes are blocked because they are not in reservedKeys. This allows identity override before token resolution.

🔒 Suggested fix
 var reservedKeys = []any{
 	BifrostContextKeyVirtualKey,
+	BifrostContextKeyGovernanceVirtualKeyID,
+	BifrostContextKeyUserID,
+	BifrostContextKeyMCPSessionID,
 	BifrostContextKeyAPIKeyName,
 	BifrostContextKeyAPIKeyID,
 	BifrostContextKeyRequestID,
🤖 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/schemas/context.go` around lines 302 - 325, The MCPAuthMode() method
currently reads identity keys that can be overwritten by restricted-write code
paths; add BifrostContextKeyUserID, BifrostContextKeyGovernanceVirtualKeyID, and
BifrostContextKeyMCPSessionID to the set of reserved keys used by BifrostContext
(or the existing reservedKeys collection) so these context entries cannot be
modified by restricted writes, then ensure BifrostContext's Set/With methods
respect that reservedKeys collection so MCPAuthMode() always reads protected,
non-overridable identity values from the context.
🤖 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 `@core/schemas/bifrost.go`:
- Around line 178-186: Update the MCPAuthModeSession documentation and any
related help text to require server-minted or cryptographically high-entropy
session IDs rather than “client-issued opaque” values: change the comment for
MCPAuthModeSession to state that x-bf-mcp-session-id must be a server-generated,
unpredictable token (e.g., >=128 bits from a CSPRNG) and update any downstream
explanatory text that references x-bf-mcp-session-id to reflect this
server-minted/high-entropy requirement and guidance for generation/rotation.

---

Duplicate comments:
In `@core/schemas/context.go`:
- Around line 302-325: The MCPAuthMode() method currently reads identity keys
that can be overwritten by restricted-write code paths; add
BifrostContextKeyUserID, BifrostContextKeyGovernanceVirtualKeyID, and
BifrostContextKeyMCPSessionID to the set of reserved keys used by BifrostContext
(or the existing reservedKeys collection) so these context entries cannot be
modified by restricted writes, then ensure BifrostContext's Set/With methods
respect that reservedKeys collection so MCPAuthMode() always reads protected,
non-overridable identity values from the context.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b3b014c9-1f51-4f82-93d7-1c7c4f91ea38

📥 Commits

Reviewing files that changed from the base of the PR and between 26fbd91 and fc6475d.

📒 Files selected for processing (24)
  • core/mcp/clientmanager.go
  • core/mcp/codemode/starlark/listfiles.go
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/oauth.go
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/rdb_test.go
  • framework/configstore/store.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/tables/oauth.go
  • framework/oauth2/main.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
💤 Files with no reviewable changes (16)
  • transports/bifrost-http/handlers/mcp.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • framework/configstore/rdb_test.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/oauth2_consent.go
  • framework/oauth2/sync.go
  • transports/bifrost-http/handlers/oauth2.go
  • framework/configstore/store.go
  • transports/bifrost-http/handlers/mcpserver.go
  • framework/configstore/tables/oauth.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • framework/oauth2/main.go
  • transports/bifrost-http/handlers/config.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
✅ Files skipped from review due to trivial changes (1)
  • core/mcp/codemode/starlark/listfiles.go

Comment thread core/schemas/bifrost.go

akshaydeo commented May 20, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • May 20, 11:01 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 20, 11:01 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit 2c6647e into dev May 20, 2026
15 of 16 checks passed
@akshaydeo
akshaydeo deleted the 05-18-refactor_mcp_per_user_oauth_flow_refactor branch May 20, 2026 11:01
@akshaydeo akshaydeo mentioned this pull request May 20, 2026
18 tasks
akshaydeo added a commit that referenced this pull request May 20, 2026
## Summary

This PR cuts the `v1.5.11` / `v1.3.11` release across core, framework, and all plugins, and introduces a new Claude skill (`release-checklist`) for pre-release migration safety auditing.

## Changes

- **`release-checklist` skill** — Adds `.claude/skills/release-checklist/SKILL.md`, a read-only pre-release audit tool that scans Go-defined database migrations changed in a release for high-scale deadlock/lock-contention risks and boot-time-blocking operations. It produces a structured `PASS`/`WARN`/`FAIL` report with a concrete remediation plan per finding. The skill is designed to grow via an extensible Checks Registry.
- **Version bumps** — `core` → `1.5.11`, `framework` → `1.3.11`, `transports` → `1.5.3`, `plugins/governance` → `1.5.11`, `plugins/logging` → `1.5.11`, `plugins/semanticcache` → `1.5.11`, `plugins/otel` → `1.2.11`, `plugins/maxim` → `1.6.11`, `plugins/prompts` → `1.0.11`, and remaining plugins bumped accordingly.
- **Changelogs populated** — All per-package changelogs updated with the full set of features and fixes shipping in this release.

Key highlights in this release:
- Temporary access tokens for scoped, time-limited API access
- MCP per-user OAuth flow refactor
- Bedrock Mantle inference engine support
- Azure Realtime provider with enriched session tracking
- Direct access control (DAC) and virtual key rotation
- Cluster-aware log metadata and per-node usage aggregation
- Feature flag framework
- Config-hash-based file value override of DB on restart
- Semantic cache plugin rewrite
- Numerous streaming stability, Bedrock, Anthropic, and Gemini fixes
- AWS SDK and dependency security updates

## Type of change

- [ ] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [x] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

```sh
# Verify version files reflect the new release
cat core/version          # expect 1.5.11
cat framework/version     # expect 1.3.11
cat transports/version    # expect 1.5.3

# Core/Transports
go test ./...
```

To exercise the new `release-checklist` skill, invoke it via Claude with:
```
/release-checklist origin/dev...HEAD
```
Expected output: a structured report with `PASS`/`WARN`/`FAIL` per check and a Remediation Plan table for any findings.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

#3603, #3565, #3489, #3334, #3335, #3435, #3554, #3590, #3444, #3198, #3581, #3610, #3599, #3567, #3382, #3461 and others listed in the changelogs.

## Security considerations

- AWS SDK and dependency security updates are included (#3461).
- `FullyRedacted()` for proxy passwords and `MarshalForStorage()` for `ProxyConfig` prevent partial secret leakage in API responses (#3445).
- The `release-checklist` skill is strictly read-only and never modifies files.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request May 20, 2026
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.

Files API Support

3 participants