test(e2e): cover MCP core happy paths: upstream auth, access control, allowed_tools, aggregate routing - #33263
Draft
tin-berri wants to merge 2 commits into
Draft
test(e2e): cover MCP core happy paths: upstream auth, access control, allowed_tools, aggregate routing#33263tin-berri wants to merge 2 commits into
tin-berri wants to merge 2 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
tin-berri
force-pushed
the
litellm_mcp_e2e_tests
branch
from
July 15, 2026 02:34
d3c9670 to
f503c3a
Compare
tin-berri
force-pushed
the
litellm_mcp_e2e_core_flows
branch
8 times, most recently
from
July 15, 2026 23:03
f86b2e4 to
523abf6
Compare
tin-berri
force-pushed
the
litellm_mcp_e2e_tests
branch
from
July 16, 2026 19:51
a03750f to
9b144f1
Compare
tin-berri
force-pushed
the
litellm_mcp_e2e_core_flows
branch
2 times, most recently
from
July 16, 2026 20:03
a67aa98 to
8dab1be
Compare
5 tasks
tin-berri
force-pushed
the
litellm_mcp_e2e_core_flows
branch
2 times, most recently
from
July 17, 2026 00:41
2d4b549 to
110709c
Compare
… allowed_tools, aggregate routing
…on the authorization_code flow
tin-berri
force-pushed
the
litellm_mcp_e2e_core_flows
branch
from
July 17, 2026 02:32
110709c to
c84cb8b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Relevant issues
Stacked on #33102 (the first tests/e2e/mcp suite); this PR extends that suite and should merge after it
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito 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
All runs are against the tests/e2e compose stack (
ghcr.io/berriai/litellm:main-latest+ postgres + redis + the mcp-stub service from this PR)All runs are against the tests/e2e compose stack (
ghcr.io/berriai/litellm:main-latest+ postgres + redis + the mcp-stub service). Suite run across the stacked suite: 8 passed / 1 failed; the failure is the base PR's deliberately red Authorization-header OAuth test (challenge-skip masking gap documented in #33102), not a test from this PRWhile building the since-removed client_credentials coverage, this work also surfaced and live-verified a real gateway bug worth recording:
_raise_preemptive_401_for_unauthenticated_serversinlitellm/proxy/_experimental/mcp_server/server.pychallenges every oauth2 server that received no per-request oauth header, and because the raise sits at the outerauth_type == oauth2level, client_credentials (M2M) servers, for which the gateway is supposed to mint its own token from stored credentials, fall through into an interactive OAuth challenge and are unusable over the MCP protocol path. Verified live: an earlycontinueforserver.has_client_credentialsat the top of that block makes the full M2M flow work, with the token minted from the configured token_url exactly once and cached per expires_in. Recorded here as a finding for a separate fix; this PR carries no M2M test by choiceType
✅ Test
Changes
Adds the core MCP happy-path coverage on top of #33102: upstream credential injection (static api_key), server-level access control via object_permission grants, server-level allowed_tools governance, and the aggregate /mcp namespace with x-mcp-servers scoping. Each test asserts the recorded state round-trips through the management API (with secrets redacted) and that the behavior actually bites on live MCP protocol traffic, per the e2e standards
The mcp-stub grows three sibling mounts next to the anonymous and interactive-OAuth ones the base branch ships, all in the same container and port:
/second/mcpserves a deliberately disjoint tool set so aggregate routing is provable;/apikey/mcprejects any request whoseX-API-Keyis not exactly the stub's expected secret;/oauth/mcp(with a client_credentials grant on the stub IdP's token endpoint) stays as foundation for future M2M coverage but carries no test in this PR. The guarded mounts record the headers of the last authorized request and expose them through the base branch'srecorded_headerstool pattern, so tests can assert exactly which credentials the gateway attached upstream and that the caller's virtual key never crossed the gateway boundary; a served call on the guarded mount is itself proof the gateway injected the credential, which is the fail-before-fix evidence built into the upstream-auth testHarness changes are additive:
models.pygains the allowed_tools field on the MCP server bodies andobject_permissionon key generation,mcp_client.pygains aggregate-namespace helpers and acall_tool_oncethat models denials as values, andcoverage_registry/mcp.yamlgains five new cells (the two denial cells and both oauth cells were already in the registry and are now claimed by tests; the interactive authorization_code cells ship with the base branch)QA runbook
Final Attestation