Skip to content

refactor(mcp): extract upstream preparation and support modern clients - #44232

Merged
joshua-berri merged 3 commits into
mainfrom
litellm_extract_mcp_upstream_7745
Oct 2, 2026
Merged

joshua-berri merged 3 commits into
mainfrom
litellm_extract_mcp_upstream_7745

Conversation

@joshua-berri

@joshua-berri joshua-berri commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Upstream preparation is embedded in the MCP server manager
  • Explicit modern MCP upstream configuration is rejected

How it solves it:

  • Extract credential and client preparation into a shared module
  • Compose target lookup and authorization through existing resolver policies
  • Use SDK discovery for explicitly configured modern HTTP/stdio upstreams
  • Reject incompatible transport settings before saving

User Flow

Before: adding a modern MCP upstream fails validation

  1. POST http://localhost:18402/v1/mcp/server with a server URL, transport: "http", and mcp_info.protocol_version: "2026-07-28"
  2. Receive HTTP 422 for the protocol version
  3. Configuring 2025-11-25 instead permits listing tools and calling add(2,3), returning 5

After: the configured modern upstream serves tools successfully

  1. POST http://localhost:18402/v1/mcp/server with a server URL, transport: "http", and mcp_info.protocol_version: "2026-07-28"
  2. Receive HTTP 201 with a server ID
  3. GET /mcp-rest/tools/list?server_id=<id>, then POST /mcp-rest/tools/call with that ID, name: "add", and arguments: {"a":2,"b":3}; receive HTTP 200 and 5

Linear ticket

Resolves LIT-7745

Implementation

upstream.py owns credential selection, header precedence, SigV4, stdio configuration and client preparation. It reuses the existing credential provider and error mapping; the manager retains metadata discovery and request-context capture

MCPServerTargetCatalog composes the existing lookup and authorization helpers. Credential management and temporary OAuth lookup use the contract while preserving canonical server identity, caller permissions and endpoint-specific errors

Explicit 2026-07-28 upstreams use the SDK's discovery/adoption path on HTTP and stdio. Legacy revisions retain initialization. Downstream advertisement stays unchanged; modern SSE is rejected before creation or update. Partial updates validate the stored configuration plus explicitly submitted fields. The same compatibility rule guards request models, config/runtime models, and the public client. Protocol/transport writes also re-read and validate under a database row lock in the existing write transaction, so concurrent partial edits cannot combine into an invalid saved server. Pooling, worker affinity and catalog freshness remain outside this change

Pre-Submission checklist

  • I have added meaningful tests
  • The handful of test files covering my change pass locally
  • My PR passes all required CI/CD checks
  • My PR's scope is as isolated as possible
  • I have received Greptile confidence of at least 4/5

Verification

At ca7f23dad688fae60ddf32033284d9c7f3242051, refreshed mapped unit suites passed: 1,806 manager/auth/resolver/consumer tests (one existing skip), 411 client tests, and 130 request-type tests. After an explicit type-annotation correction, 621 management/request-type tests and 26 protocol client cases passed again.

The refreshed canonical MCP integration run passed all 386 selected tests, excluding only the previously classified unrelated SSE end-user REST authorization case. The earlier full run had 384 passes and that one failure. All five new persistence/concurrency regressions and eight modern gateway transport cases passed. Final-commit live source replay confirms default/explicit modern SSE creates return 422 with no saved server; incompatible partial updates return 400 without changing the stored configuration. Valid edits and legacy/modern tool calls still succeed.

Whole-product and configured test-tree Ruff, formatting, strict-rule, type-discipline, test-quality, canonical basedpyright budget, E2E types, import checks and schema synchronization passed locally.

Changed executable-line coverage is 181/182 (99.45%). Validation helpers have 100% line and branch coverage (12/12 branches). Overall touched-function branch coverage is 132/144 (91.67%); remaining gaps include unchanged OAuth guards/cache invalidation and client cleanup paths, plus closed-union fallthroughs. The sole missed changed line remains the defensive SDK revision consistency check unreachable with the locked SDK after supported-version validation. Completed current-tip Codecov report: 98.38% patch coverage; repository-wide coverage 80.25%. Its two extra missing request-model lines are blank lines (1686 and 1781), a hosted mapping artifact, not executable gaps.

Independent Devin MCP verification passed at final ca7f23dad688fae60ddf32033284d9c7f3242051, against original baseline 2c9a9711712895a7e08ba27fca357291f4b86290, sequential pre-repair c479a4af2b0297e750f568db4cecf7f5eae871dd, and concurrency pre-repair a74097531fe31e5d67c1daf3b05d8aeeec5d87a0. Sources were clean; processes were restarted from their measured source paths. The shared enterprise directory used for the immediate race baseline was byte-identical between baseline and final.

Independent results: original gateway create/list/call and HTTP/stdio credential/lifecycle cases passed; sequential invalid writes were rejected without persistence. Six locked-row race repetitions saved invalid configurations before repair; all six final repetitions produced one accepted edit and one 400, retained valid configuration, and served list/call successfully. The initial incorrectly timed lock harness was discarded and is not evidence.

pytest -n 4 on request types, MCP management endpoints, public client and partial-update files: 1,089 passed. The additional database helper file passed seven tests. The five focused live create/update/concurrency tests passed. These controlled peers do not claim real OAuth consent or AWS authorization.

Greptile reviewed this commit at 5/5 and confirmed both findings resolved; Veria and Cursor Bugbot found no issues. The current-tip Codecov report is complete and passing. All 102 completed non-skipped hosted checks pass, including MCP integration, OAuth, lint/types and Codecov. The separate schema-migration job is still running; no schema or migration files changed.

