Commit graph

795 commits

Author SHA1 Message Date
Yassin Kortam
9cc5b78c33
Merge pull request #41634 from BerriAI/litellm_agent_access_groups
feat(agents): attach access groups to agents and enforce them for models, MCP servers and agent calls
2026-09-21 19:13:46 -05:00
joshua-berri
3353c57e76
Merge pull request #42292 from BerriAI/litellm_extract_mcp_operation_context_7741
refactor(mcp): extract explicit operation context and dispatch
2026-09-21 22:38:07 +00:00
yassin
82eef2fcca fix(proxy): scope agent permissions to invoking caller
An agent key that echoes the x-litellm-user-id / x-litellm-team-id headers
forwarded by /a2a is capped at that user's and team's models, MCP servers
and agents, on top of its own grants and access group ceiling. The echoed
ids only narrow, and nested A2A hops forward the original human caller

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 22:32:32 +00:00
Mateo Wang
7b8bc54237
Merge pull request #42036 from BerriAI/litellm_team_membership_lookup_fail_closed
fix(auth): fail closed when the team membership lookup hits a db outage
2026-09-21 14:58:46 -07:00
yucheng-berri
79d6e236f9
Merge pull request #39805 from BerriAI/litellm_mcp_admin_api_preserve_oauth_scopes
fix(mcp): keep oauth scopes in admin api credential redaction
2026-09-21 14:29:13 -07:00
Joshua Valluru
ef67412e50 fix(mcp): keep OAuth prefetch failure logs free of caller data 2026-09-21 13:13:20 -07:00
joshua-berri
3549143bcd
Merge pull request #34919 from BerriAI/litellm_fix_mcp_peek_utf8_boundary
fix(mcp): handle split UTF-8 routing previews
2026-09-21 19:56:50 +00:00
Joshua Valluru
e208b4e89e fix(mcp): keep explicit legacy sampling callers isolated 2026-09-21 12:40:12 -07:00
Joshua Valluru
d2f30a77fd test(mcp): preserve toolset scope across explicit context 2026-09-21 12:31:48 -07:00
Joshua Valluru
a835e75620 fix(mcp): handle split UTF-8 routing previews in place 2026-09-21 12:24:19 -07:00
Joshua Valluru
1098604ed6 refactor(mcp): extract explicit operation context and dispatch 2026-09-21 12:24:15 -07:00
Joshua Valluru
bf5dff8986 chore: sync MCP UTF-8 fix with main 2026-09-21 12:15:57 -07:00
Joshua Valluru
1499d84f5a fix(mcp): paginate optional discovery lists 2026-09-21 11:37:55 -07:00
yassin
31caa98a41 Merge remote-tracking branch 'origin/main' into litellm_agent_access_groups
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

# Conflicts:
#	tests/test_litellm/proxy/auth/test_auth_checks.py
2026-09-20 08:52:45 +00:00
yassin
f9244749e0 fix(proxy): return 422 instead of 429 for BudgetExceededError
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-20 06:00:06 +00:00
mateo-berri
a3e9ed34fe fix(mcp): gate the pre-call listing per tool, not per server
A tools/call on a cold worker listed the target server once and then never
again, so a later caller whose credentials expose a wider upstream catalog
got 404 for tools the first caller never had. Gate the pre-call listing on
whether this worker already exposes the requested tool, so callers with
different catalogs no longer mask each other. Removing the per-server guard
also drops the empty-listing case that re-listed on every call.
2026-09-19 19:29:33 -07:00
mateo-berri
92ff54f134 fix(mcp): list a never-listed server before its first tools/call
The startup tool-name fill skips servers whose upstream wants the caller's
own token (true_passthrough, OAuth discovery), and mcp 2 no longer runs the
list handler before an uncached tools/call, so every uvicorn worker that had
not served tools/list answered 404 "Tool not found" for prefixed tools/call
and the REST server_id route on those servers.

