Skip to main content

Overview

The MCP Sessions UI is available in Bifrost v1.5.0-prerelease2 and above (initial release), with per-user-headers support added in v1.5.4.
The MCP Sessions page is scoped to per-user MCP authentications — both per-user OAuth tokens and per-user submitted headers. Server-level headers and oauth clients don’t surface here; their credentials live on the MCP client config itself, not as per-caller rows. Each row represents one of:
  • A completed credential — OAuth token or stored header values, keyed to a specific identity (VK, signed-in user, or session ID)
  • A pending submission flow — a consent / submission link the user hasn’t yet completed
The table is scoped to the caller’s identity: a signed-in admin sees rows visible under their VK / user ID; a caller authenticating only via x-bf-vk sees rows for that VK; etc.
MCP Sessions table with one row of each type and status

Columns


Statuses

Per-user OAuth (Type = OAuth)

Per-user Headers (Type = Headers)

Pending flow rows (Type = Pending)

Pending rows expire on their own after a short window (15 minutes); expired flow rows are deleted by Bifrost’s sweep worker — they don’t linger as failed rows.

Why orphaned and needs_* are different

Both look like “broken — make the user re-auth”, but the remediation is different:
  • needs_reauth / needs_update are caller-side problems. A fresh credential fixes them: re-authenticate for OAuth, resubmit for headers.
  • orphaned is an access-control problem. The credential itself is fine; what’s missing is the identity’s right to use this MCP through Bifrost. Running a fresh OAuth flow or resubmitting headers would either produce a duplicate credential or land back in the same orphan state on the next reconcile. The actual fix is admin-side: re-add the VK to the MCP’s allowlist, turn AllowOnAllVirtualKeys back on, or restore the user’s access profile.
The UI hides the Re-authenticate / Edit values action on orphaned rows for exactly this reason.

Actions

The action menu adapts to the row’s kind and status. Orphaned and needs_reauth rows are mutually exclusive with the action that wouldn’t help — Bifrost doesn’t surface no-op options.

Re-authenticate (OAuth)

Available on needs_reauth OAuth token rows. Clicking it:
  1. Mints a fresh consent flow against the same MCP client and identity
  2. Redirects the browser to the upstream provider
  3. On callback, replaces the dead credential in place — same row ID, status flips to active
The original identity (VK ID, user ID, or session ID) is preserved — re-auth doesn’t let you re-bind to a different identity.

Edit values (Headers)

Available on active and needs_update header credential rows. Clicking it:
  1. Mints a fresh submission flow against the same MCP client and identity
  2. Redirects the browser to the values form pre-populated with the names of currently-stored keys (values are never shown)
  3. On submit, Bifrost runs a one-time upstream verify, replaces the credential in place, and flips status to active

Complete authentication (Pending)

Available on pending flow rows. Just sends the user back to the auth URL (OAuth consent or headers submission depending on the flow’s kind) so they can finish what they started.

Revoke

Available on credential rows and on stale pending flows. Hard-deletes the row. For pending OAuth flows, the corresponding flow row is removed first to close the race where an upstream callback could mint a brand-new token after revoke.
Bifrost does not call the upstream provider’s /revoke endpoint when you click Revoke. Per-user OAuth doesn’t store a per-server revocation endpoint, so revocation is local to Bifrost only. If you want the upstream provider to invalidate the token too, revoke it from the provider’s dashboard (GitHub Settings → Authorized OAuth Apps, etc.). Per-user-headers credentials never call an upstream revoke — the headers are just stored values.

Automatic reconciliation when VK / MCP access changes

Bifrost keeps per-user credentials in sync with the VK ↔ MCP allowlist automatically. When the effective allowlist for a credential’s identity changes, every affected row flips status without anyone having to click anything: The “effective allowlist” Bifrost uses is explicit per-VK MCP configs ∪ MCPs with AllowOnAllVirtualKeys=true — same predicate as the runtime tool-allowance check. Session-keyed credentials (rows where the identity is x-bf-mcp-session-id) are not subject to reconcile — they don’t have an AP-model identity to evaluate. They are only deleted when their MCP client is deleted.

What appears in the table

The table is scoped to the caller’s identity:
  • A signed-in admin sees rows visible under their VK / user ID — not every row in the system.
  • A user authenticated only via a vk header sees rows for that VK.
  • A caller asserting only x-bf-mcp-session-id sees rows for that session ID.
This is the same identity scoping that gates which auth URL a caller can complete: for user-mode flows, only the bound SSO user can finish the flow (anyone else gets a 403). VK-mode and session-mode flows treat the URL itself as the capability — see Flow mode and access rules for the per-mode behavior. When a credential and a pending flow exist for the same (identity, MCP) binding, only the credential row is shown. The flow row is suppressed to avoid duplicate-looking entries — it stays in the database until the user completes (and the row is consumed) or it expires.

Troubleshooting

Check the row status on the Sessions page:
  • Active but tool still failing → look at the access-token expiry. If it’s past, Bifrost will refresh on the next call automatically; if the refresh itself is failing, the row flips to needs_reauth after a couple of retries.
  • Orphaned → the caller’s identity has lost access to this MCP client. Restore the VK assignment / toggle AllowOnAllVirtualKeys back on / fix the access profile; the row reactivates on next reconcile.
  • Needs re-auth → click Re-authenticate and complete the upstream flow.
  • Needs update (header rows) → click Edit values and resubmit on the form.
Pending flows have a 15-minute TTL. If the user took too long, the row is gone — trigger the action again to mint a fresh flow.
That’s by design. The Re-authenticate / Edit values action is hidden on orphaned rows. If you got there via a stale URL, the new credential would still be orphaned because the access constraint is admin-side. Restore access (re-assign the VK, toggle AllowOnAllVirtualKeys back on, fix the access profile) and the row reactivates automatically.
You probably revoked the credential row while a pending flow was still in flight. The flow completed against the same (identity, MCP) binding and minted a fresh credential. Revoke now drops pending flows first to close this race; if you’re still seeing it, also delete any Pending rows for the same MCP / identity from the table.