Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 201 additions & 113 deletions docs/openapi/openapi.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,8 @@ paths:
$ref: './paths/management/mcp.yaml#/client-complete-oauth'
/api/mcp/client/{id}/initiate-verification:
$ref: './paths/management/mcp.yaml#/client-initiate-verification'
/api/mcp/client/{id}/reauthorize:
$ref: './paths/management/mcp.yaml#/client-reauthorize'
/api/mcp/client/{id}/verify-headers:
$ref: './paths/management/mcp.yaml#/client-verify-headers'

Expand Down
151 changes: 128 additions & 23 deletions docs/openapi/paths/management/mcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,14 @@ clients:
in: query
description: |
Comma-separated runtime connection states to include (OR semantics),
resolved against live engine state. `connected` matches clients the engine
currently reports as connected; `disconnected` matches everything else.
resolved against live engine state. Only `connected` and
`disconnected` are meaningful filter values: `connected` matches
clients the engine currently reports as connected; `disconnected`
matches everything else (error, pending states, needs_reauth,
disabled, not present in the engine). Selecting both, or neither,
applies no state filter. Note the response-only needs_reauth
projection on per-user clients happens after filtering, so such
clients still match `connected`.
schema:
type: string
example: connected
Expand Down Expand Up @@ -169,7 +175,10 @@ client:
summary: Add MCP client
description: |
Adds a new MCP client with the specified configuration.
Note: tool_pricing is not available when creating a new client as tools are fetched after client creation.
Note: tool_pricing is not available when creating a new client; tool
pricing can only be set once the tool list is known. For shared-connection
clients tools are fetched after client creation; for per-user auth types
they are discovered during the create/verify flow itself.
tags:
- MCP
requestBody:
Expand Down Expand Up @@ -204,8 +213,13 @@ client-by-id:
operationId: editMCPClient
summary: Edit MCP client
description: |
Updates an existing MCP client's configuration.
Updates an existing MCP client's configuration. All fields are optional
(PATCH semantics); connection_type, auth_type, connection_string,
stdio_config, and oauth_config_id are immutable after creation.
Unlike client creation, tool_pricing can be included to set per-tool execution costs since tools are already fetched.
For OAuth-based clients, providing oauth_config rotates the stored OAuth
configuration in place and flips every bound token to needs_reauth when
a field actually changes (see MCPClientUpdateRequest.oauth_config).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Optionally provide vk_configs to manage which virtual keys have access to this MCP server and with which tools. When provided, this fully replaces all existing VK assignments in a single atomic transaction.
Set disabled: true to shut down the client's connection and workers without removing it. Set disabled: false to reconnect a previously disabled client.
tags:
Expand Down Expand Up @@ -301,35 +315,56 @@ client-complete-oauth:
operationId: completeMCPClientOAuth
summary: Complete MCP client OAuth flow
description: |
Completes the OAuth flow for an MCP client after the user has authorized the request.
This endpoint should be called after the OAuth provider redirects back to the callback endpoint
and the OAuth token has been stored. It retrieves the pending MCP client configuration and
establishes the connection with the OAuth-provided credentials.
Completes an OAuth flow for an MCP client after the admin has authorized
the request upstream. Call it once the flow's status_url reports
"authorized". It serves every admin-side OAuth completion with one
endpoint:

- Create-time and config.json-bootstrap flows: retrieves the pending MCP
client configuration and establishes the connection with the
OAuth-provided credentials (per_user_oauth clients instead verify with
the admin token, discover tools, and retain the token as the admin
discovery credential).
- Reauthorize flows (started via POST /api/mcp/client/{id}/reauthorize):
for shared "oauth" clients, reconnects the client with the fresh
credential; for per_user_oauth clients, verifies the fresh admin token
upstream, re-discovers tools, and promotes it to the retained admin
discovery credential.

