Skip to content

feat: add mcp per-user headers auth type with credential storage and submission flow#3703

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

feat: add mcp per-user headers auth type with credential storage and submission flow#3703
Pratham-Mishra04 merged 1 commit into
devfrom
05-22-feat_backend_for_per_user_headers_mcp_auth_added

Conversation

@Pratham-Mishra04

Copy link
Copy Markdown
Collaborator

Summary

Adds MCPAuthTypePerUserHeaders — a new per-user MCP authentication type where each caller submits their own API keys or signed-token header values (e.g. Authorization, X-Api-Key) rather than going through an OAuth dance. The admin declares the required header names (per_user_header_keys) at MCP client creation time; end users supply values on first tool use via an inline-401 submission flow that mirrors the existing per-user OAuth surface.

Changes

  • New MCPAuthTypePerUserHeaders auth type: Added to MCPAuthType constants, MCPClientConfig, and all validation paths. Requires a non-empty PerUserHeaderKeys list; oauth_config_id must not be set.
  • Unified MCPAuthRequiredError: Replaced MCPUserOAuthRequiredError with MCPAuthRequiredError (with a Kind field: "oauth" or "headers"). MCPUserOAuthRequiredError is retained as a type alias for backward compatibility.
  • perUserHeadersResolver: New credstore resolver that looks up per-user header credentials by (auth_mode, identity, mcp_client_id). On miss or stale schema, initiates a submission flow and returns an MCPAuthRequiredError with Kind="headers" and a SubmitURL.
  • MCPHeadersProvider interface and mcp_headers.Provider: Storage backend for per-user header credentials and pending submission flow rows. Mirrors OAuth2Provider structurally. Includes InitiateUserSubmissionFlow which mints a mcp_headers_auth temp token embedded in the auth-page URL fragment.
  • VerifyHeadersConnection: New method on MCPManager and Bifrost that opens a temporary MCP connection using caller-supplied header values, runs the Initialize handshake, and discovers tools. Used during admin MCP client creation (sample values) and user submission (validate before persisting).
  • Database migrations: Two new migrations — add_mcp_per_user_header_credentials_table (creates mcp_per_user_header_credentials, adds per_user_header_keys_json to config_mcp_clients, and creates partial unique indexes per auth mode) and add_mcp_per_user_header_flows_table (creates mcp_per_user_header_flows).
  • StaticConfigHeaders updated: Now strips any header whose name appears in PerUserHeaderKeys from the plugin-visible static header set, preventing admin-set static values from leaking through the connect-plugin gate for per-user-headers clients.
  • BifrostContextKeyMCPCallbackBaseURL: Replaces BifrostContextKeyOAuthRedirectURI. The base URL is now set once; OAuth resolver appends /api/oauth/callback, headers resolver appends the workspace submit path.
  • GovernancePlugin.PreMCPConnectionHook: New hook that resolves the caller's VK identity onto the BifrostContext before the credential-store resolver runs, so per-user auth types can key stored credentials by VK row ID.
  • HTTP handlers:
    • POST /api/mcp/client extended to handle per_user_headers auth type: validates per_user_header_keys, runs VerifyHeadersConnection with admin sample values, persists discovered tools, and discards the sample values.
    • New MCPPerUserHeadersHandler with routes: GET /api/mcp/per-user-headers/flows/{id} (flow detail), PUT /api/mcp/per-user-headers/flows/{id} (submit), DELETE /api/mcp/per-user-headers/credential/{id} (revoke).
    • MCPSessionsHandler extended to list, reauth, and revoke header credential and header flow rows alongside OAuth rows. Added auth_kind field to mcpSessionRow to disambiguate OAuth vs headers rows on the wire.
  • mcpHeadersAuthScope temp token scope: Grants GET and PUT access to the per-user-headers flow endpoints, bound to the flow ID. Registered at server startup alongside mcpAuthScope.
  • CredentialSweepWorker: Background worker that reaps orphaned credential rows (24h cadence, 30-day retention) and expired pending flow rows (15-min cadence). Started and stopped alongside the OAuth sweep worker.
  • identityForMCPAuthMode moved to its own file (credstore/identity.go) so both perUserOAuthResolver and perUserHeadersResolver share it without duplication.
  • Cascade deletes: DeleteMCPClientConfig and DeleteVirtualKey now also delete mcp_per_user_header_credentials and mcp_per_user_header_flows rows for the affected client/VK.
  • MarkMCPPerUserHeaderCredentialsNeedsUpdate: Called by updateMCPClient when PerUserHeaderKeys changes, flipping existing active credential rows to needs_update so callers are forced to resubmit on next tool use.

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