On a resolution miss, execute_mcp_tool now lists the prefix-matched (or
server_id-requested) server once, with the caller's credentials, through the
existing tools/list path, then resolves as before. Listing failures fall
through to the existing 404, a worker that already listed the server never
re-lists it, and a server outside the caller's allowed set is never listed.
2026-09-19 18:49:26 -07:00
mateo-berri
b3b280d463 test(auth): model the membership row read in the fakes the loader now reaches 2026-09-19 16:32:22 -07:00
Yucheng He
e768f25983 test(mcp): cover lazy discovery and empty configured scopes 2026-09-19 14:24:05 -07:00
mateo-berri
854f5d959e Merge remote-tracking branch 'origin/main' into litellm_org_alias_from_team 2026-09-19 12:55:15 -07:00
ryan
84e56a60d2 Merge remote-tracking branch 'origin/main' into litellm_org_alias_from_team 2026-09-19 08:48:37 +00:00
Joshua Valluru
f5ab563499 fix(mcp): preserve session expiry signals and scope dependency CI 2026-09-18 22:52:10 -07:00
Joshua Valluru
aea13ee03b fix(mcp): preserve legacy behavior on SDK2 and streamline verification 2026-09-18 22:28:31 -07:00
Mateo Wang
078a60478f
Merge pull request #41485 from BerriAI/litellm_jwt_token_exchange_grant
feat(proxy): add RFC 8693 token exchange for IdP JWTs on the gateway token endpoint
2026-09-18 21:27:20 -07:00
jesus
3301fdafaf Merge remote-tracking branch 'origin/main' into litellm_org_alias_from_team 2026-09-19 00:48:54 +00:00
mateo-berri
50629ff5ca Merge branch 'main' of https://github.com/BerriAI/litellm into litellm_jwt_token_exchange_grant
# Conflicts:
#	tests/test_litellm/proxy/auth/test_auth_checks.py
2026-09-18 17:30:38 -07:00
Yucheng He
362d99e001 fix(mcp): keep discovered scopes out of saved settings 2026-09-18 17:23:31 -07:00
joshua
7410d00d2e merge(main): resolve mcp server.py import conflict and relock
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-19 00:08:33 +00:00
jesus
82e3f3980d refactor(auth): resolve org identity through an auth_checks helper
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 23:59:33 +00:00
joshua
8d8efe7203 style(mcp): satisfy lint and type budgets for the SDK 2 port
Format the ported files, annotate mutable wire payloads, give the e2e
OAuth client the SDK 2 httpx2/AuthorizationCodeResult API, tighten the
transport-streams alias to the two-stream SDK 2 shape, and add a
test-quality reason for the MockTransport factory injection.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 23:49:23 +00:00
joshua
0d2963fe89 test(mcp): update MCP suites for SDK2 handler signatures and ctx var
Call handlers with ServerRequestContext and params models, seed the
litellm contextvar instead of the removed SDK request_ctx, forward
headers/auth through the httpx2 MockTransport factory, and add
regressions for handler registration, context propagation, and modern
protocol-version rejection.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 23:34:30 +00:00
yassin
2231a3ca43 feat(mcp): give each allowed MCP client an alias and a value
mcp_allowed_clients entries become {alias, value} objects: the value is what the JWT claim or header must equal, the alias is the name the dashboard and logs show. The Network Settings section is renamed Allowed Clients with one alias/value row per client

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 22:29:17 +00:00
joshua
545bbeb001 test(mcp): update MCP suites for SDK 2 APIs
Rename McpError/isError/inputSchema-style references to the SDK 2
spellings, parse the JSONRPCMessage union with a TypeAdapter, and drive
the SDK transports off httpx2 MockTransport injection where respx can no
longer intercept. Adjust for SDK 2 behavior: the initialize handshake
negotiates handshake-era protocol versions only, an empty SSE stream
surfaces CONNECTION_CLOSED, non-2xx tool responses surface INTERNAL_ERROR
MCPError instead of HTTPStatusError, and the SDK read timeout carries the
JSON-RPC REQUEST_TIMEOUT code.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 22:13:18 +00:00
yassin
cca7ab8b1b test(mcp): type the REST allowlist test stubs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 21:50:16 +00:00
yassin
0536fb3062 fix(mcp): fail closed on empty JWT claims and gate the REST tool routes on mcp_allowed_clients
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 21:29:59 +00:00
Yucheng He
f59cd303c6 fix(mcp): preserve scopes through admin server edits 2026-09-18 14:14:28 -07:00
jesus
96dc32ddcf Merge remote-tracking branch 'origin/main' into litellm_org_alias_from_team 2026-09-18 20:58:38 +00:00
yassin
9917375d4b Merge remote-tracking branch 'origin/main' into litellm_mcp_client_allowlist
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

