Skip to content

feat: add mcp per-user headers auth flow ui wiring - #3704

Merged
Pratham-Mishra04 merged 1 commit into
devfrom
05-22-feat_added_ui_for_per_user_headers_mcp_auth
May 27, 2026
Merged

feat: add mcp per-user headers auth flow ui wiring#3704
Pratham-Mishra04 merged 1 commit into
devfrom
05-22-feat_added_ui_for_per_user_headers_mcp_auth

Conversation

@Pratham-Mishra04

Copy link
Copy Markdown
Collaborator

Summary

Adds a per-user headers authentication type for MCP clients, mirroring the existing per-user OAuth flow. Admins declare a set of required header key names on the MCP client config; each end user then submits their own values (API keys, tokens, etc.) via a dedicated auth landing page. The backend verifies upstream connectivity and stores credentials encrypted per-user. This enables MCP servers that require caller-specific API keys without sharing a single set of credentials across all users.

Changes

  • New per_user_headers auth type added to MCPAuthType, MCPClientConfig, CreateMCPClientRequest, and UpdateMCPClientRequest. Admins declare required header key names via per_user_header_keys; user-submitted values are never stored on the client config.
  • MCPHeadersAuthorizer dialog (mcpHeadersAuthorizer.tsx): mirrors OAuth2Authorizer's state machine (confirm → input → testing → success/failed). On Create, the admin supplies sample values; the server verifies upstream, discovers tools, and persists atomically in a single POST. Nothing is committed if the user cancels or verification fails.
  • HeadersForm component (headersForm.tsx): reusable secret-input form used by both the admin test panel and the end-user submission page. Renders one password input per required key, supports show/hide toggle, previously-submitted key badges, and optional read-only display of admin-static header names.
  • Auth landing page (mcp-sessions/auth/page.tsx): split into OAuthAuthView and HeadersAuthView. The kind=headers query param routes to the headers branch. HeadersAuthView fetches the pending flow row and schema, renders HeadersForm, and PUTs values back to the flow endpoint. Handles 401/404/410 error states and a post-submit success card.
  • Sessions table (sessionsTable.tsx): adds a Type column with OAuth, Headers, and Pending badges. Adds needs_update status badge for header rows whose schema has changed. Header rows show an "Edit values" / "Update values" action instead of "Re-authenticate". Reconnect is disabled for all per-user auth types (isPerUserAuth replaces isPerUserOAuth). Header rows display in the access token expiry column.
  • RTK Query API (mcpPerUserHeadersApi.ts): getMCPPerUserHeadersFlow, submitMCPPerUserHeadersFlow, and revokeMCPPerUserHeaders endpoints targeting /api/mcp/per-user-headers/flows/{id}.
  • Type definitions (mcpPerUserHeaders.ts, mcpSessions.ts): MCPHeadersFlowDetail, MCPPerUserHeadersSubmitRequest/Response, MCPHeadersUserCredentialStatus, MCPSessionKind extended with "header", MCPSessionStatus extended with "needs_update", and auth_kind discriminator on MCPSessionRow.
  • MCP clients table: per_user_headers auth type renders as "Per-user Headers" in the auth type display column.
  • Minor copy fix: "MCP tool groups" heading capitalised to "MCP Tool Groups".

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

cd ui
pnpm i
pnpm build
pnpm test
  1. Navigate to MCP Registry → Add Client.
  2. Select Per-User Headers as the auth type.
  3. Enter comma-separated header key names (e.g. X-API-Key, X-Tenant-ID) in the Required Headers textarea.
  4. Click Create — the MCPHeadersAuthorizer dialog opens.
  5. Enter sample values and click Run Test. Verify the server connects, discovers tools, and the client appears in the registry.
  6. As an end user, trigger a tool call that requires per-user headers. Confirm the auth landing page (/workspace/mcp-sessions/auth?flow=...&kind=headers) renders the submission form with the correct required keys.
  7. Submit values and confirm the sessions table shows a Headers type row with Active status.
  8. In the admin, change the per_user_header_keys schema. Confirm the existing credential row flips to Needs update and the "Update values" action appears.

Screenshots/Recordings

Add before/after screenshots of the MCP client form auth type selector, the MCPHeadersAuthorizer dialog, the auth landing page headers form, and the sessions table Type/Status columns.

Breaking changes

  • No

isPerUserOAuth prop on MCPClientActionsMenu renamed to isPerUserAuth — internal component only, no external API surface affected.

Related issues

