Skip to content

feat(mcp): add dcr_bridge column and plumbing for client-forwarded auth modes - #32745

Merged
tin-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_lit4337_dcr_bridge_plumbing
Jul 10, 2026
Merged

feat(mcp): add dcr_bridge column and plumbing for client-forwarded auth modes#32745
tin-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_lit4337_dcr_bridge_plumbing

Conversation

@tin-berri

@tin-berri tin-berri commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Part of LIT-4337 (PR 1 of the stack; the discovery facade, register relay, and UI toggle land in follow-up PRs on top of this field)

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Live proxy from this branch on localhost:4010 backed by a fresh Postgres database, with prisma migrate deploy applying the new migration in sequence first ("All migrations have been successfully applied"; information_schema.columns then shows dcr_bridge boolean, is_nullable YES)

  1. Create a true_passthrough server with the flag on
curl -s -X POST http://localhost:4010/v1/mcp/server -H "Authorization: Bearer $MASTER_KEY" -H "Content-Type: application/json" \
  -d '{"server_name":"bridge_demo","url":"https://mcp.linear.app/mcp","transport":"http","auth_type":"true_passthrough","dcr_bridge":true}'
# 200, server_id b9e36a1f-bd2d-48d9-98a5-61d4704f59ef
  1. Read it back; the flag round-trips
curl -s http://localhost:4010/v1/mcp/server/b9e36a1f-... -H "Authorization: Bearer $MASTER_KEY"
# {'server_name': 'bridge_demo', 'auth_type': 'true_passthrough', 'dcr_bridge': True}
  1. The flag is rejected on a gateway-managed auth type
curl -s -X POST http://localhost:4010/v1/mcp/server ... -d '{...,"auth_type":"oauth2","oauth2_flow":"authorization_code","dcr_bridge":true}'
# HTTP 422 {"detail":[{"type":"value_error","loc":["body"],"msg":"Value error, dcr_bridge is only supported for auth_type true_passthrough or oauth_delegate (got 'oauth2'). ..."}]}
  1. Switching auth_type away clears the flag with the other auth-flow-scoped fields
curl -s -X PUT http://localhost:4010/v1/mcp/server ... -d '{"server_id":"b9e36a1f-...","url":"...","transport":"http","auth_type":"api_key","credentials":{"auth_value":"sk-x"}}'
# HTTP 202
curl -s http://localhost:4010/v1/mcp/server/b9e36a1f-... 
# {'auth_type': 'api_key', 'dcr_bridge': None}
  1. Enabling the flag on an update without auth_type in the payload validates against the stored row and fails closed
curl -s -X PUT http://localhost:4010/v1/mcp/server ... -d '{"server_id":"b9e36a1f-...","url":"...","transport":"http","dcr_bridge":true}'
# HTTP 400 {"detail":{"error":"dcr_bridge is only supported for auth_type true_passthrough or oauth_delegate (stored auth_type: 'api_key'). Include the server's auth_type in the update payload or configure one of the client-forwarded token modes first."}}

Note: tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py::test_delete_mcp_oauth_user_credential_invalidates_when_record_already_gone fails identically on a clean litellm_internal_staging checkout, so it is pre-existing and unrelated to this change

Type

🆕 New Feature

Changes

Adds the dcr_bridge per-server boolean end to end as a dark field: nullable dcr_bridge column on LiteLLM_MCPServerTable (three schema.prisma copies plus a migration), the field on MCPServer, LiteLLM_MCPServerTable, NewMCPServerRequest, and UpdateMCPServerRequest, config-yaml ingestion, the DB-row and config builders, and both server-table response builders so the value round-trips to the dashboard. No behavior changes; nothing reads the flag at request time yet

The flag is only meaningful for the client-forwarded token modes, so it is validated everywhere it can enter: model validators reject it on create (and on update when the payload carries auth_type) for any auth type other than true_passthrough or oauth_delegate, load_servers_from_config rejects it for other auth types and rejects non-boolean values, and the update endpoint validates a flag-only update against the stored row's auth_type, failing closed when that row cannot be read. dcr_bridge also joins _AUTH_FLOW_SCOPED_FIELDS so switching a server's auth_type clears it alongside the other flow-scoped settings, and a new MCPServer.is_dcr_bridge property gates on both the flag and the mode as defense in depth for rows edited outside these paths

Context: verbatim upstream OAuth discovery stays the default for the client-forwarded modes (that contract is load-bearing for deployments whose clients are pre-registered with the upstream IdP). The bridge is a per-server opt-in for OAuth-only MCP clients that can only connect via DCR; this PR ships the field so the follow-ups can gate the discovery facade and register relay on it