Replays are rejected with 409: hitting the endpoint again after the flow
already completed (no pending configuration and no freshly-written
token) returns "OAuth flow has already been completed".
tags:
- MCP
- OAuth
parameters:
- name: id
in: path
required: true
description: MCP client ID
description: |
The oauth_config_id of the flow being completed (as returned in the
initiation response's oauth_config_id / complete_url), not the MCP
client ID.
schema:
type: string
security:
- ManagementBearerAuth: []
responses:
'200':
description: MCP client connected successfully with OAuth
description: MCP client connected (or re-authorized) successfully with OAuth
content:
application/json:
schema:
$ref: '../../schemas/management/common.yaml#/SuccessResponse'
'400':
description: OAuth not authorized yet or MCP client not found in pending OAuth clients
description: OAuth flow not authorized yet, or the OAuth config does not belong to an OAuth-based MCP client
$ref: '../../openapi.yaml#/components/responses/BadRequest'
'404':
description: MCP client not found in pending OAuth clients or OAuth config not found
description: OAuth config not found, or no MCP client is linked to this OAuth flow
$ref: '../../openapi.yaml#/components/responses/NotFound'
'409':
description: OAuth flow has already been completed for this MCP client (replay)
$ref: '../../openapi.yaml#/components/responses/Conflict'
'500':
$ref: '../../openapi.yaml#/components/responses/InternalError'

Expand Down Expand Up @@ -376,18 +411,86 @@ client-initiate-verification:
'500':
$ref: '../../openapi.yaml#/components/responses/InternalError'

client-reauthorize:
post:
operationId: reauthorizeMCPClient
summary: Reauthorize an MCP client
description: |
Redoes the OAuth consent flow for an already-authorized OAuth-based MCP
client, without delete-and-recreate. The flow always runs against the
credentials currently stored on the client's OAuth config.

- auth_type "oauth": serves both a standalone admin-triggered reauth
(e.g. the upstream provider revoked the credential and the client sits
in needs_reauth) and the follow-up to rotating oauth_config via
PUT /api/mcp/client/{id} (which cascades every bound token to
needs_reauth).
- auth_type "per_user_oauth": repairs the retained admin discovery
credential used for periodic tool-list refresh. Only allowed while
that credential actually sits in needs_reauth (409 otherwise);
end-user credentials are untouched either way.

Complete the returned flow like any other admin OAuth flow: open
authorize_url in a browser, poll status_url until "authorized", then
POST complete_url.
tags:
- MCP
- OAuth
parameters:
- name: id
in: path
required: true
description: MCP client ID
schema:
type: string
security:
- ManagementBearerAuth: []
responses:
'200':
description: Reauthorization flow initiated
content:
application/json:
schema:
$ref: '../../schemas/management/oauth.yaml#/OAuthFlowInitiation'
'400':
description: Client is not an OAuth-based auth type (oauth, per_user_oauth), or has never completed initial OAuth authorization (use initiate-verification instead)
$ref: '../../openapi.yaml#/components/responses/BadRequest'
'404':
description: MCP client not found
$ref: '../../openapi.yaml#/components/responses/NotFound'
'409':
description: The admin discovery credential for this per_user_oauth client does not need repair or does not exist
$ref: '../../openapi.yaml#/components/responses/Conflict'
'503':
description: OAuth provider not configured
content:
application/json:
schema:
$ref: '../../schemas/inference/common.yaml#/BifrostError'
'500':
$ref: '../../openapi.yaml#/components/responses/InternalError'

client-verify-headers:
post:
operationId: verifyMCPClientHeaders
summary: Verify a pending per-user-headers MCP client
description: |
Completes the one-time admin verification for an MCP client sitting in
pending_verification state with auth_type "per_user_headers" (declared
via config.json). The admin supplies sample values for every declared
Completes the admin verification for an MCP client with auth_type
"per_user_headers". The admin supplies sample values for every declared
per_user_header_keys entry; Bifrost opens an upstream connection with
them, discovers the tool list, persists it, and transitions the client
to connected. The sample values are discarded — each end-user submits
their own values at runtime. Synchronous; no browser flow.
to connected. The sample values are retained as the admin discovery
credential the periodic tool syncer uses to refresh the tool list; each
end-user still submits their own values at runtime. Synchronous; no
browser flow.

Serves two situations: the one-time bootstrap verification for a client
sitting in pending_verification (declared via config.json), and a
voluntary refresh of an already-verified client's retained admin
discovery credential — resubmitting sample values always re-runs
verification and upserts the credential back to active, whether or not
it currently needs repair (mirrors POST /reauthorize for OAuth-based
clients).
tags:
- MCP
parameters:
Expand All @@ -411,8 +514,10 @@ client-verify-headers:
type: string
description: |
Sample value for every header name declared in the client's
per_user_header_keys. Used once for the verification
connection, then discarded — never persisted.
per_user_header_keys. Used for the verification connection,
then retained as the admin discovery credential for periodic
tool-list refresh. Never used for end-user traffic and never
surfaced on /api/mcp/sessions.
security:
- ManagementBearerAuth: []
responses:
Expand All @@ -436,9 +541,6 @@ client-verify-headers:
$ref: '../../openapi.yaml#/components/responses/BadRequest'
'404':
$ref: '../../openapi.yaml#/components/responses/NotFound'
'409':
description: Client has already been verified (tools discovered); delete and recreate to re-verify
$ref: '../../openapi.yaml#/components/responses/Conflict'
'422':
description: Upstream verification failed with the supplied header values
content:
Expand All @@ -454,12 +556,15 @@ sessions:
get:
summary: List MCP sessions
description: |
Returns every per-user MCP authentication artifact visible to the caller —
Returns every per-user MCP authentication artifact visible to the caller:
OAuth tokens, header credentials, and pending submission / consent flows.

Row visibility is scoped to the caller's identity (Virtual Key, signed-in
user, or asserted session ID). Server-level `headers` / `oauth` clients
are not surfaced here; their credentials live on the MCP client config.
Admin discovery credentials (the retained bootstrap credential Bifrost
uses for periodic tool-list refresh on per-user clients) never appear
here either; only user-, vk-, and session-keyed rows are listed.