Security considerations

  • Per-user header values (API keys, tokens) are submitted directly to the backend and stored encrypted in the credential store. Values are never round-tripped to the client after submission.
  • Admin sample values supplied during the create-time verification step are discarded after the upstream connectivity check and are never persisted.
  • The auth landing page accepts a temp token in the URL fragment (#t=) to bind anonymous browser visitors to a specific flow ID without requiring a dashboard session.
  • Extra keys in user submissions are dropped server-side against the live PerUserHeaderKeys schema, preventing stale UI submissions from persisting deprecated keys.

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

@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.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Pratham-Mishra04, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 17 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7c71a0c3-26c1-44f6-856c-53b1bac1ea34

📥 Commits

Reviewing files that changed from the base of the PR and between dfa9a71 and e093972.

📒 Files selected for processing (16)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
  • ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/headersForm.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpApi.ts
  • ui/lib/store/apis/mcpPerUserHeadersApi.ts
  • ui/lib/types/mcp.ts
  • ui/lib/types/mcpPerUserHeaders.ts
  • ui/lib/types/mcpSessions.ts
  • ui/lib/types/schemas.ts
📝 Walkthrough

Walkthrough

Adds per-user header credentials to MCP: new types and RTK endpoints, a reusable HeadersForm, an MCPHeadersAuthorizer dialog, client create/edit wiring that stages verification, clients/sessions UI updates, auth-page routing for header submission flows, plus a small UI text fix.

Changes

Per-User Headers Authentication

Layer / File(s) Summary
Type definitions and RTK Query endpoints
ui/lib/types/mcp.ts, ui/lib/types/mcpPerUserHeaders.ts, ui/lib/types/mcpSessions.ts, ui/lib/store/apis/baseApi.ts, ui/lib/store/apis/mcpPerUserHeadersApi.ts, ui/lib/store/apis/index.ts
MCPAuthType adds per_user_headers; new types model header flow detail and session kinds/statuses; added RTK Query endpoints to fetch flows, submit header values, and revoke credentials; cache tag registration and invalidations updated.
Reusable HeadersForm component
ui/components/headersForm.tsx
New form rendering secret inputs per required key with reveal toggles, previously-submitted indicators, optional admin-static headers block, initial value construction and schema-resync helpers, and submit/test/cancel gating.
MCPHeadersAuthorizer dialog component
ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
Multi-step dialog (confirm → input → testing → success/failed) that renders HeadersForm, injects user_headers into the provided payload for verification, handles async cancellation and errors, and prevents dismissal during testing.
MCPClientForm per-user headers flow
ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
Adds Per-User Headers auth option, textarea to declare required header key names, optional static headers panel, submission validation requiring ≥1 key, staged payload with per_user_header_keys and headers, and opens MCPHeadersAuthorizer for admin verification.
MCPClientSheet edit UI
ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
Client edit sheet supports editing required headers for per_user_headers, syncs textarea state, validates presence on submit, and includes per_user_header_keys in update payload.
MCPClientsTable per-user auth display
ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
Detects per-user auth for per_user_oauth and per_user_headers, updates auth type label to "Per-user Headers", and disables reconnect for per-user auth clients.
Auth page headers flow routing
ui/app/workspace/mcp-sessions/auth/page.tsx
MCPSessions auth page reads URL flow and kind; when kind === "headers" renders HeadersAuthView which loads flow details, wires schema into HeadersForm, submits values via mutation, handles submitted state and errors, and shows binding/expiry metadata.
Sessions table credential type display and actions
ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
Adds a "Type" column with TypeBadge for Pending/OAuth/Headers, extends StatusBadge with needs_update, routes completion/edit actions and URLs for header flows, adds "Edit values" for header rows, and returns “—” for access expiry on header rows.
mcpApi cache merge update
ui/lib/store/apis/mcpApi.ts
Copies per_user_header_keys into matched client config during update cache merge and removes an unused import symbol.
Schema validation
ui/lib/types/schemas.ts
Adds optional per_user_header_keys to mcpClientUpdateSchema with duplicate-entry rejection.
Capitalization fix
ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
Updates heading text from "MCP tool groups" to "MCP Tool Groups".

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • maximhq/bifrost#3494: Also touches MCPToolGroups header markup and adjusts related UI class/markup.

Suggested reviewers

  • akshaydeo
  • danpiths
  • roroghost17

Poem

A rabbit fiddles with headers light,
Keys and secrets tucked in tight,
Forms and dialogs hum and sing,
Sessions learn their new credential ring,
Admins smile — the flow takes flight. 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main feature addition: per-user headers authentication flow UI integration for MCP clients.
Description check ✅ Passed The PR description is comprehensive, covering summary, changes, type of change, affected areas, testing steps, security considerations, and checklist completion.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-22-feat_added_ui_for_per_user_headers_mcp_auth

Comment @coderabbitai help to get the list of available commands and usage tips.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from bb1238f to a605ec2 Compare May 23, 2026 15:59
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from b45e15d to 8737c78 Compare May 23, 2026 15:59
@stepsecurity-app

Copy link
Copy Markdown
Contributor

Security Policy Alert: Secret Policy Violation

This workflow run has been blocked by StepSecurity's secrets policy because it accesses secrets and the workflow file differs from the default branch.

To approve this workflow, please add the workflows-approved label to this PR.

Note: The label must be added by someone other than the PR author (Pratham-Mishra04) or automation bots to ensure proper security review.

After the label is added, you can re-run the blocked workflow to proceed.

This workflow will be automatically approved once merged into the default branch.

For more information, see StepSecurity's Secret Exfiltration Policy documentation.

@greptile-apps

greptile-apps Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge; the implementation is consistent with the existing OAuth flow patterns and there are no data-loss or security regressions.

The change is a large but well-structured UI feature addition. The one gap noted — HeadersAuthView not checking detail.status before rendering the form — degrades UX only if the backend returns HTTP 200 for a completed/expired flow (rather than 404/410 as the error-handling paths assume). No auth bypass, credential exposure, or functional breakage was found.

ui/app/workspace/mcp-sessions/auth/page.tsx — the new HeadersAuthView component is missing the non-pending flow guard that OAuthAuthView has.

Important Files Changed

Filename Overview
ui/app/workspace/mcp-sessions/auth/page.tsx Splits the auth landing page into OAuthAuthView and HeadersAuthView routed on ?kind=headers. Most of the logic is refactored indentation/rename only. One gap: HeadersAuthView doesn't check detail.status !== 'pending' the way OAuthAuthView does.
ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx New dialog component mirroring OAuth2Authorizer; state machine (confirm → input → testing → success/failed) and cancel-guard via cancelledRef are correctly implemented.
ui/components/headersForm.tsx New reusable secret-input form; buildSubmissionValues omit-if-blank behaviour, schema-sync via useEffect, and canSubmit guards are all correct.
ui/app/workspace/mcp-sessions/views/sessionsTable.tsx Adds Type column, needs_update badge, header row actions (Edit/Update values), pendingActionRowId for per-row spinner, and header-specific revoke dialog copy. Changes are consistent and correct.
ui/app/workspace/mcp-registry/views/mcpClientForm.tsx Adds per-user-headers auth type with required-key Textarea and MCPHeadersAuthorizer dialog; mirrors the per-user OAuth flow correctly.
ui/lib/store/apis/mcpPerUserHeadersApi.ts New RTK Query API file with GET/PUT/DELETE endpoints; tag invalidation and providesTags look correct.

Reviews (13): Last reviewed commit: "feat: added ui for per user headers mcp ..." | Re-trigger Greptile

Comment thread ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx Outdated
Comment thread ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from a605ec2 to 1435f09 Compare May 24, 2026 19:55
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from 8737c78 to 70c0449 Compare May 24, 2026 19:55

@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: 6

🧹 Nitpick comments (2)
ui/lib/types/mcpPerUserHeaders.ts (1)

7-13: ⚡ Quick win

Use @/lib/* aliases instead of relative imports in UI TS files.

Please switch these imports to the project alias style for consistency with the rest of ui/ code.

Based on learnings, in the Bifrost UI codebase, prefer using the @/lib path alias for imports instead of relative paths in ui TypeScript files.

🤖 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/types/mcpPerUserHeaders.ts` around lines 7 - 13, Replace the relative
imports with the project path alias: change the import of
MCPHeadersUserCredentialStatus and the grouped imports (AuthMode,
MCPClientSummary, UserSummary, VirtualKeySummary) to use the '`@/lib/`...' alias
(e.g., import MCPHeadersUserCredentialStatus from '`@/lib/mcp`' and import {
AuthMode, MCPClientSummary, UserSummary, VirtualKeySummary } from
'`@/lib/mcpSessions`') so the file uses the same `@/lib` alias style as other UI
TypeScript files.
ui/app/workspace/mcp-sessions/auth/page.tsx (1)

373-413: 💤 Low value

Consider unifying HeadersBindingValue and BindingValue to reduce duplication.

These two components (lines 373-413 and 470-510) share nearly identical logic, differing only in their prop types (MCPHeadersFlowDetail vs MCPFlowDetail). If both types share the same shape for flow_mode, user_id, user, virtual_key, and session_id, you could create a shared interface or use a union type to avoid ~40 lines of duplication.

♻️ Example approach
// In a shared types file or at the top of this file
type FlowBindingInfo = Pick<
  MCPFlowDetail | MCPHeadersFlowDetail,
  'flow_mode' | 'user_id' | 'user' | 'virtual_key' | 'session_id'
>;

// Single component handles both flow types
function BindingValue({ flow }: { flow: FlowBindingInfo }) {
  // ... existing logic unchanged
}
🤖 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/auth/page.tsx` around lines 373 - 413, The two
components HeadersBindingValue and BindingValue duplicate the same rendering
logic; consolidate them by introducing a shared type (e.g., FlowBindingInfo)
that picks the common fields from MCPHeadersFlowDetail and MCPFlowDetail
(flow_mode, user_id, user, virtual_key, session_id) and then replace both
components with a single component BindingValue({ flow }: { flow:
FlowBindingInfo }) that contains the existing conditional rendering (user, vk,
session, Unknown). Update callers to pass their existing flow objects (which are
compatible with the picked fields) and remove the duplicated HeadersBindingValue
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx`:
- Around line 187-189: The Retry Button rendered in the mcpHeadersAuthorizer
component is missing a data-testid; update the Button element inside the
component where onClick={handleRetry} (the Retry button) to include a
data-testid attribute (e.g., data-testid="mcp-headers-retry-button" or similar
consistent name used elsewhere) so automated tests can target it; ensure the
attribute is added to the Button JSX with the chosen stable identifier.
- Around line 1-17: Rename the React component file from
mcpHeadersAuthorizer.tsx to PascalCase (e.g., MCPHeadersAuthorizer.tsx), update
the default/named component export to match the filename (export default
function MCPHeadersAuthorizer or export const MCPHeadersAuthorizer), and update
all imports that reference this file throughout the codebase so they use the new
filename; ensure any references in tests, routes, or parent components that
import HeadersForm or useCreateMCPClientMutation continue to work after the
rename.

In `@ui/components/headersForm.tsx`:
- Around line 163-171: Add a data-testid attribute to the reveal/hide button so
E2E tests can target it: update the button element (the one using setReveal and
rendering Eye/EyeOff based on isRevealed) to include a descriptive data-testid
like data-testid={`header-value-reveal-${key}`} or similar; ensure the value
uses the unique key so tests can differentiate buttons for different headers and
keep the existing onClick, aria-label, and tabIndex intact.
- Around line 163-169: The reveal toggle button is currently removed from
keyboard navigation via tabIndex={-1}; update the button in the headersForm
component (the button using setReveal, key and isRevealed) to be
keyboard-focusable by removing tabIndex or setting it to 0, and keep the
existing aria-label so screen readers still get the correct "Show value" / "Hide
value" text; ensure the onClick behavior remains and that keyboard users can
activate it with Enter/Space.
- Around line 25-63: Replace the ad-hoc allFilled logic in the HeadersForm
component with a Zod schema that validates each required key as a non-empty
string and provides per-field error messages; create a schema (e.g.,
headersSchema) that builds an object with keys matching requiredKeys (and
optional keys for adminHeaderKeys/initialValues where necessary) and message
text like "Header '<name>' is required" for empty values, then wire that schema
into the form via the form library's resolver (or zod.parse on submit) in the
HeadersForm component so errors populate field-level messages shown next to each
input (update any references to allFilled / submit gating to rely on
formState.isValid or resolver errors instead); ensure initialValues is used as
defaultValues in the form setup so validation runs against that shape.

In `@ui/lib/store/apis/mcpPerUserHeadersApi.ts`:
- Around line 35-38: Replace the current use of invalidatesTags in the mutation
endpoints that return tags ["MCPSessions", { type:
"MCPPerUserHeaderCredentials", id: arg.flowId }] with an optimistic cache patch
using onQueryStarted and the Api.util.updateQueryData helpers: in the mutation
endpoint functions in ui/lib/store/apis/mcpPerUserHeadersApi.ts, add an
onQueryStarted handler that immediately updates the relevant cached queries
(e.g., the MCPSessions list and the MCPPerUserHeaderCredentials entry keyed by
flowId) using dispatch(api.util.updateQueryData), capture the patch undo
function, and roll it back on error (await queryFulfilled; catch -> undo). Do
this for both occurrences currently using invalidatesTags (the block producing
the tag with arg.flowId and the other at the referenced line) so mutations
optimistically update the cache and revert on failure.

---

Nitpick comments:
In `@ui/app/workspace/mcp-sessions/auth/page.tsx`:
- Around line 373-413: The two components HeadersBindingValue and BindingValue
duplicate the same rendering logic; consolidate them by introducing a shared
type (e.g., FlowBindingInfo) that picks the common fields from
MCPHeadersFlowDetail and MCPFlowDetail (flow_mode, user_id, user, virtual_key,
session_id) and then replace both components with a single component
BindingValue({ flow }: { flow: FlowBindingInfo }) that contains the existing
conditional rendering (user, vk, session, Unknown). Update callers to pass their
existing flow objects (which are compatible with the picked fields) and remove
the duplicated HeadersBindingValue implementation.

In `@ui/lib/types/mcpPerUserHeaders.ts`:
- Around line 7-13: Replace the relative imports with the project path alias:
change the import of MCPHeadersUserCredentialStatus and the grouped imports
(AuthMode, MCPClientSummary, UserSummary, VirtualKeySummary) to use the
'`@/lib/`...' alias (e.g., import MCPHeadersUserCredentialStatus from '`@/lib/mcp`'
and import { AuthMode, MCPClientSummary, UserSummary, VirtualKeySummary } from
'`@/lib/mcpSessions`') so the file uses the same `@/lib` alias style as other UI
TypeScript files.
🪄 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: 4219bdbd-37d2-44d2-80fb-e73a1c2b0f7a

📥 Commits

Reviewing files that changed from the base of the PR and between 1435f09 and 70c0449.

📒 Files selected for processing (13)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
  • ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/headersForm.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpPerUserHeadersApi.ts
  • ui/lib/types/mcp.ts
  • ui/lib/types/mcpPerUserHeaders.ts
  • ui/lib/types/mcpSessions.ts

Comment thread ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
Comment thread ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx Outdated
Comment thread ui/components/headersForm.tsx
Comment thread ui/components/headersForm.tsx
Comment thread ui/components/headersForm.tsx
Comment thread ui/lib/store/apis/mcpPerUserHeadersApi.ts
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from 1435f09 to 0cc89eb Compare May 24, 2026 21:27
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from 70c0449 to cf07e4e Compare May 24, 2026 21:27
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from 0cc89eb to cb69509 Compare May 25, 2026 06:27
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from cf07e4e to 522cf0a Compare May 25, 2026 06:27
@coderabbitai
coderabbitai Bot requested a review from roroghost17 May 25, 2026 06:28

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/app/workspace/mcp-registry/views/mcpClientForm.tsx`:
- Around line 191-195: The headers validation currently runs only when authType
=== "headers" but the per-user flow can pass data.headers into payload.headers;
update any conditional checks that call headersValidationError (and any logic
gating opening MCPHeadersAuthorizer) to include authType === "per_user_headers"
as well (e.g., change checks from authType === "headers" to authType ===
"headers" || authType === "per_user_headers"), ensuring data.headers is
validated before setting payload.headers or per_user_header_keys and before
launching MCPHeadersAuthorizer; reference headersValidationError, authType,
data.headers, perUserHeaderKeys, payload.headers, and MCPHeadersAuthorizer to
locate the affected logic.

In `@ui/app/workspace/mcp-sessions/auth/page.tsx`:
- Around line 267-297: The error branch in the isError || !detail block (around
HeadersAuthView rendering) must explicitly handle HTTP 403 like the OAuth branch
does: detect status === 403 and return the same ownership/RBAC card component
used by the OAuth flow (instead of falling through to the generic error view).
Update the conditional in page.tsx to add a status === 403 case in the same
block that checks status === 401/404/410, render the exact component used by the
OAuth path (the ownership/RBAC card), and ensure that component is imported
where HeadersAuthView and InvalidLinkView are used so enterprise RBAC
short-circuits show the dedicated card rather than a generic load failure.

In `@ui/app/workspace/mcp-sessions/views/sessionsTable.tsx`:
- Around line 322-353: The revoke flow uses generic OAuth wording but for header
rows (row.kind === "header" or check row.auth_kind) you must present
header-specific title/description/success text; update the revoke handler
invoked by the mcp-session-revoke-menu-item (onRevoke) to branch on
row.kind/row.auth_kind and supply different dialog/toast copy for "header"
(e.g., explain values must be resubmitted, no upstream OAuth token) vs OAuth
rows (existing wording about revoking upstream token and re-authentication).
Ensure the DropdownMenuItem onSelect still calls onRevoke but pass the row or
its kind/auth_kind so the dialog/toast builders can pick the correct strings and
update any success message shown after revoke accordingly.

In `@ui/components/headersForm.tsx`:
- Around line 97-106: The submit and test handlers (handleSubmit and handleTest)
lack an explicit guard for the case where there are no required header keys
(requiredKeys.length === 0), allowing actions to run even when schema is empty;
update handleSubmit, handleTest and the similar handler around lines 191-197 to
return early if requiredKeys is missing or empty (e.g., check requiredKeys &&
requiredKeys.length > 0) in addition to the existing allFilled and busy checks
so neither onSubmit nor onTest is invoked when no required header keys exist.
🪄 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: 901a2ab0-1efe-4401-af92-898a96cb3474

📥 Commits

Reviewing files that changed from the base of the PR and between 70c0449 and 522cf0a.

📒 Files selected for processing (13)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
  • ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/headersForm.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpPerUserHeadersApi.ts
  • ui/lib/types/mcp.ts
  • ui/lib/types/mcpPerUserHeaders.ts
  • ui/lib/types/mcpSessions.ts
✅ Files skipped from review due to trivial changes (3)
  • ui/lib/store/apis/index.ts
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/lib/store/apis/baseApi.ts

Comment thread ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
Comment thread ui/app/workspace/mcp-sessions/auth/page.tsx Outdated
Comment thread ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
Comment thread ui/components/headersForm.tsx
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from cb69509 to c7d9551 Compare May 25, 2026 07:12
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from 522cf0a to 1c9aa14 Compare May 25, 2026 07:12
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from 2d84d56 to a396bc2 Compare May 25, 2026 13: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

Caution

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

⚠️ Outside diff range comments (1)
ui/app/workspace/mcp-sessions/views/sessionsTable.tsx (1)

301-315: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Per-row pending state is computed but global disabling still blocks all rows.

busy currently uses global mutation flags (reauthing || revoking), so triggering one row disables actions for every row. Since isPendingRow is already tracked, scope busy to the active row to match the intended per-row behavior.

💡 Suggested fix
 function RowActions({ row, reauthing, revoking, isPendingRow, onReauth, onRevoke }: RowActionsProps) {
-	const busy = reauthing || revoking;
+	const busy = isPendingRow && (reauthing || revoking);
 	return (
 		<DropdownMenu>

Also applies to: 355-370, 388-403

🤖 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/views/sessionsTable.tsx` around lines 301 -
315, The per-row actions are being globally disabled because busy is computed
from global flags (reauthing || revoking); change the busy calculation in
RowActions (and the other similar blocks) to scope it to the current row by
combining isPendingRow with the global flags (e.g., busy = isPendingRow &&
(reauthing || revoking) or busy = (reauthing && isPendingRow) || (revoking &&
isPendingRow)), so only the active row becomes disabled/uses the loader; update
all occurrences that compute busy (including the blocks around the other
instances noted) so the Button disabled/loader logic uses the per-row busy
instead of the global flags alone.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx`:
- Around line 597-603: The TooltipTrigger currently uses asChild with a raw
<Info> icon which is not keyboard-focusable or testable; wrap the icon in a
focusable element (e.g., a button or span with tabIndex={0}) used as the child
of TooltipTrigger (the TooltipTrigger/TooltipContent block around Info) and add
a data-testid attribute (e.g., data-testid="required-headers-tooltip-trigger")
to that focusable element so it is keyboard-focusable and selectable in E2E
tests; update any relevant ARIA attributes (aria-label or title) on that element
to preserve accessibility.

In `@ui/lib/types/schemas.ts`:
- Around line 978-987: The refine on the per_user_header_keys zod schema
currently compares raw header strings so case variants like "X-API-Key" and
"x-api-key" pass as distinct; update the predicate in
per_user_header_keys.refine to normalize each header (e.g., trim and
toLowerCase) before creating the Set and checking uniqueness, preserving the
existing optional handling and error message "Duplicate header names are not
allowed".

---

Outside diff comments:
In `@ui/app/workspace/mcp-sessions/views/sessionsTable.tsx`:
- Around line 301-315: The per-row actions are being globally disabled because
busy is computed from global flags (reauthing || revoking); change the busy
calculation in RowActions (and the other similar blocks) to scope it to the
current row by combining isPendingRow with the global flags (e.g., busy =
isPendingRow && (reauthing || revoking) or busy = (reauthing && isPendingRow) ||
(revoking && isPendingRow)), so only the active row becomes disabled/uses the
loader; update all occurrences that compute busy (including the blocks around
the other instances noted) so the Button disabled/loader logic uses the per-row
busy instead of the global flags alone.
🪄 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: 2136f7e9-9ca5-4cac-8814-430fc1d1abc1

📥 Commits

Reviewing files that changed from the base of the PR and between 2d84d56 and a396bc2.

📒 Files selected for processing (16)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
  • ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/headersForm.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpApi.ts
  • ui/lib/store/apis/mcpPerUserHeadersApi.ts
  • ui/lib/types/mcp.ts
  • ui/lib/types/mcpPerUserHeaders.ts
  • ui/lib/types/mcpSessions.ts
  • ui/lib/types/schemas.ts
✅ Files skipped from review due to trivial changes (2)
  • ui/lib/store/apis/mcpApi.ts
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx

Comment thread ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
Comment thread ui/lib/types/schemas.ts
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from a396bc2 to 311e88c Compare May 25, 2026 16:03
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 25, 2026
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from 7bb0272 to d389c49 Compare May 26, 2026 18:29
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from 311e88c to 2a4a450 Compare May 26, 2026 18:29

@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.

Caution

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

⚠️ Outside diff range comments (1)
ui/app/workspace/mcp-registry/views/mcpClientForm.tsx (1)

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

Block parent sheet dismissal during active per-user headers flow.

At Line 244, onOpenChange only gates on !oauthFlow; when headersFlow is active, the sheet can still close and interrupt the in-progress per-user headers authorizer flow.

💡 Suggested fix
- <Sheet open={open} onOpenChange={(open) => !open && !oauthFlow && onClose()}>
+ <Sheet open={open} onOpenChange={(open) => !open && !oauthFlow && !headersFlow && onClose()}>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/app/workspace/mcp-registry/views/mcpClientForm.tsx` at line 244, The
Sheet's onOpenChange currently prevents closing only when oauthFlow is active;
update the handler used where Sheet is rendered (the onOpenChange prop) to also
block dismissal while headersFlow is active by gating against both flags (e.g.,
only call onClose() when !oauthFlow && !headersFlow), so the sheet cannot close
during an in-progress per-user headers authorizer flow.
♻️ Duplicate comments (3)
ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx (1)

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

Guard async completion with a per-open session token, not only cancelledRef.

Line 54 resets cancelledRef on reopen, so an older in-flight request can still complete into the new dialog session and incorrectly call onSuccess/onError.

Proposed fix
 	const cancelledRef = useRef(false);
+	const sessionRef = useRef(0);

 	useEffect(() => {
 		if (open) {
+			sessionRef.current += 1;
 			setStatus("confirm");
 			setErrorMessage(null);
 			cancelledRef.current = false;
 		}
 	}, [open]);

 	const handleRunTest = async (values: Record<string, string>) => {
 		if (cancelledRef.current) return;
+		const runSession = sessionRef.current;
 		setStatus("testing");
 		try {
 			await createMCPClient({ ...payload, user_headers: values }).unwrap();
-			if (cancelledRef.current) return;
+			if (cancelledRef.current || runSession !== sessionRef.current) return;
 			setStatus("success");
 			onSuccess();
 		} catch (err) {
-			if (cancelledRef.current) return;
+			if (cancelledRef.current || runSession !== sessionRef.current) return;
 			const errMsg = getErrorMessage(err);
 			setStatus("failed");
 			setErrorMessage(errMsg);
 			onError(errMsg);
 		}
 	};

 	const handleCancel = () => {
 		cancelledRef.current = true;
+		sessionRef.current += 1;
 		onClose();
 	};

Also applies to: 62-77, 84-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx` around lines 50
- 56, The reopen useEffect resets cancelledRef but doesn’t prevent prior async
completions from affecting a new dialog session; add a per-open session token
(e.g., sessionIdRef or incrementing sessionCounter) and set it when open becomes
true alongside setStatus/setErrorMessage; in each async callback or promise
resolution inside the component (the handlers that currently check cancelledRef
before calling onSuccess/onError and the async flows in the other useEffect
blocks/handlers referenced around the same areas) capture the current token in a
local variable and verify token equality before calling setStatus,
setErrorMessage, onSuccess, or onError so only the session that started the
async work may complete it.
ui/components/headersForm.tsx (2)

123-127: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the admin-header info trigger keyboard-accessible (and testable).

Line 126 uses a raw SVG as TooltipTrigger child, so keyboard users can’t focus/activate it. Wrap the icon in a semantic button and attach a stable data-testid.

Proposed fix
 							<Tooltip>
 								<TooltipTrigger asChild>
-									<Info className="text-muted-foreground size-3" />
+									<button
+										type="button"
+										className="text-muted-foreground inline-flex items-center"
+										aria-label="About static admin headers"
+										data-testid={`${testIdPrefix}-admin-headers-info-btn`}
+									>
+										<Info className="size-3" />
+									</button>
 								</TooltipTrigger>

As per coding guidelines, add data-testid to all new interactive elements in React components for E2E compatibility.

🤖 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/components/headersForm.tsx` around lines 123 - 127, The Info SVG used as
the child of TooltipTrigger is not keyboard-accessible: wrap the <Info> element
in a semantic interactive element (e.g., a <button>) and use that button as the
TooltipTrigger child (keep TooltipTrigger asChild). Add a stable data-testid
like data-testid="admin-header-info-btn" on the button and include an accessible
name (aria-label or visually-hidden text) so keyboard users can focus and
activate the tooltip; update any tests to target the new data-testid.

25-63: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Define this form’s validation with a Zod schema instead of only canSubmit gates.

The current flow has no schema-driven field errors, so it misses the required form-validation pattern for ui/**/*.{tsx,ts}. Please move/add a headers form schema (or schema builder) and surface meaningful per-field messages.

As per coding guidelines, ui/**/*.{tsx,ts} must “Always define a Zod schema for forms with meaningful validation messages,” and form schemas should live in ui/lib/types/schemas.ts.

Also applies to: 91-115

🤖 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/components/headersForm.tsx` around lines 25 - 63, Add a Zod schema for
this headers form (e.g., HeadersFormSchema) into ui/lib/types/schemas.ts and
replace the ad-hoc canSubmit gating with schema-driven validation: define
required string keys, optional initialValues shape, and per-field messages
(e.g., "Header name is required", "Value cannot be empty") and export it; then
import and use that schema in the HeadersForm component to validate inputs and
surface per-field errors for the fields rendered from HeadersFormProps
(requiredKeys, adminHeaderKeys, previouslySubmittedKeys) and in the handlers
onSubmit/onTest so the form shows meaningful field-level errors instead of only
disabling the Submit button.
🤖 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.

Outside diff comments:
In `@ui/app/workspace/mcp-registry/views/mcpClientForm.tsx`:
- Line 244: The Sheet's onOpenChange currently prevents closing only when
oauthFlow is active; update the handler used where Sheet is rendered (the
onOpenChange prop) to also block dismissal while headersFlow is active by gating
against both flags (e.g., only call onClose() when !oauthFlow && !headersFlow),
so the sheet cannot close during an in-progress per-user headers authorizer
flow.

---

Duplicate comments:
In `@ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx`:
- Around line 50-56: The reopen useEffect resets cancelledRef but doesn’t
prevent prior async completions from affecting a new dialog session; add a
per-open session token (e.g., sessionIdRef or incrementing sessionCounter) and
set it when open becomes true alongside setStatus/setErrorMessage; in each async
callback or promise resolution inside the component (the handlers that currently
check cancelledRef before calling onSuccess/onError and the async flows in the
other useEffect blocks/handlers referenced around the same areas) capture the
current token in a local variable and verify token equality before calling
setStatus, setErrorMessage, onSuccess, or onError so only the session that
started the async work may complete it.

In `@ui/components/headersForm.tsx`:
- Around line 123-127: The Info SVG used as the child of TooltipTrigger is not
keyboard-accessible: wrap the <Info> element in a semantic interactive element
(e.g., a <button>) and use that button as the TooltipTrigger child (keep
TooltipTrigger asChild). Add a stable data-testid like
data-testid="admin-header-info-btn" on the button and include an accessible name
(aria-label or visually-hidden text) so keyboard users can focus and activate
the tooltip; update any tests to target the new data-testid.
- Around line 25-63: Add a Zod schema for this headers form (e.g.,
HeadersFormSchema) into ui/lib/types/schemas.ts and replace the ad-hoc canSubmit
gating with schema-driven validation: define required string keys, optional
initialValues shape, and per-field messages (e.g., "Header name is required",
"Value cannot be empty") and export it; then import and use that schema in the
HeadersForm component to validate inputs and surface per-field errors for the
fields rendered from HeadersFormProps (requiredKeys, adminHeaderKeys,
previouslySubmittedKeys) and in the handlers onSubmit/onTest so the form shows
meaningful field-level errors instead of only disabling the Submit button.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cd17188c-ef16-4426-9d12-f1378d73974e

📥 Commits

Reviewing files that changed from the base of the PR and between a396bc2 and 2a4a450.

📒 Files selected for processing (16)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientForm.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientSheet.tsx
  • ui/app/workspace/mcp-registry/views/mcpClientsTable.tsx
  • ui/app/workspace/mcp-registry/views/mcpHeadersAuthorizer.tsx
  • ui/app/workspace/mcp-sessions/auth/page.tsx
  • ui/app/workspace/mcp-sessions/views/sessionsTable.tsx
  • ui/components/headersForm.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/index.ts
  • ui/lib/store/apis/mcpApi.ts
  • ui/lib/store/apis/mcpPerUserHeadersApi.ts
  • ui/lib/types/mcp.ts
  • ui/lib/types/mcpPerUserHeaders.ts
  • ui/lib/types/mcpSessions.ts
  • ui/lib/types/schemas.ts
✅ Files skipped from review due to trivial changes (2)
  • ui/app/_fallbacks/enterprise/components/mcp-tool-groups/mcpToolGroups.tsx
  • ui/lib/store/apis/mcpApi.ts

Pratham-Mishra04 commented May 27, 2026

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • May 27, 10:30 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 27, 10:39 AM UTC: Graphite rebased this pull request as part of a merge.
  • May 27, 10:40 AM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from 05-22-feat_backend_for_per_user_headers_mcp_auth_added to graphite-base/3704 May 27, 2026 10:35
@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from graphite-base/3704 to dev May 27, 2026 10:37
@Pratham-Mishra04
Pratham-Mishra04 dismissed coderabbitai[bot]’s stale review May 27, 2026 10:37

The base branch was changed.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch from dfa9a71 to e093972 Compare May 27, 2026 10:39
@Pratham-Mishra04
Pratham-Mishra04 merged commit e458480 into dev May 27, 2026
13 of 15 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 05-22-feat_added_ui_for_per_user_headers_mcp_auth branch May 27, 2026 10:40
akshaydeo pushed a commit that referenced this pull request May 29, 2026
## Summary

Adds a **per-user headers** authentication type for MCP clients, mirroring the existing per-user OAuth flow. Admins declare a set of required header key names on the MCP client config; each end user then submits their own values (API keys, tokens, etc.) via a dedicated auth landing page. The backend verifies upstream connectivity and stores credentials encrypted per-user. This enables MCP servers that require caller-specific API keys without sharing a single set of credentials across all users.

## Changes

- **New `per_user_headers` auth type** added to `MCPAuthType`, `MCPClientConfig`, `CreateMCPClientRequest`, and `UpdateMCPClientRequest`. Admins declare required header key names via `per_user_header_keys`; user-submitted values are never stored on the client config.
- **`MCPHeadersAuthorizer` dialog** (`mcpHeadersAuthorizer.tsx`): mirrors `OAuth2Authorizer`'s state machine (confirm → input → testing → success/failed). On Create, the admin supplies sample values; the server verifies upstream, discovers tools, and persists atomically in a single POST. Nothing is committed if the user cancels or verification fails.
- **`HeadersForm` component** (`headersForm.tsx`): reusable secret-input form used by both the admin test panel and the end-user submission page. Renders one password input per required key, supports show/hide toggle, previously-submitted key badges, and optional read-only display of admin-static header names.
- **Auth landing page** (`mcp-sessions/auth/page.tsx`): split into `OAuthAuthView` and `HeadersAuthView`. The `kind=headers` query param routes to the headers branch. `HeadersAuthView` fetches the pending flow row and schema, renders `HeadersForm`, and PUTs values back to the flow endpoint. Handles 401/404/410 error states and a post-submit success card.
- **Sessions table** (`sessionsTable.tsx`): adds a `Type` column with `OAuth`, `Headers`, and `Pending` badges. Adds `needs_update` status badge for header rows whose schema has changed. Header rows show an "Edit values" / "Update values" action instead of "Re-authenticate". Reconnect is disabled for all per-user auth types (`isPerUserAuth` replaces `isPerUserOAuth`). Header rows display `—` in the access token expiry column.
- **RTK Query API** (`mcpPerUserHeadersApi.ts`): `getMCPPerUserHeadersFlow`, `submitMCPPerUserHeadersFlow`, and `revokeMCPPerUserHeaders` endpoints targeting `/api/mcp/per-user-headers/flows/{id}`.
- **Type definitions** (`mcpPerUserHeaders.ts`, `mcpSessions.ts`): `MCPHeadersFlowDetail`, `MCPPerUserHeadersSubmitRequest/Response`, `MCPHeadersUserCredentialStatus`, `MCPSessionKind` extended with `"header"`, `MCPSessionStatus` extended with `"needs_update"`, and `auth_kind` discriminator on `MCPSessionRow`.
- **MCP clients table**: `per_user_headers` auth type renders as "Per-user Headers" in the auth type display column.
- Minor copy fix: "MCP tool groups" heading capitalised to "MCP Tool Groups".

## Type of change

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

## Affected areas

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

## How to test

```sh
cd ui
pnpm i
pnpm build
pnpm test
```

1. Navigate to **MCP Registry → Add Client**.
2. Select **Per-User Headers** as the auth type.
3. Enter comma-separated header key names (e.g. `X-API-Key, X-Tenant-ID`) in the Required Headers textarea.
4. Click **Create** — the `MCPHeadersAuthorizer` dialog opens.
5. Enter sample values and click **Run Test**. Verify the server connects, discovers tools, and the client appears in the registry.
6. As an end user, trigger a tool call that requires per-user headers. Confirm the auth landing page (`/workspace/mcp-sessions/auth?flow=...&kind=headers`) renders the submission form with the correct required keys.
7. Submit values and confirm the sessions table shows a `Headers` type row with `Active` status.
8. In the admin, change the `per_user_header_keys` schema. Confirm the existing credential row flips to `Needs update` and the "Update values" action appears.

## Screenshots/Recordings

_Add before/after screenshots of the MCP client form auth type selector, the `MCPHeadersAuthorizer` dialog, the auth landing page headers form, and the sessions table Type/Status columns._

## Breaking changes

- [x] No

`isPerUserOAuth` prop on `MCPClientActionsMenu` renamed to `isPerUserAuth` — internal component only, no external API surface affected.

## Related issues

## Security considerations

- Per-user header values (API keys, tokens) are submitted directly to the backend and stored encrypted in the credential store. Values are never round-tripped to the client after submission.
- Admin sample values supplied during the create-time verification step are discarded after the upstream connectivity check and are never persisted.
- The auth landing page accepts a temp token in the URL fragment (`#t=`) to bind anonymous browser visitors to a specific flow ID without requiring a dashboard session.
- Extra keys in user submissions are dropped server-side against the live `PerUserHeaderKeys` schema, preventing stale UI submissions from persisting deprecated keys.

## 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
@akshaydeo akshaydeo mentioned this pull request May 29, 2026
18 tasks
akshaydeo added a commit that referenced this pull request May 29, 2026
## Summary

This PR releases **core v1.5.14**, **framework v1.3.14**, **transports v1.5.6**, and bumps all dependent plugins to their respective `.14` patch versions. It delivers a broad set of new capabilities across MCP authentication, key rotation, OTel metrics, Bedrock/Anthropic compatibility, and UI improvements, alongside a number of targeted bug fixes and refactors.

## Changes

- **Direct API Key Header** — Providers can now receive an API key passed directly via a request header (#3817)
- **MCP Per-User Auth** — Introduced `MCPCredentialStore` abstraction, per-user MCP credential reconciliation, and a new per-user header auth type with lazy-auth submission flow (#3656, #3702, #3703, #3704, #3705)
- **MCP TLS Configuration** — Added configurable TLS (`insecureSkipVerify`, `caCertPem`) for HTTP/SSE MCP client connections (#3779, #3783)
- **MCP Sessions Management** — Filter, search, and pagination on the MCP sessions list API and table, plus a `can_reauth` identity gate (#3823, #3824, #3825)
- **Key Rotation** — Keys now rotate on 401/402/403 responses; returns `502 upstream_credentials_exhausted` when all keys are permanently exhausted. Added `triggered_rotation` to `KeyAttemptRecord` and tightened `bifrost_key_rotation_events_total` semantics (#3430, #3491)
- **OTel Metrics** — Added OTel spec-compatible metrics (backward compatible) with provider cache and semantic cache attributes in metrics export (#3865, #3816)
- **Opus 4.8 Support** — System message handling and general compatibility for Opus 4.8 (#3868, #3878)
- **Dimension Rankings** — New `GetDimensionRankings` API and dashboard tabs for team, customer, BU, and user rankings (#3766)
- **Model Pricing Attributes** — `additional_attributes` field on model pricing rows with management API and UI editor (#3829)
- **Prompt Cache Retention** — Added prompt cache retention parameter on responses requests (#3810)
- **Tool Call Execution UI** — Inline tool-call execution, stop streaming, bulk execute/submit, and a redesigned tool-call UI (#3837, #3843)
- **Sheet Navigation** — Prev/next keyboard navigation and URL state across virtual key, MCP client, and routing rule sheets (#3739, #3740, #3744, #3745)
- **Bedrock Tool Name Truncation** — Truncate Bedrock function/tool names to the provider length limit
- **Bedrock Guardrails** — Set guardrail config in Bedrock requests built from responses (#3862)
- **Anthropic Tool Use** — Default `tool_use` input to `{}` when arguments are absent (#3880)
- **Responses Streaming** — Fixed responses stream events (#3838)
- **Compat Flow** — Fixed missing parameter parsing on the compat flow (#3881)
- **Passthrough API Version** — Set a default API version in passthrough requests as a fallback (#3853)
- **Virtual Key Updates** — Avoid overriding optional fields during virtual key update (#3855)
- **User-Mode Flows** — Gate user-mode flows on caller `user_id`, skip temp token mint, and unify flow/credential kind filtering for pending flows (#3841, #3859)
- **Partial Tool Calls** — Handle partial tool call execution failures and return successful results (#3849)
- **URL Query Escaping** — Support escaped characters in URL query parameters (#3826)
- **MCP Auth Errors** — Inline banner and retry support for MCP auth-required errors (#3856)
- **Renamed Resolvers** — `staticHeadersResolver`/`serverOAuthResolver` renamed to `sharedHeadersResolver`/`sharedOAuthResolver` (#3840)
- **Starlark Nested Tool Calls** — Exposed `RunWithPluginPipeline` on `ClientManager` and routed Starlark nested tool calls through the canonical plugin gate (#3794)
- **Deferred-Fill OAuth Removed** — Removed deferred-fill user-mode OAuth flow support (#3839)
- **Go 1.26.3** — Upgraded toolchain to Go 1.26.3 (#3782)

## Type of change

- [x] Bug fix
- [x] Feature
- [x] 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
# Core/Transports
go version  # should report go1.26.3
go test ./...

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

- Validate MCP per-user auth by configuring a per-user header auth type and confirming credentials are stored and reconciled on virtual key and MCP client changes.
- Validate key rotation by triggering a 401/402/403 from an upstream provider and confirming rotation occurs; exhaust all keys and confirm a `502 upstream_credentials_exhausted` is returned.
- Validate OTel metrics output includes `provider_cache` and `semantic_cache` attributes.
- Validate Bedrock requests with tool names exceeding the provider limit are truncated correctly.
- Validate Opus 4.8 system message handling by sending a request with a system message to an Opus 4.8 endpoint.

## Breaking changes

- [x] Yes
- [ ] No

The deferred-fill user-mode OAuth flow has been removed (#3839). Any integrations relying on that flow must migrate to the new per-user credential store approach. The `staticHeadersResolver` and `serverOAuthResolver` identifiers have been renamed to `sharedHeadersResolver` and `sharedOAuthResolver` respectively (#3840); any direct references must be updated.

## Related issues

#3817, #3656, #3702, #3703, #3704, #3705, #3779, #3783, #3823, #3824, #3825, #3430, #3491, #3865, #3816, #3868, #3878, #3766, #3829, #3810, #3837, #3843, #3739, #3740, #3744, #3745, #3862, #3880, #3838, #3881, #3853, #3855, #3841, #3859, #3849, #3826, #3856, #3840, #3794, #3839, #3782, #3724, #3814, #3836, #3869, #3886

## Security considerations

- MCP per-user credentials are stored via the new `MCPCredentialStore` abstraction; ensure the backing store is appropriately access-controlled and that credential values are encrypted at rest.
- The direct API key header feature passes provider secrets via HTTP headers; ensure TLS is enforced on all ingress paths and that headers are not logged in plaintext.
- User-mode flows are now gated on `caller user_id` and temp token minting is skipped where appropriate, reducing the surface for privilege escalation.
- TLS configuration for MCP HTTP/SSE connections supports `insecureSkipVerify`; this should only be enabled in controlled environments.

## 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)
- [x] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request May 29, 2026
akshaydeo added a commit that referenced this pull request May 29, 2026
## ✨ Features

- **Direct API Key Header** - Pass a provider API key directly via
request header (#3817)
- **MCP Per-User Authentication** - New per-user header auth type with
credential storage
  and lazy-auth submission flow (#3703, #3704, #3705)
- **MCP TLS Configuration** - Configurable TLS (insecureSkipVerify,
caCertPem) for HTTP/SSE
  MCP client connections (#3779, #3783)
- **MCP Sessions Management** - Filter, search, and pagination on the
MCP sessions list API
  and table, plus a can_reauth identity gate (#3823, #3824, #3825)
- **Tool Call Execution UI** - Inline tool-call execution, stop
streaming, bulk
  execute/submit, and a redesigned tool-call UI (#3837, #3843)
- **Dimension Rankings Dashboard** - New dashboard tabs for team,
customer, BU, and user
  rankings, backed by a GetDimensionRankings API (#3766)
- **Model Pricing Attributes** - additional_attributes on model pricing
rows with management
  API and UI editor (#3829)
- **Prompt Cache Retention** - Prompt cache retention parameter on
responses requests
  (#3810)
- **Opus 4.8 Support** - System message handling and compatibility for
Opus 4.8 (#3878,
  #3868)
  - **Key Rotation** - Rotate keys on 401/402/403 and return 502
upstream_credentials_exhausted when all keys are permanently dead
(#3491)
- **OTel Metrics** - OTel spec compatible metrics plus provider and
semantic cache
  attributes in metrics export (#3865, #3816)
- **Sheet Navigation** - Prev/next keyboard navigation and URL state
across virtual key, MCP
  client, and routing rule sheets (#3739, #3740, #3744, #3745)
  - **Go 1.26.3** - Upgraded toolchain to Go 1.26.3 (#3782)

  ## 🐞 Fixed

- **Bedrock Tool Names** - Truncate Bedrock function/tool names to the
provider length limit
- **Bedrock Guardrails** - Set guardrail config in Bedrock request built
from responses
  (#3862)
- **Anthropic Tool Use** - Default Anthropic tool_use input to {} when
arguments are absent
  (#3880)
  - **Responses Streaming** - Fixed responses stream events (#3838)
- **Compat Flow** - Fixed missing parameter parsing on the compat flow
(#3881)
- **Passthrough API Version** - Set a default API version in passthrough
requests as a
  fallback (#3853)
- **Virtual Key Updates** - Avoid overriding optional fields during
virtual key update
  (#3855)
- **User-Mode Flows** - Gate user-mode flows on caller user_id, skip
temp token mint, and
  unify flow/credential kind filtering for pending flows (#3841, #3859)
- **Partial Tool Calls** - Handle partial tool call execution failures
and return successful
  results (#3849)
- **URL Query Escaping** - Support escaped characters in URL query
parameters (#3826)
- **MCP Auth Errors** - Inline banner and retry support for MCP
auth-required errors (#3856)
- **JSON Editor Height** - Cap JSON editor max height at 400px in
message views (#3842)
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.

2 participants