go test ./...
  1. Create an MCP client with auth_type: per_user_headers and per_user_header_keys: ["Authorization"], supplying a sample user_headers map in the request body. Verify the client is created with discovered tools and the sample values are not persisted.
  2. Make a tool call through the client without submitting credentials. Confirm the response contains extra_fields.mcp_auth_required with kind: "headers" and a submit_url.
  3. Visit the submit_url, call GET /api/mcp/per-user-headers/flows/{id} to confirm the form schema, then PUT with valid header values. Confirm the credential row is created and the flow row is deleted.
  4. Retry the tool call — it should succeed using the stored credential.
  5. Call DELETE /api/mcp/per-user-headers/credential/{id} and confirm the credential and any pending flow rows are removed.
  6. Update the MCP client's per_user_header_keys and confirm existing credential rows flip to needs_update, triggering the inline-401 on next tool use.
  7. Delete the MCP client and confirm all associated credential and flow rows are removed.

Breaking changes

  • Yes
  • No

MCPUserOAuthRequiredError is retained as a type alias for MCPAuthRequiredError, so existing callers that reference the old type continue to compile. The BifrostContextKeyOAuthRedirectURI context key is replaced by BifrostContextKeyMCPCallbackBaseURL; any code outside this repository that sets the old key directly will need to be updated.