Note

Low Risk
Additive nullable column and config validation with no runtime OAuth path changes yet; auth-type guards reduce misconfiguration risk.

Overview
Adds a nullable dcr_bridge boolean on MCP servers end-to-end (Prisma migration + schema copies, API/request models, YAML config load, DB builders, and list/detail responses) so the value persists and round-trips. No request-time OAuth behavior uses the flag yet—this is storage and validation only ahead of discovery/register work.

dcr_bridge is only allowed when auth_type is true_passthrough or oauth_delegate: Pydantic validators on create/update, load_servers_from_config, and edit_mcp_server (when enabling the flag without auth_type, checked against the stored row; fails closed if the pre-read fails). The field is in _AUTH_FLOW_SCOPED_FIELDS, so changing auth type clears it with other flow settings; switching to client-forwarded modes can still set it explicitly. MCPServer.is_dcr_bridge combines the flag with those auth modes for later gating.

Reviewed by Cursor Bugbot for commit 5ec4c16. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the dcr_bridge boolean field end-to-end as a dark/inert flag — database column, Prisma schema (three copies), Pydantic models, config ingestion, DB builders, and response models — so follow-up PRs can gate the OAuth discovery facade and register relay on it without a schema migration.

  • Field plumbing: dcr_bridge: Optional[bool] = None is threaded through MCPServer, LiteLLM_MCPServerTable, NewMCPServerRequest, UpdateMCPServerRequest, both DB builder paths, both response builders, and the config loader — with no reads at request time yet.
  • Validation at every entry point: create-time model validators reject the flag on any auth type other than true_passthrough / oauth_delegate; the update endpoint separately validates against the stored auth_type when the payload omits it, failing closed (HTTP 400) on DB errors and correctly falling through to a 404 when the server_id simply does not exist.
  • Scoped-field clearing: dcr_bridge joins _AUTH_FLOW_SCOPED_FIELDS so switching a server's auth type away from a client-forwarded mode automatically clears the flag, while an explicit dcr_bridge=True in the same update payload correctly survives the clearing pass.

Confidence Score: 5/5

Safe to merge — the change is purely additive (nullable column, no existing behavior altered) and no code reads the flag at request time yet.

The field is plumbed correctly through all layers with matching schema, model, and builder changes. Validation is enforced at create time, at update time when auth_type is present, and at the endpoint level when it is absent, with the previously-flagged 404-vs-400 ambiguity now covered by an explicit test. No existing behavior is modified and no production code path reads dcr_bridge yet.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/_types.py Adds dcr_bridge: Optional[bool] = None to both NewMCPServerRequest and UpdateMCPServerRequest, with mode-before model validators enforcing the field is only set with true_passthrough or oauth_delegate auth types; update validator correctly defers the no-auth_type case to the endpoint.
litellm/proxy/management_endpoints/mcp_management_endpoints.py Adds old_server_record_read_failed flag and a gate block that validates dcr_bridge against the stored auth_type when the payload omits it; correctly skips the block (and falls through to a 404) when the record simply isn't found, addressing the prior review thread.
litellm/proxy/_experimental/mcp_server/db.py Adds dcr_bridge to _AUTH_FLOW_SCOPED_FIELDS so the value is cleared when auth_type changes; explicit caller-provided values win over the clearing logic via the if field not in data_dict guard.
litellm/types/mcp_server/mcp_server_manager.py Adds dcr_bridge: Optional[bool] = None field and is_dcr_bridge property to MCPServer; the property gates on both the flag and the mode as a defense-in-depth check for rows edited outside the normal paths.
tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py Adds thorough test coverage: create-time rejection on wrong/absent auth_type, update-time rejection with and without stored record, the 404-not-400 case for nonexistent server_id, and round-trip verification on the response model.

Reviews (2): Last reviewed commit: "fix(mcp): let a missing server 404 on a ..." | Re-trigger Greptile

Comment thread litellm/proxy/management_endpoints/mcp_management_endpoints.py Outdated
@tin-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@tin-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@codspeed-hq

codspeed-hq Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_lit4337_dcr_bridge_plumbing (5ec4c16) with litellm_internal_staging (bf02a4a)

Open in CodSpeed

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 5ec4c16. Configure here.

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

LGTM; thanks!

@tin-berri
tin-berri merged commit bca3e88 into litellm_internal_staging Jul 10, 2026
134 checks passed
@tin-berri
tin-berri deleted the litellm_lit4337_dcr_bridge_plumbing branch July 10, 2026 18:45
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