Repository navigation
fix(mcp): challenge and scope gateway-owned server authentication - #40453
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@BugBot review Please review this MCP authentication discovery fix for correctness, security, regressions, and preservation of delegated authentication behavior. |
|
@greptileai Please review this MCP authentication discovery fix, including gateway-owned modes, delegated-mode exclusions, and the regression coverage and live verification. |
Greptile SummaryThis PR enables gateway sign-in discovery for per-server MCP endpoints whose upstream authentication is owned by the gateway, then preserves the selected server scope through consent, token exchange, refresh, and request admission
Confidence Score: 5/5The PR appears safe to merge, with server scope preserved through consent, token refresh, and cross-server admission No actionable failure remains. The latest changes retain the selected server ID through authorization-code and refresh-token grants, reject mismatched resource targets, enforce live user reachability, and constrain admitted sessions to the selected server
|
| Filename | Overview |
|---|---|
| litellm/types/mcp_server/mcp_server_manager.py | Defines the shared gateway-authorization eligibility predicate while excluding delegated and explicitly client-forwarded credential modes |
| litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py | Uses the shared predicate to add matching per-server discovery challenges to gateway admission failures |
| litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py | Returns gateway authorization metadata for explicitly named servers eligible for gateway-owned sign-in |
| litellm/proxy/_experimental/mcp_server/gateway_dcr_flow.py | Extends scoped consent and grant handling to gateway-owned non-OAuth upstream modes while retaining reachability and resource checks |
| tests/test_litellm/proxy/_experimental/mcp_server/auth/test_user_api_key_auth_mcp.py | Covers missing and invalid ingress credentials across newly eligible and excluded authentication modes |
| tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py | Covers protected-resource metadata for both per-server URL formats and supported gateway-owned modes |
| tests/test_litellm/proxy/_experimental/mcp_server/test_gateway_dcr_flow.py | Verifies scoped consent, code redemption, reachability rejection, and refresh-token scope preservation |
Reviews (3): Last reviewed commit: "fix(mcp): preserve gateway-owned resourc..." | Re-trigger Greptile
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
|
@cursor review Please check the resource-scope fix and regression tests at the latest commit; local cross-server and refreshed-token verification is attached. |
|
@greptileai Please re-review the latest resource-scope fix, including consent, token refresh, and cross-server denial; updated local evidence is in the PR description. |
|
@veria-ai Please re-review the resource-scope fix at a0bb021; local tests confirm cross-server denial for access and refreshed tokens on both URL formats. |
There was a problem hiding this comment.
✅ 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 a0bb021. Configure here.
d44e52a
into
litellm_internal_staging
TLDR
Problem this solves:
How it solves it:
User Flow
Before: a client cannot discover gateway sign-in for a named no-auth MCP server
/aws_knowledge_mcp/mcpor/mcp/aws_knowledge_mcp401withoutWWW-Authenticate404; sign-in stopsAfter: the client discovers sign-in and grants access to only the requested server
401withWWW-Authenticatepointing to matching protected-resource metadata200, identifying the resource and gateway authorization serverRelevant issues
LIT-6634 tracks the separate root-metadata fallback defect
Linear ticket
Resolves LIT-6635
https://linear.app/litellm-ai/issue/LIT-6635
Pre-Submission checklist
Local affected-suite result:
897 passed, 10 warnings in 75.58s (0:01:15)The 16 new scope cases fail against the preceding PR tip and pass with this fix. They exercise both URL formats across None/none, API key, bearer, basic, authorization, token, and SigV4 modes. They verify scoped consent, rejection when the server becomes inaccessible, no unnecessary per-user vendor authorization, and scope preservation through token redemption and refresh
Test command and local gate results
The first combined test run was killed with exit 137 during the Docker build. The complete successful run above was repeated after the build finished. No budgets or suppressions were changed
Screenshots / Proof of Fix
Isolated Docker Compose gateway at
http://127.0.0.1:46635, private PostgreSQL, the real public AWS Knowledge MCP, and a running MCP SDK server enforcing a gateway-held bearer. Both runtime images were built from clean commit archives with the repository Dockerfile. All four changed installed production files match the current commit by SHA-256. No LLM calls are needed for these MCP toolsSave these reproducible scripts/configs together. All shown credentials are disposable local-only values; session tokens are withheld from published traces. Build the images from the named commits, then run
LIT6635_IMAGE=<image-tag> docker compose up -d --no-build. Tags used:litellm-6635:f529d6d6bdandlitellm-6635:scope-fixedconfig.yaml
compose.yaml
upstream.py
matrix.py
scope_probe.py
Before (f529d6d)
Authentication and discovery matrix
python3 matrix.py before. This runs actual curl requests for missing, invalid, and valid gateway credentials, plus metadata, on both URL formats for both upstreamsOAuth consent and cross-server authorization
After (a0bb021)
Authentication and discovery matrix
python3 matrix.py after. This runs actual curl requests for missing, invalid, and valid gateway credentials, plus metadata, on both URL formats for both upstreamsOAuth consent and cross-server authorization
aws-legacy full live trace
aws-standard full live trace
credential-legacy full live trace
credential-standard full live trace
Veria finding verification
Veria identified a scope gap in the preceding PR tip,
1bcb587d336c8a141809ca0fe165d1b305f1122f: after approving AWS MCP, both the access and refreshed token could list and call the credential-protected server. This was reproduced locally using the same scope probe before changing the code. Representative captured response:{"jsonrpc":"2.0","id":9,"result":{"content":[{"type":"text","text":"upstream credential accepted"}],"structuredContent":{"result":"upstream credential accepted"},"isError":false}}The current-tip traces above demonstrate the same cross-server requests denied. Consent also now names only the requested server. Gateway-owned modes enter the existing ready-to-connect state, while interactive OAuth still requires its vendor credential and existing gateway-managed OAuth scopes remain supported
Type
Bug Fix
Caveats (if any)
Low
Final Attestation