Security considerations

  • Admin-supplied sample header values used during MCP client creation are never persisted — they are used once for upstream verification and discarded.
  • Per-user header values are stored encrypted at rest using the same encryption key as OAuth tokens (BIFROST_ENCRYPTION_KEY).
  • PerUserHeaderKeys entries are stripped from the plugin-visible static header set so connect-plugin hooks cannot read or rewrite per-user credential values.
  • Temp tokens for the headers submission flow are embedded as URL fragments (#t=<token>), which are not sent to servers in Referer headers and do not appear in server access logs.
  • Flow rows are bound to a single (mode, identity, mcp_client_id) triple; the submit endpoint validates the caller's values against the upstream before persisting.

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

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d4300f7-c970-4d87-a91f-a133ef7d85b0

📥 Commits

Reviewing files that changed from the base of the PR and between 0cc89eb and 2c05f60.

📒 Files selected for processing (36)
  • core/bifrost.go
  • core/mcp/agent.go
  • core/mcp/clientmanager.go
  • core/mcp/codemode/starlark/executecode.go
  • core/mcp/credstore/credstore.go
  • core/mcp/credstore/per_user_headers.go
  • core/mcp/credstore/per_user_oauth.go
  • core/mcp/credstore/utils.go
  • core/mcp/exec.go
  • core/mcp/interface.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • core/mcp/utils.go
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/mcp.go
  • core/schemas/mcp_headers.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/store.go
  • framework/configstore/tables/mcp.go
  • framework/configstore/tables/mcp_per_user_headers.go
  • framework/mcp_headers/main.go
  • framework/mcp_headers/sweep.go
  • framework/temptoken/scope.go
  • plugins/governance/main.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcp_per_user_headers.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/temp_token_scopes.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/lib/lib.go
  • transports/bifrost-http/server/server.go

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features
    • Added per-user header authentication for MCP connections, enabling users to submit and manage custom header credentials as an alternative to OAuth-based authentication.
    • New MCP header credential verification, management, and revocation capabilities within the authentication interface.
    • Enhanced MCP authentication error handling to support both OAuth and header-based authentication flows with appropriate remediation guidance.

Walkthrough

This PR implements per-user MCP headers authentication as an alternative to OAuth, featuring unified error types that discriminate between OAuth and headers flows, a full credential lifecycle with persistence/encryption, temporary verification endpoints for header discovery, and integrated session management.

Changes

Per-User Headers MCP Authentication

Layer / File(s) Summary
Auth types, credential contracts, and unified error schema
core/schemas/mcp.go, core/schemas/bifrost.go, core/schemas/mcp_headers.go (new)
Introduce MCPAuthTypePerUserHeaders constant; define MCPAuthRequiredError type with Kind discriminator to support both OAuth (authorize_url, session_id) and headers (submit_url, session_id, required_header_keys, admin_header_keys) variants; convert MCPUserOAuthRequiredError to a backward-compatible alias; define credential status lifecycle (active, needs_update, orphaned) and MCPHeadersProvider interface for provider-based credential CRUD and flow initiation.
Credential provider implementation and lifecycle management
framework/mcp_headers/main.go, framework/mcp_headers/sweep.go, framework/temptoken/scope.go
Implement storage-backed MCPHeadersProvider with GetCredentialByMode, UpsertCredential, DeleteCredential, and InitiateUserSubmissionFlow methods; add optional temp-token service integration for short-lived flow URLs; introduce CredentialSweepWorker to periodically purge orphaned credentials (older than 30 days) and expired pending flows; add MCPHeadersAuthScopeName temp-token scope for 15-minute flow access.
Database schema, migrations, and credential/flow CRUD
framework/configstore/migrations.go, framework/configstore/rdb.go, framework/configstore/store.go, framework/configstore/tables/mcp.go, framework/configstore/tables/mcp_per_user_headers.go (new)
Add per_user_header_keys_json column and runtime PerUserHeaderKeys field to TableMCPClient; create mcp_per_user_header_credentials and mcp_per_user_header_flows tables with encryption support, status tracking, and (auth_mode, identity, mcp_client_id) binding; implement full CRUD interface including transactional upserts with UUID assignment, orphan/expired cleanup, and status transitions via ConfigStore interface and RDB implementation.
Credential resolution, headers validation, and connection verification
core/mcp/credstore/credstore.go, core/mcp/credstore/per_user_headers.go (new), core/mcp/credstore/per_user_oauth.go, core/mcp/credstore/utils.go (new), core/mcp/utils/utils.go, core/mcp/clientmanager.go, core/mcp/utils.go, core/mcp/mcp.go, core/mcp/toolmanager.go, core/bifrost.go
Wire MCPHeadersProvider into NewCredStore alongside OAuth2Provider; implement perUserHeadersResolver to fetch stored headers, validate required keys, and return MCPAuthRequiredError on missing/stale credentials; extract identityForMCPAuthMode helper; update OAuth resolver to return unified MCPAuthRequiredError; add VerifyHeadersConnection method to MCPManager for temporary header-based tool discovery; replace BuildRedirectURIFromContext with BuildMCPCallbackBaseURL and BuildOAuthRedirectURIFromContext; extend StaticConfigHeaders to exclude per-user header keys case-insensitively; update all credstore instantiations to pass headers provider.
Unified auth-required error handling in tool execution paths
core/mcp/exec.go, core/mcp/agent.go, core/mcp/interface.go, core/mcp/codemode/starlark/executecode.go
Update error detection from OAuth-specific MCPUserOAuthRequiredError to unified MCPAuthRequiredError in executeToolWithHooks and agent parallel-execution path; populate error via MCPAuthRequired union field in BifrostError.ExtraFields; update comments and interface documentation.
HTTP handlers for header credential verification, flow submission, and revocation
transports/bifrost-http/handlers/mcp.go, transports/bifrost-http/handlers/mcp_per_user_headers.go (new), transports/bifrost-http/handlers/mcpserver.go, transports/bifrost-http/handlers/temp_token_scopes.go
Add per_user_headers branch to addMCPClient for header-key validation, sample header requirements, tool discovery via VerifyHeadersConnection, and detected-tool persistence; implement MCPPerUserHeadersHandler with flowDetail, flowSubmit (validates, upserts credentials, cleans up flows), and revoke endpoints at /api/mcp/per-user-headers/flows/{id} and /api/mcp/per-user-headers/credential/{id}; extend updateMCPClient to conditionally validate and mark credentials needs_update on schema drift; update client listing to include PerUserHeaderKeys; vary tool-execution error remediation URL/text by authReq.Kind; add mcpHeadersAuthScope with 15-minute TTL and route whitelisting.
MCP session management extended for header credentials and flows
transports/bifrost-http/handlers/mcp_sessions.go
Extend mcpSessionRow with AuthKind discriminator and include updated_at for header credentials; query and de-duplicate header credentials/flows alongside OAuth rows in list(); implement reauth() branching to initiate header submission flows; extend revoke() to delete header credential/flow rows (with cascade cleanup); add row-mapping helpers and binding-key computation for header de-duplication.
HTTP server and framework configuration wiring
transports/bifrost-http/lib/config.go, transports/bifrost-http/lib/config_test.go, transports/bifrost-http/lib/ctx.go, transports/bifrost-http/lib/lib.go, transports/bifrost-http/server/server.go
Add MCPHeadersProvider and MCPHeadersSweepWorker fields to Config; construct provider and start sweep worker (30-day retention) in initFrameworkConfig; replace OAuth redirect URI context key with MCP callback base URL for both OAuth and headers flows; add HasDuplicates generic utility for case-insensitive key deduplication; extend MockConfigStore test stubs for header credential/flow methods; wire provider to temp-token service; register MCPPerUserHeadersHandler routes in server bootstrap; pass MCPHeadersProvider to bifrost.Init.
Governance plugin MCP connection lifecycle hooks
plugins/governance/main.go
Add PreMCPConnectionHook to resolve virtual-key identity context (VK ID/name plus optional team/customer details) and PostMCPConnectionHook as a pass-through in the MCP connection lifecycle.

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • maximhq/bifrost#2418: Overlaps on the agent/tool execution error-handling path for auth-required detection and propagation.
  • maximhq/bifrost#3656: Directly extends the credential-resolution refactor with per-user headers credentials and updated MCPAuthRequiredError propagation in core MCP paths.
  • maximhq/bifrost#3702: Builds on the same MCP connection/auth refactor and header-filtering infrastructure, generalized to support headers verification.

Suggested Reviewers

  • danpiths
  • akshaydeo
  • roroghost17

🐰 Hopping through headers with glee, 🎯
Per-user auth flows now run free,
OAuth joins forces with credential keys,
Unified errors make debugging a breeze!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: adding MCP per-user headers authentication with credential storage and submission flow.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, changes, type of change, affected areas, testing steps, breaking changes, security considerations, and checklist.
Docstring Coverage ✅ Passed Docstring coverage is 90.48% which is sufficient. The required threshold is 80.00%.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-22-feat_backend_for_per_user_headers_mcp_auth_added

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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-refactor_mcp_plugin_lifecycle_fixes branch from 9a1e82a to 7b10bef 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.

@coderabbitai coderabbitai Bot requested a review from roroghost17 May 23, 2026 16:00
@greptile-apps

greptile-apps Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

The core auth flows are structurally sound but the dedicated revoke endpoint does not purge in-flight flow rows, leaving a short window where a credential can be re-created after explicit revocation.

The credential-store resolver, storage layer, cascade deletes, and sweep worker mirror the established OAuth patterns and are correct. The dedicated revoke endpoint in mcp_per_user_headers.go still does not purge in-flight flow rows, and the sessions routing logic silently swallows DB lookup errors.

transports/bifrost-http/handlers/mcp_per_user_headers.go (revoke endpoint) and transports/bifrost-http/handlers/mcp_sessions.go (silent DB-error swallowing)

Important Files Changed

Filename Overview
core/mcp/credstore/per_user_headers.go New per-user headers resolver; ErrHeadersCredentialNeedsUpdate case in switch is unreachable dead code
framework/mcp_headers/main.go New MCPHeadersProvider storage backend; correctly returns both active and needs_update rows but never returns ErrHeadersCredentialNeedsUpdate
transports/bifrost-http/handlers/mcp_per_user_headers.go New per-user headers flow/credential HTTP handlers; revoke does not purge in-flight flow rows
transports/bifrost-http/handlers/mcp_sessions.go Extended sessions list/reauth/revoke for header rows; DB lookup errors silently discarded in routing logic
framework/configstore/rdb.go New per-user header CRUD methods mirror OAuth patterns; DeleteVirtualKey now correctly purges credential and flow rows
core/mcp/clientmanager.go New VerifyHeadersConnection method mirrors VerifyPerUserOAuthConnection
transports/bifrost-http/handlers/mcp.go addMCPClient and updateMCPClient extended with per_user_headers branch; validation correct
framework/configstore/migrations.go Two new migrations with partial unique indexes and rollback paths

Reviews (12): Last reviewed commit: "feat: backend for per user headers mcp a..." | Re-trigger Greptile

Comment thread transports/bifrost-http/handlers/mcp_per_user_headers.go
Comment thread transports/bifrost-http/handlers/mcp.go
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-refactor_mcp_plugin_lifecycle_fixes branch from 7b10bef to 1cd8fd3 Compare May 24, 2026 19:55
@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
Comment thread framework/configstore/rdb.go
@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
Comment thread transports/bifrost-http/handlers/mcp_per_user_headers.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: 12

Caution

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

⚠️ Outside diff range comments (1)
transports/bifrost-http/lib/config.go (1)

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

Normalize PerUserHeaderKeys before hashing/persisting.

This path feeds GenerateMCPClientHash(...) with the raw PerUserHeaderKeys slice. Because header-key order is not semantically meaningful, a config-file reorder of the same keys will look like a schema change and can spuriously trigger MCP client updates / per-user credential re-submission.

♻️ Proposed fix
 func mcpClientConfigToTable(clientConfig *schemas.MCPClientConfig) (configstoreTables.TableMCPClient, error) {
 	if clientConfig == nil {
 		return configstoreTables.TableMCPClient{}, nil
 	}
 	if clientConfig.ToolSyncInterval%time.Second != 0 {
 		return configstoreTables.TableMCPClient{}, fmt.Errorf(
 			"tool_sync_interval must be a whole number of seconds, got %q",
 			clientConfig.ToolSyncInterval.String(),
 		)
 	}
 	authType := string(clientConfig.AuthType)
 	if authType == "" {
 		authType = string(schemas.MCPAuthTypeHeaders)
 	}
+	perUserHeaderKeys := slices.Clone(clientConfig.PerUserHeaderKeys)
+	slices.Sort(perUserHeaderKeys)
+	perUserHeaderKeys = slices.Compact(perUserHeaderKeys)
+
 	return configstoreTables.TableMCPClient{
 		ClientID:                  clientConfig.ID,
 		Name:                      clientConfig.Name,
 		IsCodeModeClient:          clientConfig.IsCodeModeClient,
 		ConnectionType:            string(clientConfig.ConnectionType),
 		ConnectionString:          clientConfig.ConnectionString,
@@
-		PerUserHeaderKeys:         clientConfig.PerUserHeaderKeys,
+		PerUserHeaderKeys:         perUserHeaderKeys,
 		ConfigHash:                clientConfig.ConfigHash,
 	}, 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/lib/config.go` around lines 1433 - 1468, The
mcpClientConfigToTable path currently passes raw PerUserHeaderKeys into
persistence and GenerateMCPClientHash causing spurious diffs when key order
changes; fix by normalizing PerUserHeaderKeys (create a copy, deduplicate if
necessary, then sort the slice) before assigning it to the TableMCPClient or
before calling GenerateMCPClientHash so order is deterministic; update
mcpClientConfigToTable to use the normalized slice for ConfigHash and the
PerUserHeaderKeys field, referencing mcpClientConfigToTable, PerUserHeaderKeys
and GenerateMCPClientHash to locate the change.
🤖 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/mcp/credstore/per_user_headers.go`:
- Around line 114-125: The function missingRequiredHeaderKeys currently does
exact map lookups which treat header names case-sensitively; change it to
compare header names case-insensitively by normalizing storedHeaders keys (e.g.,
build a new map with strings.ToLower(key) -> value) and compare each required
key using strings.ToLower(key) so "Authorization" and "authorization" match;
apply the same normalization approach to the other header helper in this file
that performs header existence/lookup logic so all header name checks are
case-insensitive.

In `@core/mcp/utils.go`:
- Around line 639-651: When config.AuthType == schemas.MCPAuthTypePerUserHeaders
also validate that the client uses an HTTP transport: reject configs whose
transport/type is SSE, STDIO, in-process or any non-HTTP scheme so they cannot
pass validation; add this check alongside the existing PerUserHeaderKeys and
OauthConfigID validations in the same validation block (where config.AuthType,
config.PerUserHeaderKeys and config.OauthConfigID are checked), and surface an
error message saying something like "per_user_headers requires an HTTP transport
(transport_type must be HTTP) for client '<name>'" so VerifyHeadersConnection
and transport.NewStreamableHTTP will only be invoked for valid HTTP clients.

In `@core/mcp/utils/utils.go`:
- Around line 28-44: The
BuildOAuthRedirectURIFromContext/BuildMCPCallbackBaseURL logic can produce a
double-slash when the stored base has a trailing slash; update
BuildMCPCallbackBaseURL to normalize the returned base by trimming any trailing
'/' (use strings.TrimRight or equivalent) so BuildOAuthRedirectURIFromContext
can safely concatenate "/api/oauth/callback" without producing "//"; locate the
functions BuildMCPCallbackBaseURL and BuildOAuthRedirectURIFromContext and apply
the trimming to the base before returning it.

In `@framework/configstore/rdb.go`:
- Around line 5383-5385: The MCPClient preload Select currently omits the
encryption_status column, causing TableMCPClient.AfterFind to be unable to
detect encrypted rows; update the Preload("MCPClient", func(db *gorm.DB)
*gorm.DB { ... }) Select to include "encryption_status" alongside "client_id,
name, headers_json, allowed_extra_headers_json, per_user_header_keys_json" so
AfterFind can properly trigger decryption logic for headers_json.
- Around line 1840-1846: When reconciling authoritative client config
(clientConfig.ConfigHash != ""), ensure auth-specific DB columns are cleared
when omitted in the payload: instead of only writing
updates["per_user_header_keys_json"] when clientConfig.PerUserHeaderKeys != nil,
detect the authoritative path (clientConfig.ConfigHash != "") and explicitly set
updates["per_user_header_keys_json"] to a NULL/empty sentinel when
PerUserHeaderKeys is nil so stale header schemas are removed; do the same for
the OAuth column by clearing updates["oauth_config_id"] when the payload does
not include an OAuth config (e.g., clientConfig.OAuthConfigId is nil/empty)
during authoritative sync. Ensure you reference the same updates map and keys
("per_user_header_keys_json", "oauth_config_id") so the DB update will
overwrite/clear prior values in the authoritative ConfigHash path.

In `@framework/mcp_headers/main.go`:
- Around line 84-91: Before converting the DB row into a credential, reject rows
that are not active by checking the row's needs_update and orphaned flags: in
the code path around the current return in main.go (before calling
rowToCredential), if row.NeedsUpdate is true return a specific error (e.g.
schemas.ErrHeadersCredentialNeedsUpdate or, if that error doesn't exist,
schemas.ErrHeadersCredentialNotFound), and if row.Orphaned is true return a
specific orphaned error (e.g. schemas.ErrHeadersCredentialOrphaned or
schemas.ErrHeadersCredentialNotFound); only call rowToCredential and return the
credential when both flags are false so drifted/orphaned rows are not treated as
usable.

In `@plugins/governance/main.go`:
- Around line 1734-1745: PreMCPConnectionHook currently only sets governance
team/customer context when vk.Team or vk.Customer relations are loaded; update
the block to fall back to foreign-key fields if relations are nil: when vk.Team
!= nil set Team ID/Name from vk.Team as before, else if vk.TeamID != nil set
schemas.BifrostContextKeyGovernanceTeamID from vk.TeamID (and skip name or set
empty); likewise for customer — if vk.Customer != nil use vk.Customer.ID/Name,
else if vk.CustomerID != nil set schemas.BifrostContextKeyGovernanceCustomerID
from vk.CustomerID; keep ctx.SetValue calls (and the same keys) and avoid
overwriting more specific relation values with FK fallbacks.

In `@transports/bifrost-http/handlers/mcp_per_user_headers.go`:
- Around line 214-226: The missing-header check and the filtering loop perform
exact map lookups so header names like "Authorization" vs "authorization" fail;
make header matching case-insensitive by normalizing request header names to a
single case (e.g. strings.ToLower) before lookups. Concretely: build a temporary
map (e.g. reqHeadersLower map[string]string) populated with lowercased keys from
req.Headers, call missingPerUserHeaderValues against config.PerUserHeaderKeys
after lowercasing those keys or change missingPerUserHeaderValues to lowercase
its incoming keys, and in the filtered population loop use the original config
key name as the map key but retrieve the value from
reqHeadersLower[strings.ToLower(key)]. Apply the same normalization in the
second occurrence referenced (lines ~337-344).

In `@transports/bifrost-http/handlers/mcp_sessions.go`:
- Around line 215-220: The header-credential and header-flow lookups (e.g.,
calls to h.store.ConfigStore.GetMCPPerUserHeaderCredentialByID and the similar
header-flow lookup used by revoke/reauth) are currently ignoring errors and
treating any error as a cache miss, allowing header-backed rows to fall through
to the OAuth path and return 404; change those call sites so that if the store
call returns a non-nil error you surface a 500 (do not fallthrough to the OAuth
path), logging the error and short-circuiting (return) before calling
reauthHeaderCredential or the OAuth handlers; update both the reauth path
(reauthHeaderCredential invocation) and the revoke flow (the similar lookup
block around the 355-399 range) to check and handle err != nil explicitly.

In `@transports/bifrost-http/handlers/mcp.go`:
- Around line 409-425: The validation lowercases header names only for duplicate
detection but leaves the original-cased PerUserHeaderKeys in place, causing
case-only edits (e.g. "Authorization" → "authorization") to be treated as schema
changes; update the handler to canonicalise the header keys permanently after
validation—use strings.ToLower(strings.TrimSpace(key)) (the same logic that
produces normalisedHeaders) to replace the incoming req.PerUserHeaderKeys (or
the stored representation used by perUserHeaderKeysChanged) so storage and
change-detection both use the canonicalised form; keep using lib.HasDuplicates
and missingPerUserHeaderValues for validation but persist normalisedHeaders for
comparison and storage to avoid spurious perUserHeaderKeysChanged flips.
- Around line 822-838: The validation currently allows an explicitly provided
empty slice for req.PerUserHeaderKeys which lets resolvePerUserHeaderKeys
persist an empty schema; update the validation in the request-handling path (the
block that examines req.PerUserHeaderKeys in mcp.go) to reject an explicitly
provided zero-length slice for per-user-headers clients by returning a
BadRequest (similar to how empty strings and duplicates are handled);
specifically, if req.PerUserHeaderKeys != nil and len(req.PerUserHeaderKeys) ==
0, call SendError with a clear message like "per_user_header_keys must contain
at least one entry" so resolvePerUserHeaderKeys cannot be given an empty list.
- Around line 1000-1009: The code flips per-user-header credential rows to
'needs_update' (MarkMCPPerUserHeaderCredentialsNeedsUpdate) before calling
h.mcpManager.UpdateMCPClient, which can leave credentials marked when the
runtime update later fails; move the call to
MarkMCPPerUserHeaderCredentialsNeedsUpdate so it runs only after
h.mcpManager.UpdateMCPClient returns success, and in the failure path ensure any
partial DB row rollback (the existing rollback logic around UpdateMCPClient)
does not leave credentials in 'needs_update' (i.e., revert the mark or skip
marking). Apply the same reorder/fix for the analogous block at the other
location (lines ~1013-1022) and reference existingConfig,
perUserHeaderKeysChanged, and h.store.ConfigStore when making the change.

---

Outside diff comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 1433-1468: The mcpClientConfigToTable path currently passes raw
PerUserHeaderKeys into persistence and GenerateMCPClientHash causing spurious
diffs when key order changes; fix by normalizing PerUserHeaderKeys (create a
copy, deduplicate if necessary, then sort the slice) before assigning it to the
TableMCPClient or before calling GenerateMCPClientHash so order is
deterministic; update mcpClientConfigToTable to use the normalized slice for
ConfigHash and the PerUserHeaderKeys field, referencing mcpClientConfigToTable,
PerUserHeaderKeys and GenerateMCPClientHash to locate the change.
🪄 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: f59f8454-557a-4b71-9528-9a6c4d445308

📥 Commits

Reviewing files that changed from the base of the PR and between 1cd8fd3 and 0cc89eb.

📒 Files selected for processing (35)
  • core/bifrost.go
  • core/mcp/agent.go
  • core/mcp/clientmanager.go
  • core/mcp/codemode/starlark/executecode.go
  • core/mcp/credstore/credstore.go
  • core/mcp/credstore/identity.go
  • core/mcp/credstore/per_user_headers.go
  • core/mcp/credstore/per_user_oauth.go
  • core/mcp/exec.go
  • core/mcp/interface.go
  • core/mcp/mcp.go
  • core/mcp/utils.go
  • core/mcp/utils/utils.go
  • core/schemas/bifrost.go
  • core/schemas/mcp.go
  • core/schemas/mcp_headers.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/store.go
  • framework/configstore/tables/mcp.go
  • framework/configstore/tables/mcp_per_user_headers.go
  • framework/mcp_headers/main.go
  • framework/mcp_headers/sweep.go
  • framework/temptoken/scope.go
  • plugins/governance/main.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcp_per_user_headers.go
  • transports/bifrost-http/handlers/mcp_sessions.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/temp_token_scopes.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/lib/lib.go
  • transports/bifrost-http/server/server.go

Comment thread core/mcp/credstore/per_user_headers.go
Comment thread core/mcp/utils.go
Comment thread core/mcp/utils/utils.go
Comment thread framework/configstore/rdb.go
Comment thread framework/configstore/rdb.go
Comment thread transports/bifrost-http/handlers/mcp_per_user_headers.go
Comment thread transports/bifrost-http/handlers/mcp_sessions.go
Comment thread transports/bifrost-http/handlers/mcp.go
Comment thread transports/bifrost-http/handlers/mcp.go
Comment thread transports/bifrost-http/handlers/mcp.go
@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-refactor_mcp_plugin_lifecycle_fixes branch from 1cd8fd3 to a0b1f5c Compare May 25, 2026 06:27
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch 2 times, most recently from c7d9551 to 1a2dcbf Compare May 25, 2026 07:29
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from 1a2dcbf to c2f1282 Compare May 25, 2026 08:10
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 c2f1282 to e27f0c0 Compare May 25, 2026 12:31
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-refactor_mcp_plugin_lifecycle_fixes branch from a0b1f5c to 0707fe5 Compare May 25, 2026 12:31
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch 2 times, most recently from 7bb0272 to d389c49 Compare May 26, 2026 18:29
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-refactor_mcp_plugin_lifecycle_fixes branch from 0707fe5 to 3559654 Compare May 26, 2026 18:29
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-refactor_mcp_plugin_lifecycle_fixes branch from 3559654 to ebcb864 Compare May 27, 2026 05:44
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from d389c49 to dbe84c6 Compare May 27, 2026 05:44

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:36 AM UTC: Graphite rebased this pull request as part of a merge.
  • May 27, 10:37 AM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04 Pratham-Mishra04 changed the base branch from 05-22-refactor_mcp_plugin_lifecycle_fixes to graphite-base/3703 May 27, 2026 10:32
@Pratham-Mishra04 Pratham-Mishra04 changed the base branch from graphite-base/3703 to dev May 27, 2026 10:34
@Pratham-Mishra04 Pratham-Mishra04 dismissed coderabbitai[bot]’s stale review May 27, 2026 10:34

The base branch was changed.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch from dbe84c6 to 2c05f60 Compare May 27, 2026 10:35
@Pratham-Mishra04 Pratham-Mishra04 merged commit 52b9250 into dev May 27, 2026
12 of 14 checks passed
@Pratham-Mishra04 Pratham-Mishra04 deleted the 05-22-feat_backend_for_per_user_headers_mcp_auth_added branch May 27, 2026 10:37
akshaydeo pushed a commit that referenced this pull request May 29, 2026
…submission flow (#3703)

## Summary

Adds `MCPAuthTypePerUserHeaders` — a new per-user MCP authentication type where each caller submits their own API keys or signed-token header values (e.g. `Authorization`, `X-Api-Key`) rather than going through an OAuth dance. The admin declares the required header names (`per_user_header_keys`) at MCP client creation time; end users supply values on first tool use via an inline-401 submission flow that mirrors the existing per-user OAuth surface.

## Changes

- **New `MCPAuthTypePerUserHeaders` auth type**: Added to `MCPAuthType` constants, `MCPClientConfig`, and all validation paths. Requires a non-empty `PerUserHeaderKeys` list; `oauth_config_id` must not be set.
- **Unified `MCPAuthRequiredError`**: Replaced `MCPUserOAuthRequiredError` with `MCPAuthRequiredError` (with a `Kind` field: `"oauth"` or `"headers"`). `MCPUserOAuthRequiredError` is retained as a type alias for backward compatibility.
- **`perUserHeadersResolver`**: New credstore resolver that looks up per-user header credentials by `(auth_mode, identity, mcp_client_id)`. On miss or stale schema, initiates a submission flow and returns an `MCPAuthRequiredError` with `Kind="headers"` and a `SubmitURL`.
- **`MCPHeadersProvider` interface and `mcp_headers.Provider`**: Storage backend for per-user header credentials and pending submission flow rows. Mirrors `OAuth2Provider` structurally. Includes `InitiateUserSubmissionFlow` which mints a `mcp_headers_auth` temp token embedded in the auth-page URL fragment.
- **`VerifyHeadersConnection`**: New method on `MCPManager` and `Bifrost` that opens a temporary MCP connection using caller-supplied header values, runs the Initialize handshake, and discovers tools. Used during admin MCP client creation (sample values) and user submission (validate before persisting).
- **Database migrations**: Two new migrations — `add_mcp_per_user_header_credentials_table` (creates `mcp_per_user_header_credentials`, adds `per_user_header_keys_json` to `config_mcp_clients`, and creates partial unique indexes per auth mode) and `add_mcp_per_user_header_flows_table` (creates `mcp_per_user_header_flows`).
- **`StaticConfigHeaders` updated**: Now strips any header whose name appears in `PerUserHeaderKeys` from the plugin-visible static header set, preventing admin-set static values from leaking through the connect-plugin gate for per-user-headers clients.
- **`BifrostContextKeyMCPCallbackBaseURL`**: Replaces `BifrostContextKeyOAuthRedirectURI`. The base URL is now set once; OAuth resolver appends `/api/oauth/callback`, headers resolver appends the workspace submit path.
- **`GovernancePlugin.PreMCPConnectionHook`**: New hook that resolves the caller's VK identity onto the `BifrostContext` before the credential-store resolver runs, so per-user auth types can key stored credentials by VK row ID.
- **HTTP handlers**:
  - `POST /api/mcp/client` extended to handle `per_user_headers` auth type: validates `per_user_header_keys`, runs `VerifyHeadersConnection` with admin sample values, persists discovered tools, and discards the sample values.
  - New `MCPPerUserHeadersHandler` with routes: `GET /api/mcp/per-user-headers/flows/{id}` (flow detail), `PUT /api/mcp/per-user-headers/flows/{id}` (submit), `DELETE /api/mcp/per-user-headers/credential/{id}` (revoke).
  - `MCPSessionsHandler` extended to list, reauth, and revoke header credential and header flow rows alongside OAuth rows. Added `auth_kind` field to `mcpSessionRow` to disambiguate OAuth vs headers rows on the wire.
- **`mcpHeadersAuthScope` temp token scope**: Grants `GET` and `PUT` access to the per-user-headers flow endpoints, bound to the flow ID. Registered at server startup alongside `mcpAuthScope`.
- **`CredentialSweepWorker`**: Background worker that reaps orphaned credential rows (24h cadence, 30-day retention) and expired pending flow rows (15-min cadence). Started and stopped alongside the OAuth sweep worker.
- **`identityForMCPAuthMode`** moved to its own file (`credstore/identity.go`) so both `perUserOAuthResolver` and `perUserHeadersResolver` share it without duplication.
- **Cascade deletes**: `DeleteMCPClientConfig` and `DeleteVirtualKey` now also delete `mcp_per_user_header_credentials` and `mcp_per_user_header_flows` rows for the affected client/VK.
- **`MarkMCPPerUserHeaderCredentialsNeedsUpdate`**: Called by `updateMCPClient` when `PerUserHeaderKeys` changes, flipping existing active credential rows to `needs_update` so callers are forced to resubmit on next tool use.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./...
```

1. Create an MCP client with `auth_type: per_user_headers` and `per_user_header_keys: ["Authorization"]`, supplying a sample `user_headers` map in the request body. Verify the client is created with discovered tools and the sample values are not persisted.
2. Make a tool call through the client without submitting credentials. Confirm the response contains `extra_fields.mcp_auth_required` with `kind: "headers"` and a `submit_url`.
3. Visit the `submit_url`, call `GET /api/mcp/per-user-headers/flows/{id}` to confirm the form schema, then `PUT` with valid header values. Confirm the credential row is created and the flow row is deleted.
4. Retry the tool call — it should succeed using the stored credential.
5. Call `DELETE /api/mcp/per-user-headers/credential/{id}` and confirm the credential and any pending flow rows are removed.
6. Update the MCP client's `per_user_header_keys` and confirm existing credential rows flip to `needs_update`, triggering the inline-401 on next tool use.
7. Delete the MCP client and confirm all associated credential and flow rows are removed.

## Breaking changes

- [ ] Yes
- [x] No

`MCPUserOAuthRequiredError` is retained as a type alias for `MCPAuthRequiredError`, so existing callers that reference the old type continue to compile. The `BifrostContextKeyOAuthRedirectURI` context key is replaced by `BifrostContextKeyMCPCallbackBaseURL`; any code outside this repository that sets the old key directly will need to be updated.

## Security considerations

- Admin-supplied sample header values used during MCP client creation are never persisted — they are used once for upstream verification and discarded.
- Per-user header values are stored encrypted at rest using the same encryption key as OAuth tokens (`BIFROST_ENCRYPTION_KEY`).
- `PerUserHeaderKeys` entries are stripped from the plugin-visible static header set so connect-plugin hooks cannot read or rewrite per-user credential values.
- Temp tokens for the headers submission flow are embedded as URL fragments (`#t=<token>`), which are not sent to servers in `Referer` headers and do not appear in server access logs.
- Flow rows are bound to a single `(mode, identity, mcp_client_id)` triple; the submit endpoint validates the caller's values against the upstream before persisting.

## 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 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