Screenshots / Proof of Fix

Run the repository math MCP server at http://127.0.0.1:18090/mcp and a source-built proxy at http://localhost:18402. Set LOCAL_MASTER_KEY to the local test proxy's master key. Use the same requests on each source build, deleting each created server after its case. Response excerpts below show the relevant fields

curl -sS -w '\n%{http_code}' http://localhost:18402/v1/mcp/server \
  -H "Authorization: Bearer $LOCAL_MASTER_KEY" -H 'Content-Type: application/json' \
  -d '{"server_name":"proofmodern","alias":"proofmodern","url":"http://127.0.0.1:18090/mcp","transport":"http","mcp_info":{"protocol_version":"2026-07-28"}}'

curl -sS -w '\n%{http_code}' "http://localhost:18402/mcp-rest/tools/list?server_id=$SERVER_ID" \
  -H "Authorization: Bearer $LOCAL_MASTER_KEY"

curl -sS -w '\n%{http_code}' http://localhost:18402/mcp-rest/tools/call \
  -H "Authorization: Bearer $LOCAL_MASTER_KEY" -H 'Content-Type: application/json' \
  -d "{\"server_id\":\"$SERVER_ID\",\"name\":\"add\",\"arguments\":{\"a\":2,\"b\":3}}"

For the legacy control, use 2025-11-25 and prooflegacy in the creation body. SERVER_ID is the ID returned by each successful creation

Before (2c9a971)

Legacy upstream

  1. POST the legacy creation body: HTTP 201 with a server ID
  2. GET the tool list: HTTP 200, including add
  3. POST the tool call: HTTP 200, {"content":[{"type":"text","text":"5"}],"isError":false}

Modern upstream

  1. POST the modern creation body: HTTP 422, literal_error under body.mcp_info
  2. No server ID is created, so listing and calling are unavailable

After (ca7f23d)

Legacy upstream

  1. POST the legacy creation body: HTTP 201 with server ID 70216994-66df-44c4-8a90-3253aa138eca
  2. GET the tool list: HTTP 200, including add
  3. POST the tool call: HTTP 200, {"content":[{"type":"text","text":"5"}],"isError":false}

Modern upstream

  1. POST the modern creation body: HTTP 201 with server ID 8723fd94-4b8e-4bec-9853-72ecb6633c6a
  2. GET the tool list: HTTP 200, including add
  3. POST the tool call: HTTP 200, {"content":[{"type":"text","text":"5"}],"isError":false}

Transport-validation repair

On pre-repair c479a4af2b0297e750f568db4cecf7f5eae871dd, modern SSE creation returned 201 and incompatible transport-only/protocol-only updates returned 202. Matching requests on final ca7f23dad688fae60ddf32033284d9c7f3242051 return 422/400 before saving. GET confirms rejected creates are absent and rejected updates retain HTTP; a subsequent add(2,3) still returns 5. Metadata-only edits, reset to auto/SSE, and a combined modern/HTTP update remain accepted.

The concurrent-edit follow-up also reproduces a two-worker race at a74097531fe31e5d67c1daf3b05d8aeeec5d87a0: protocol-only and transport-only requests both pass a stale pre-check and save an invalid combination (202/202 or 202/500). At the final commit, one succeeds and the other returns 400; the stored combination remains valid. Both plain edits and a simultaneous rename are covered. All 298 affected database unit tests pass; changed database functions have full line and branch coverage.

Type

Refactoring
New Feature

Caveats (if any)

Low

  • Modern upstream selection is explicit; auto retains existing behavior
  • Modern upstream support is limited to HTTP and stdio

Final Attestation

  • The tests check the right things, including relevant edge cases

@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High risk] Refactors MCP protocol handling and upstream client initialization.

The PR appears safe to merge with respect to the reviewed MCP transport and concurrent-edit changes.

Summary

The PR extracts MCP upstream client preparation, adds explicit modern HTTP and stdio discovery, and validates protocol–transport compatibility before and during persistence. The latest changes re-read the server under a database row lock so concurrent partial edits cannot save an incompatible combination.

Reviews (4) · Last reviewed commit: "fix(mcp): serialize protocol validation ..."

Comment thread litellm/experimental_mcp_client/client.py Outdated
@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.44751% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/experimental_mcp_client/client.py 92.30% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread litellm/proxy/_experimental/mcp_server/upstream.py
@codspeed

codspeed Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_extract_mcp_upstream_7745 (ca7f23d) with main (688d791)

Open in CodSpeed

@joshua-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

Comment thread litellm/proxy/management_endpoints/mcp_management_endpoints.py

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

Stale Bugbot comment from a previous run.

@joshua-berri

Copy link
Copy Markdown
Contributor Author

@greptileai please re-review a740975. The modern SSE persistence finding is fixed with shared validation and passing create/partial-update persistence regressions.

@joshua-berri

Copy link
Copy Markdown
Contributor Author

@greptileai please re-review ca7f23d. Both transport-validation findings now have passing sequential and deterministic two-worker persistence regressions.

@joshua-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@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 ca7f23d. Configure here.

@joshua-berri
joshua-berri merged commit 04bc354 into main Oct 2, 2026
108 of 109 checks passed
@joshua-berri
joshua-berri deleted the litellm_extract_mcp_upstream_7745 branch October 2, 2026 23:04

This branch was successfully deployed

1 active deployment
e2e-changed — ca7f23da Deployed Oct 2, 2026 by joshua-berri via oauth #2695
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.

4 participants