# Conflicts:
#	litellm/proxy/_experimental/mcp_server/server.py
2026-09-18 20:46:50 +00:00
yassin
fe8cf02823 feat(mcp): resolve the allowlisted client identity from the JWT claim or an opt-in header instead of clientInfo.name
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 19:27:43 +00:00
yassin
c5919a3c0e Merge remote-tracking branch 'origin/main' into litellm_mcp_client_allowlist
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

# Conflicts:
#	litellm/proxy/_experimental/mcp_server/server.py
#	litellm/proxy/proxy_server.py
2026-09-18 19:01:08 +00:00
yassin
ce48a3fbcc test(mcp): give the new cache and tombstone patches TQ008 reasons and match the keyword eviction call
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 02:49:41 +00:00
yassin
fd834f6f8b fix(mcp): broadcast BYOK and OAuth credential eviction to peer workers and expire admin session tombstones
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 02:10:50 +00:00
yassin
ea37596b88 feat(mcp): let proxy admins force-close live MCP sessions and revoke stored user credentials
Adds an admin-only DELETE /v1/mcp/sessions that terminates stateful MCP gateway sessions on the current worker by session id prefix and/or by the LiteLLM user that opened them, tombstones the terminated ids so a client reusing one gets 404 instead of a silently recreated stateless session, and lets PROXY_ADMIN name a user_id on the BYOK and OAuth credential delete routes. Full and view-only admins can list every user's stored credential metadata for a server (never the secret). The dashboard gains Disconnect controls on the Live Connections tab and a User Credentials tab with Revoke controls, both hidden from read-only admins.

Resolves LIT-8001

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 01:01:26 +00:00
mateo-berri
788e6eb737 merge: origin/main into litellm_jwt_token_exchange_grant 2026-09-17 17:59:23 -07:00
mateo-berri
82d252210e fix(proxy): word the token exchange's 503 by whether the database fault can clear
A permanent database fault (a missing or version-skewed query engine)
in the subject_token check was answered with the same "retry" wording
as a transient outage. The status stays 503 temporarily_unavailable,
the only OAuth error a client reads as the server's fault and what the
mint path already answers to the same fault, but the description now
says retrying will not help until the deployment is repaired, using
PrismaDBExceptionHandler.is_permanent_database_fault the way the mint
path does.
2026-09-17 17:20:17 -07:00
Joshua Valluru
3519d01549 test(mcp): add isolated SDK2 dependency compatibility gate 2026-09-17 17:16:47 -07:00
mateo-berri
8e3742a5f3 fix(proxy): answer 503 temporarily_unavailable when the token exchange cannot verify the subject token
Some checks are pending
LiteLLM Rust / rust-lint (push) Waiting to run
LiteLLM Rust / rust-test (push) Waiting to run
LiteLLM Rust / rust-wheel (push) Waiting to run
A subject token JWT auth could not check, because the IdP's JWKS was unreachable with no cached copy or the auth database was down, came back as 400 invalid_request with the same fixed message a bad token gets, so clients re-logged in instead of retrying the way they already do for a mint-time 503. Those checks now answer 503 temporarily_unavailable and log the reason, while real rejections stay 400 invalid_request.
2026-09-17 16:39:02 -07:00
yassin
33531649c3 perf(mcp): count gateway session groups with Counter and pin the oversized initialize peek invariant
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 23:20:47 +00:00
yassin
c230393731 fix(mcp): refuse sessionless and stale-session POSTs that skip initialize while mcp_allowed_clients is set
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 23:18:54 +00:00
jesus
1b69a5b0a4 test(proxy): model missing organizations in MCP auth fixtures
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 22:34:02 +00:00