When both a credential and a pending flow exist for the same
`(identity, mcp_client)` binding, the credential is returned and the
Expand Down
14 changes: 9 additions & 5 deletions docs/openapi/paths/management/oauth.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ oauth-config-by-id:
description: |
Revokes a server-level OAuth configuration and its associated access token.
After revocation, the MCP client will no longer be able to use this OAuth token.
Revocation is not terminal for the client: an admin can restore access by
redoing consent via POST /api/mcp/client/{id}/reauthorize, which runs
against the credentials currently stored on the client's OAuth config.
tags:
- OAuth
parameters:
Expand Down Expand Up @@ -217,8 +220,9 @@ per-user-oauth-flow-start:
'500':
$ref: '../../openapi.yaml#/components/responses/InternalError'

# ─── Removed: OAuth-server endpoints (RFC 7591/8414 surface) ────────────────
# Bifrost is not an OAuth Authorization Server. Upstream OAuth happens via
# the per-user-oauth-flow-* endpoints above.

# Legacy block intentionally removed:
# The endpoints in this file cover upstream MCP OAuth only, Bifrost acting
# as an OAuth *client* against external MCP servers (via the
# per-user-oauth-flow-* endpoints above and the /api/mcp/client/* flows).
# The inbound surface where Bifrost acts as an OAuth Authorization Server
# for /mcp callers (/.well-known/*, /oauth2/*) is a separate feature and is
# not documented in this file.
8 changes: 8 additions & 0 deletions docs/openapi/schemas/management/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ ClientConfig:
mcp_tool_execution_timeout:
type: integer
description: Timeout for MCP tool execution in seconds
mcp_tool_sync_interval:
type: integer
description: >
Global tool-list sync interval in minutes for MCP clients. Applies to
clients whose per-client tool_sync_interval is 0 or omitted; a
per-client positive value overrides it and a per-client negative value
disables syncing for that client. When 0 or unset, a 10-minute default
applies.
mcp_code_mode_binding_level:
type: string
description: Binding level for MCP code mode
Expand Down
Loading
Loading