Commit graph

1501 commits

Author SHA1 Message Date
Cursor Agent
0b4a6b2679 feat: Add MCP configuration review and invocation logs for troubleshooting
Backend:
- Add call_type and mcp_tool_name filters to /spend/logs/ui endpoint
- Add GET /v1/mcp/server/{server_id}/logs endpoint for per-server invocation logs
- Add GET /v1/mcp/server/{server_id}/diagnose endpoint for connection diagnostics

Frontend:
- Add 'Logs' tab to MCP Server detail view showing invocation history
- Add 'Diagnostics' tab showing pass/fail checks for config, auth, connectivity, network
- Add 'Call Type' filter to main Logs page (MCP Tool Call, Completion, etc.)
- Add fetchMCPServerLogs and fetchMCPServerDiagnostics networking functions

Tests:
- Add 5 Python tests for new backend endpoints (logs + diagnostics)
- Add 9 Vitest tests for new UI components (logs + diagnostics)

Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
2026-03-07 08:34:45 +00:00
yuneng-jiang
39c5adcff1
Merge pull request #23019 from BerriAI/litellm_redis_txn_buffer_check
[Fix] Block proxy startup when use_redis_transaction_buffer has no Redis
2026-03-06 22:01:37 -08:00
yuneng-jiang
9d9a59190c Use passed general_settings parameter instead of global import
The validation method now reads use_redis_transaction_buffer directly
from the passed general_settings dict rather than delegating to
RedisUpdateBuffer._should_commit_spend_updates_to_redis() which
imports the global. Tests simplified to remove unnecessary patching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:30:52 -08:00
yuneng-jiang
3a15e1cc2e [Fix] Block proxy startup when use_redis_transaction_buffer is enabled without Redis cache
When `use_redis_transaction_buffer: true` is set in general_settings but no
Redis cache is configured in litellm_settings, the proxy starts successfully
but silently drops all spend tracking data. This adds a startup validation
that raises a clear error, preventing the proxy from running in a broken state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:24:49 -08:00
yuneng-jiang
4eee2b752d
Merge pull request #23011 from BerriAI/litellm_key-aliases-internal-user
[Fix] Internal Users Cannot Access Key Aliases on Request Logs Page
2026-03-06 21:23:22 -08:00
yuneng-jiang
b314e8d20a
Merge pull request #20688 from BerriAI/litellm_budget_tier_enforcement_for_keys
[Fix] Budget-linked keys never had spend reset
2026-03-06 20:44:58 -08:00
Krish Dholakia
ff8e01d20b
feat: Add Canadian PII protection (PIPEDA) (#22951)
* feat: Add Canadian PII protection patterns and PIPEDA-compliant policy template

Adds 6 new Canadian PII regex pattern detectors to patterns.json:
- ca_sin: Social Insurance Number (PIPEDA Privacy Act, Income Tax Act)
- ca_ohip: Ontario Health Insurance Plan Number (PHIPA)
- ca_on_drivers_licence: Ontario driver's licence (HTA, PIPEDA)
- ca_immigration_doc: IRCC immigration docs (UCI, work/study permits, IMM refs)
- ca_bank_account: Canadian bank account routing (transit-institution-account)
- ca_postal_code: Canadian postal code (Canada Post spec)

Adds comprehensive policy template 'canadian-pii-protection' (id: canadian-pii-protection)
with 5 sub-guardrails grouping patterns by data type. All patterns include contextual
keyword matching (English + French keywords where applicable) to reduce false positives.
Complements existing passport_canada pattern.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* feat: Add Canadian PII compliance dataset and tests (57 tests)

Adds:
- test_ca_patterns.py: 30 unit tests for regex pattern matching (SIN, OHIP,
  driver's licence, immigration docs, bank account, postal code)
- test_ca_policy_e2e.py: 27 end-to-end tests running the full
  ContentFilterGuardrail pipeline with MASK action — validates detection
  of real PII and pass-through of clean prompts
- canadianPiiCompliancePrompts.ts: 21-prompt compliance dataset for UI
  evaluation, wired into the main compliancePrompts framework

Fixes keyword_pattern alternation ordering in patterns.json — longer
alternatives (e.g. "social insurance number") now precede shorter ones
("social insurance") to avoid excessive gap-word count when the regex
engine selects the shorter match first.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* feat: Add University of Toronto FIPPA identifier patterns and tests (36 tests)

Add 3 UofT institutional identifiers (student/employee number, UTORid, TCard)
covered under Ontario FIPPA. Includes pattern definitions, policy template
sub-guardrail, compliance prompts, unit tests, and e2e tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Correct test assertion bug and inaccurate docstring

Fix test_utorid_masked checking `result` (dict) instead of `output` (string).
Update test_ca_policy_e2e.py docstring to clarify scope vs UofT tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Address Greptile review feedback

- Tighten ca_postal_code keyword_pattern: replace broad "address" with
  specific compound terms (mailing/street/shipping/home address)
- Add missing "PIPEDA" tag to policy_templates.json for discoverability
- Add us_phone pattern to test_ca_policy_e2e.py setup to match deployed template
- Add phone number e2e test for complete coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Tighten patterns to reduce false positives and add missing test coverage

- ca_sin: reject leading-zero SINs ([1-9]\d{2}), set allow_word_numbers to false
- ca_immigration_doc: require separators in UCI pattern (prevent bare \d{10} match)
- uoft_utorid: qualify generic keywords (acorn -> acorn login, quercus -> quercus login)
- uoft_tcard: remove generic keywords (student card, id card, library card) that
  overlap with credit card contexts; keep only UofT-specific terms (tcard, campus card)
- Add visa/mastercard/amex/iban patterns to test_ca_policy_e2e.py setup to match
  deployed template; add Visa card masking test
- Add test verifying "student card" no longer triggers TCard redaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-06 18:27:31 -08:00
yuneng-jiang
12005c4a02 Fix /key/aliases auth for internal users and scope results by role
Internal users were blocked from accessing /key/aliases because the route
was missing from key_management_routes. Added the route and scoped query
results so non-admin users only see aliases for their own keys and their
teams' keys, matching /key/list behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:20:10 -08:00
Ishaan Jaff
b7b20664c1
Gflags worker parameters (#22931)
* feat: add LITELLM_WORKER_STARTUP_HOOKS for per-worker initialization (gflags support)

Add support for running user-defined startup hooks in each worker process
during proxy_startup_event. This enables re-initialization of in-process
state (like gflags.FLAGS) that doesn't survive uvicorn worker spawning.

Usage:
  export LITELLM_WORKER_STARTUP_HOOKS=mymodule:init_fn,other:setup_fn

Hooks run early in proxy_startup_event (before config/DB loading).
Supports both sync and async callables. Errors propagate to prevent
broken workers from serving traffic. No-op when env var is unset.

Includes 5 tests covering sync/async hooks, multiple hooks, error
propagation, and no-hooks-set scenarios.

Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>

* docs: add Worker Startup Hooks page with gflags usage example

- New docs page: docs/proxy/worker_startup_hooks.md
  - Explains the problem (per-process state lost in multi-worker deployments)
  - Full gflags example with wrapper module and startup script
  - Covers multiple hooks, async hooks, error behavior
  - Architecture diagram showing master→worker flow
- Added LITELLM_WORKER_STARTUP_HOOKS to config_settings.md env var table
- Added to sidebar under Setup & Deployment

Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>

* Update litellm/proxy/proxy_server.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-06 18:09:57 -08:00
Ishaan Jaff
bb52b0b6b0
fix(mcp): resolve $ref params and path-level params in OpenAPI spec parsing (#22952)
* fix(mcp): resolve \$ref params and merge path-level params in OpenAPI tool registration

Real-world OpenAPI specs (e.g. GitHub's 11.8 MB official spec) use two
patterns that crashed tool registration:

1. \$ref parameters: params defined as {"$ref": "#/components/parameters/foo"}
   instead of inline objects. Accessing param["name"] on a $ref raises KeyError.
   Fix: resolve each param against components/parameters before processing.

2. Path-level parameters: params defined on the path object apply to all
   HTTP methods on that path, but the operation object doesn't include them.
   GitHub's spec uses this for owner/repo/etc. path params.
   Fix: merge path-level params with operation-level params (op-level wins
   when the same name+in combination appears in both).

With this fix the full GitHub REST API spec loads successfully:
720 paths → 1079 tools, all with correct parameter schemas.

* fix(mcp): resolve \$ref params in OpenAPI preview endpoint (test/tools/list)

The _preview_openapi_tools function (called by the UI add-server form to show
connection status and available tools) had the same bug as _register_openapi_tools:
it accessed param["name"] directly without resolving \$ref parameters or merging
path-level parameters from the path item.

This caused "Failed to load OpenAPI spec: 'name'" for any spec that uses
component-level parameter references (e.g. GitHub's official REST API spec).

Apply the same fix: resolve \$ref against components/parameters and merge
path-level params (with operation-level taking priority) before building schemas.

* refactor(openapi-mcp): extract resolve_operation_params, add tests

- Hoist _resolve_ref and _resolve_param_list to module level in
  openapi_to_mcp_generator.py (were being redefined on every loop iteration)
- _resolve_ref now returns None for unresolvable $refs instead of
  the stub dict, preventing (None, None) from poisoning deduplication
- Add resolve_operation_params() as a shared helper that handles both
  $ref resolution and path-level param merging
- Replace duplicated inline logic in mcp_server_manager.py and
  rest_endpoints.py with calls to resolve_operation_params()
- Add TestResolveRef, TestResolveParamList, TestResolveOperationParams
  test classes covering $ref resolution, path-level merging, collision
  semantics, unresolvable ref filtering, and a GitHub-style spec fixture
2026-03-06 18:02:48 -08:00
yuneng-jiang
c2b03c15b9
Merge pull request #22939 from BerriAI/litellm_hashicorp_vault_backend
feat: Hashicorp Vault config override backend endpoints
2026-03-06 17:59:46 -08:00
v0rtex20k
c64140e4c5
[Feat[ extends OAuth2 M2M authentication support to info routes (/key/info, /team/info, /user/info, /model/info) (#22713)
* added info_route

* greptile pt1

* greptile pt2

* greptile pt3
2026-03-06 17:29:25 -08:00
hliu-roblox
07ac97aff4
feat(key_management): allow @ in key_alias for email-based aliases (#23003)
Adds @ to the _KEY_ALIAS_PATTERN allowed character set so that
key aliases like user/user@example.com are accepted. Updates tests
to cover email-based alias formats.
2026-03-06 17:24:42 -08:00
Sameer Kankute
8b0375f99c
Merge pull request #22888 from BerriAI/litellm_a2a-custom-headers
[Feat] Add a2a custom headers
2026-03-06 18:24:21 +05:30
Sameer Kankute
159c477c18 feat(proxy): client-side provider API key precedence for Anthropic /v1/messages
- Add forward_llm_provider_auth_headers support from litellm_settings
- When enabled, client x-api-key takes precedence over deployment keys
- Forward x-api-key when x-litellm-api-key or Authorization used for auth
- Fix duplicate patch lines in test_byok_oauth_endpoints.py
- Add Claude Code BYOK documentation with /login and ANTHROPIC_CUSTOM_HEADERS
- Add unit tests for clean_headers x-api-key forwarding logic
- Sync model_prices backup (pre-commit hook)

Made-with: Cursor
2026-03-06 18:20:46 +05:30
yuneng-jiang
8523bb6b48
Merge pull request #22956 from BerriAI/litellm_key_null_duration
[Fix] Key Expiry Default Duration
2026-03-05 21:06:55 -08:00
yuneng-jiang
e468b0278f [Fix] Key Expiry Default Duration - support null to never expire
Support passing duration=null on /key/update to reset a key's expiry to never expires, alongside the existing "-1" magic string (kept for backward compat).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 20:54:30 -08:00
yuneng-jiang
99c4f3cbea
Merge pull request #22938 from BerriAI/litellm_fix_team_usage_spend
[Fix] Team Usage Spend Truncated Due to Pagination
2026-03-05 20:45:27 -08:00
ryan-crabbe
11f83ff522
Merge branch 'main' into litellm_hashicorp_vault_backend 2026-03-05 17:27:33 -08:00
yuneng-jiang
d0e480414c Fix team usage spend showing lower than expected values
The /team/daily/activity endpoint used Prisma pagination (page_size=1000)
but the UI only fetched page 1. Teams with many keys/models easily exceed
1000 rows in LiteLLM_DailyTeamSpend, causing truncated totals.

Switches the endpoint to use SQL GROUP BY via get_daily_activity_aggregated
with include_entity_breakdown=True, returning all data in a single response
while preserving per-team breakdown. Also adds timezone parameter support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:00:51 -08:00
Krish Dholakia
53a1e31729
feat(spend-logs): add truncation note when error logs are truncated for DB storage (#22936)
When the messages or response JSON fields in spend logs are truncated
before being written to the database, the truncation marker now includes
a note explaining:
- This is a DB storage safeguard
- Full, untruncated data is still sent to logging callbacks (OTEL, Datadog, etc.)
- The MAX_STRING_LENGTH_PROMPT_IN_DB env var can be used to increase the limit

Also emits a verbose_proxy_logger.info message when truncation occurs in
the request body or response spend log paths.

Adds 3 new tests:
- test_truncation_includes_db_safeguard_note
- test_response_truncation_logs_info_message
- test_request_body_truncation_logs_info_message

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-03-05 16:58:46 -08:00
Ryan Crabbe
21718d208d feat: Hashicorp Vault config override backend endpoints
Add CRUD endpoints for managing Hashicorp Vault configuration via the
proxy admin API, with background sync, env var management, and
connection testing. Fix pre-existing bug where premium check ran after
global state mutation, and guard DELETE against clearing non-Vault
secret managers.
2026-03-05 16:57:08 -08:00
yuneng-jiang
92b3160206
Merge pull request #22858 from BerriAI/litellm_rbac_vector_agents
[Feature] RBAC for Vector Stores and Agents
2026-03-05 16:40:38 -08:00
yuneng-jiang
05d2ccdf56 [Fix] PATCH /update/ui_settings now merges with existing record instead of overwriting
Previously, model_dump(exclude_none=True) included all bool fields (since
False != None), causing a partial PATCH to overwrite every other setting to
its default. Fix uses exclude_unset=True and reads the existing DB record
before merging, giving proper PATCH semantics.

This was a pre-existing bug but is fixed here since we're touching this code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:49:40 -08:00
Curtis
725c0c158f
Prisma DB Failure Detection and Self-Healing (#21059)
* fix(proxy): readiness check returns 200 when database is unreachable

_db_health_readiness_check() catches health_check() exceptions but
never updates db_health_cache to "disconnected" and never re-raises.
The caller health_readiness() always returns 200 with "db": "connected"
hardcoded, regardless of actual DB state.

In Kubernetes, this means pods with dead database connections stay in
the Service endpoints and continue receiving traffic they cannot serve.

Changes:
- Set db_health_cache to "disconnected" and re-raise the exception on
  health_check failure so health_readiness() returns 503
- Use actual db_health_status["status"] in the response instead of
  hardcoding "db": "connected"
- Reduce cache TTL from 2 minutes to 15 seconds. The 2-minute window
  is too wide for readiness probes (typically 10-15s intervals) and
  means a pod can report healthy for up to 2 minutes after the DB dies
- Only serve cached results when status is "connected". The previous
  condition (status != "unknown") would also cache "disconnected" for
  2 minutes, delaying recovery detection after a DB comes back

* fix(proxy): add DB connection self-healing to readiness check

When the Prisma query engine's internal TCP connection pool holds dead
connections (caused by network blips, Cloud SQL proxy restarts, or
node-level issues), health_check() fails with httpx.ConnectError.
The engine never recovers on its own because nothing triggers a
disconnect/connect cycle to restart the subprocess with fresh
connections.

This leaves pods permanently failing readiness checks until they are
manually restarted, even after the underlying DB becomes reachable
again.

Add a reconnect attempt to _db_health_readiness_check() when
health_check() fails:
1. disconnect() - kills the query engine subprocess and closes all
   connections (has built-in backoff retry: 3 tries, 10s max)
2. connect() - starts a new engine with fresh TCP connections (has
   built-in backoff retry: 3 tries, 10s max)
3. health_check() - verifies the new connection works (has built-in
   backoff retry: 3 tries, 10s max)

If reconnect succeeds, the pod immediately returns to service (200).
If it fails, the original exception is re-raised (503). Reconnect
attempts are rate-limited by probe frequency (~10-15s), so a
permanently unreachable DB gets one attempt per cycle with no retry
loops.

This uses the same disconnect/connect mechanism that
PrismaWrapper.recreate_prisma_client() uses for IAM token refresh,
and aligns with the community-documented pattern for Prisma connection
recovery in long-running processes (prisma/prisma#24718, #27024).

* Add poetry lock and modify test_health_endpoints

* Address allow_requests_on_db_unavailable regression

* Address comments

* resolve greptile issue

* Restore accidentally deleted UI HTML files

These were removed in an earlier commit but still exist on main.
Restoring to keep the PR diff clean.

* Guard reconnect with is_database_transport_error

Only attempt disconnect/connect/health_check cycle for transport-level
failures (unreachable DB, dropped connection). Data-layer errors like
UniqueViolationError indicate the DB is reachable, so reconnecting
would be pointless churn.

* Address greptile's comments

* Fix module alias after rebase and add adversarial test coverage

- Unify module alias to _health_endpoints_module after rebase conflict
- Add test for non-transport error with flag on (exercises is_database_transport_error guard)
- Add test for disconnect() failure during reconnect cycle
- Split non-transport error test into flag-off (re-raises) and flag-on (skips reconnect) variants

* Remove stale UI HTML files reintroduced during rebase
2026-03-05 13:44:49 -08:00
Spencer Burridge
c919031ff0
feat(proxy): include user_email in jwt upsert user creation (#22915)
* Include user_email in new user creation within get_user_object

Enhance the get_user_object function to include user_email in the parameters when creating a new user. This change is accompanied by a new test to verify that user_email is correctly included during the upsert process.

* Improve error handling in test_get_user_object by logging exceptions

Updated the test_get_user_object_upsert_includes_user_email function to log exceptions when they occur, enhancing the visibility of potential issues during testing. This change helps in diagnosing failures related to the mock LiteLLM_UserTable.
2026-03-05 10:55:11 -08:00
Sameer Kankute
501671aa43 fix(agents): PUT update_agent_in_db clears static_headers and extra_headers when omitted
For full-replace PUT semantics, always include static_headers and extra_headers
in update_data, defaulting to {} and [] when not supplied. Previously,
omitting these fields left stale DB values intact (e.g. auth headers).

Made-with: Cursor
2026-03-05 16:16:21 +05:30
Sameer Kankute
594499e806 Add tests 2026-03-05 15:14:45 +05:30
Sameer Kankute
fd53678898 test(agents): add tests for A2A custom header forwarding
Covers:
- Static headers forwarded to backend
- Dynamic headers extracted by name (extra_headers config)
- Convention-based x-a2a-{agent_id/name}-{header} forwarding
- Static headers win over dynamic on conflict
- Unrelated x-a2a- prefixes are not forwarded
- No-header case leaves existing behaviour unchanged
- merge_agent_headers utility unit tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 14:28:48 +05:30
Ishaan Jaff
1bb713bc7b
feat(mcp): BYOK MCP servers with OAuth 2.1 PKCE authorization flow (#22850)
* feat(mcp): BYOK (Bring Your Own Key) for OpenAPI MCP servers with OAuth 2.1 flow

Adds per-user credential storage for BYOK MCP servers so external clients
can authenticate via standard OAuth 2.1 PKCE without needing a full identity
provider.

Backend:
- New DB table LiteLLM_MCPUserCredentials (user_id, server_id, credential_b64)
- is_byok, byok_description, byok_api_key_help_url fields on MCPServerTable
- OAuth 2.1 authorization server endpoints (/.well-known/oauth-authorization-server,
  /.well-known/oauth-protected-resource, /v1/mcp/oauth/authorize, /v1/mcp/oauth/token)
- 401 challenge with WWW-Authenticate header when BYOK server has no credential
- CRUD endpoints: POST/DELETE /v1/mcp/server/{id}/user-credential
- has_user_credential annotated on GET /v1/mcp/server response

UI:
- ByokCredentialModal: 2-step Connect flow (access description + API key entry)
- BYOK toggle + description fields on admin MCP server create form
- Connect/Connected state in MCP server table
- BYOK Demo page (/tools/byok-demo) showing full OAuth 2.1 PKCE flow

* feat(mcp/byok): redesign OAuth authorize page to match 2-step Connect mockup

- Step 1: L→S logos, requested access checklist, How it works box, Continue button
- Step 2: API key input, Save toggle, Duration pills (1h/24h/7d/30d/until_revoked), security note
- Matches screenshots: white modal on dark bg, progress dots, dark CTA buttons
- Authorize handler now fetches byok_description and byok_api_key_help_url from server registry
- CLAUDE.md: replace SQL snippet with proper DB migration troubleshooting guidance

* fix: address greptile review feedback (greploop iteration 1)

- XSS: escape all user-supplied values in _build_authorize_html() with html.escape()
- Open redirect: validate redirect_uri scheme and URL-encode code/state in redirect
- N+1 query: batch BYOK credential lookup into single find_many() call
- Critical path DB: add 60s TTL in-memory cache to _check_byok_credential()
- Encrypt BYOK credentials at rest using encrypt_value_helper/decrypt_value_helper

* fix(byok): update OAuth popup with LiteLLM logo, MCP title suffix, remove emojis

* fix(byok-demo): fix token endpoint URL (/v1/mcp/oauth/token not /v1/mcp/token)

* feat(byok): inject stored BYOK credential as mcp_auth_header on tool execution

* feat(byok): use contextvars to inject per-user credential into OpenAPI tool closures; remove byok-demo from LiteLLM UI

OpenAPI tools have auth headers baked into their closures at registration time. BYOK servers have
no static auth token, so per-user credentials were never reaching the HTTP calls.

Fix: add _request_auth_header ContextVar in openapi_to_mcp_generator.py. create_tool_function now
reads this var at call time and overrides the Authorization header if set. execute_mcp_tool resolves
the MCP server and performs BYOK checks before the local-tool dispatch branch, then sets the
ContextVar around _handle_local_mcp_tool so the credential flows into the HTTP request.

Also remove the /tools/byok-demo page from the LiteLLM UI dashboard — the demo lives at
~/Downloads/litellm-byok-demo/index.html (served separately on port 8080).

* fix: address greptile review feedback (greploop iteration 2)

- Cache invalidation: add _invalidate_byok_cred_cache() and call it after
  store_user_credential() in both token endpoint and management endpoint
- Unbounded cache: add _BYOK_CRED_CACHE_MAX_SIZE=4096 with clear-on-overflow
- Unbounded auth codes: add _AUTH_CODES_MAX_SIZE=1000 with 503 on overflow
- Double DB query: merge _check_byok_credential + _get_byok_credential into
  single _get_byok_credential call; raise 401 inline if None returned
- Sidebar: remove byok-demo entry (page was deleted in prior commit)
- JWT comment: document why byok_session HS256 token can't be used as proxy auth

* fix: address greptile review feedback (greploop iteration 3)

- auth_type: pre-format Authorization header (Bearer/ApiKey/Basic) in server.py
  before setting ContextVar so openapi_to_mcp_generator respects server auth_type
- cache invalidation on delete: call _invalidate_byok_cred_cache after
  delete_user_credential so stale True entries don't persist for 60s
- ContextVar guard: only set _request_auth_header when mcp_auth_header is set,
  avoiding unnecessary ContextVar overhead on non-BYOK tool calls

* fix: address greptile review feedback (greploop iteration 4)

- Unified credential cache: store actual credential value (Optional[str])
  instead of just bool so _get_byok_credential also benefits from caching —
  eliminates the DB hit on every BYOK tool call within the 60s TTL window
- Extracted _write_byok_cred_cache() helper for consistent cache writes
- Replaced has_user_credential with get_user_credential in _check_byok_credential
  so one DB call satisfies both existence check and value retrieval
- Remove false 'encrypted at rest' claim from OAuth HTML and ByokCredentialModal

* Update tests/test_litellm/proxy/_experimental/mcp_server/test_byok_oauth_endpoints.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update tests/test_litellm/proxy/_experimental/mcp_server/test_byok_oauth_endpoints.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-04 21:19:25 -08:00
Ishaan Jaff
9897df5089
feat(mcp): allow admins to override tool name and description per MCP server (#22828)
* feat(mcp): add tool_name_to_display_name and tool_name_to_description overrides for MCP servers

* docs(mcp): add mcp_openapi.md with OpenAPI→MCP guide and tool override section

* docs(mcp): add sequential UI screenshots to mcp_openapi.md

* fix(mcp): apply tool overrides after permission filtering; reverse-map display names in tools/call
2026-03-04 17:58:05 -08:00
Miguel Armenta
750fc4a980
azure content enhancement... (#22581)
* azure content enhancement...

* rafactored to increase confidence score

* improvements based on additional feedback

* removed unused import

* Force-split any word longer than max length allowed

* preserve whitespace in text splitting

* moving common initialization to base class

* consolidate enforcement into async_make_request as single point, remove redundant caller-side checks, extract shared init/HTTP logic into base, and fix stale log messages

* clean up

* clean up tests
2026-03-04 10:22:30 -08:00
ryan-crabbe
0df36582de
Merge pull request #22728 from BerriAI/litellm_batch_expiry_validation_followup
fix(proxy): improve team expiry enforcement validation
2026-03-04 10:16:02 -08:00
Julio Quinteros Pro
1ec6502f88 Fix tool management tests using wrong field name call_policy
Tests used call_policy throughout but the actual API model uses
input_policy and output_policy. Updated _make_tool_row helper,
list filter query param, and policy update request/response assertions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:20:17 -03:00
Harshit Jain
41b149ee93
Merge pull request #22678 from Harshit28j/litellm_custom_auth_opt_in
fix(proxy): make common_checks opt-in for custom auth
2026-03-04 14:53:44 +05:30
Ishaan Jaff
7befe3c78f
feat(proxy): add key_alias, key_hash, requested_model DD APM span tags (#22710)
* feat(proxy): add key_alias, key_hash, requested_model tags to DD APM spans

* refactor(proxy): consolidate DD APM tag helpers into DDSpanTagger class

* refactor(proxy): move DDSpanTagger to its own file litellm/proxy/dd_span_tagger.py
2026-03-03 20:22:59 -08:00
Ishaan Jaff
1f412bc6d8
[Feat] Add Tool Policies for AI Gateway (#22732)
* fix: fix ui render

* fix: fix minor bugs

* refactor: use prisma functions instead of raw sql (safer)

* fix(add-new-tiles-to-tool-policies): allow developer to see what's available

* feat: ensure tool allowlist runs correctly for tool names + mcp's

* refactor: more ui improvements

* feat: working key tool blocking

* feat(tools): show tool logs

* refactor: backend code improvements

* refactor: improve log viewer for tools

* fix: address PR review feedback for tool access control

- Add missing blocked_tools column to root schema.prisma (schema drift)
- Invalidate ToolPolicyRegistry after policy mutations so changes take effect immediately
- Remove dead code: unused get_effective_policies, get_tool_policies_cached, and helpers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: race condition in permission resolution and remove duplicate allowlist check

- Use atomic update_many with object_permission_id=None to prevent concurrent
  requests from creating orphaned permission rows and losing tool blocks
- Remove duplicate allowed_tools enforcement from guardrail (already enforced
  in auth layer via check_tools_allowlist)
- Move inline uuid import to module level

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update to account for  userAgent

* UI - Add ToolDetails

* input/output policy

* LiteLLM_PolicyAttachmentTable

* LiteLLM_PolicyAttachmentTable

* fix: add _enqueue_tool_registry_upsert

* fix: tool mgmt endpoints

* tool mgmt endpoints

* Update tests/test_litellm/proxy/db/test_tool_registry_writer.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update tests/test_litellm/proxy/db/test_tool_registry_writer.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update tests/test_litellm/proxy/db/test_tool_registry_writer.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: sync root schema.prisma and fix test_tool_registry_writer for input/output policy

- Migrate root schema.prisma LiteLLM_ToolTable from call_policy to
  input_policy/output_policy, add missing user_agent and last_used_at columns
  (now consistent with litellm/proxy/schema.prisma and litellm-proxy-extras)
- Fix SpendLogToolIndex comment across all three schema files
- Fix all call_policy references in test_tool_registry_writer.py:
  swapped update_tool_policy arguments, wrong get_tools_by_names return type
  assertions, _mock_tool_row setting call_policy instead of input_policy

Addresses Greptile review feedback on PR #22732.

Made-with: Cursor

---------

Co-authored-by: Krrish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-03 20:22:20 -08:00
Krish Dholakia
90eb6729d5
Agent Tracing - support context_id based trace id propogation + nested llm calls (#22626)
* style(ui/): distinguish agent calls from llm calls on ui

* feat: initial grouping working

* feat: set stable contextid for a2a calls - allows for easily passing to downstream llm/mcp calls

* feat(a2a_endpoints.py): fix tracing to avoid recreating logging objects for the same call

allows stable trace id usage

* fix(guardrail_endpoints): handle string ui_type values in _build_field_dict

_build_field_dict unconditionally called .value on ui_type, which crashes
for guardrail configs that use plain strings (e.g. BlockCodeExecutionGuardrailConfigModel
uses "multiselect" and "percentage"). Now checks with hasattr before calling .value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: propagate trace/session id from headers in MCP server calls

Cherry-picked mcp_server/server.py fixes from 6feb9bab: adds
get_chain_id_from_headers to extract x-litellm-trace-id /
x-litellm-session-id from raw headers, and uses it in call_tool
and list_tools to keep spend logs and tracing consistent with A2A.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 18:19:12 -08:00
Ryan Crabbe
52ec73c07d fix(proxy): improve team expiry enforcement validation
- Change status codes from 400 to 500 for team metadata misconfig errors
  (callers can't fix admin-set config, 400 is misleading)
- Add anchor value validation to batch endpoint (matching files endpoint)
- Coerce seconds to int to handle string values from metadata
- Add error-path tests: missing keys, invalid anchor, status code assertions
- Add happy-path test: team injects expiry when caller sends nothing
2026-03-03 17:29:39 -08:00
yuneng-jiang
ab101671c7
Merge pull request #22725 from BerriAI/litellm_team_admin_reset_spend
[Fix] Team Admin Reset Key Spend
2026-03-03 16:50:46 -08:00
yuneng-jiang
0a1b2635d7 fix: allow team admins to access /key/{key}/reset_spend route
The route-level auth check was blocking internal_user role (team admins)
from reaching /key/{key}/reset_spend because KEY_RESET_SPEND was missing
from key_management_routes. Added it so team admins pass the route check
and the endpoint's existing _check_proxy_or_team_admin_for_key enforces
actual authorization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:54:34 -08:00
milan-berri
98b9bc8b72
fix: resolve base_model in /cost/estimate for Azure custom deployments (#22724)
The _resolve_model_for_cost_lookup function was only checking
litellm_params.model when resolving model names from the router.
For Azure custom deployment names (e.g. azure/openai/gpt-5.3-codex),
this deployment name doesn't exist in the model cost map, so cost
returned /bin/zsh.

Now checks model_info.base_model and litellm_params.base_model first,
falling back to litellm_params.model only if no base_model is set.
This matches how the router resolves base_model everywhere else.
2026-03-03 15:43:02 -08:00
Julio Quinteros Pro
a07d041881 fix: apply same AsyncMock pattern to remaining OIDC discovery test
Address Greptile review: test_resolve_jwks_url_resolves_oidc_discovery_document
also used the inconsistent patch.object pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:56:51 -03:00
Julio Quinteros Pro
eb658693a3 fix: use direct AsyncMock assignment instead of patch.object in JWT tests
The patch.object with new_callable=AsyncMock can behave inconsistently
across Python versions, causing mock_response.status_code to return a
MagicMock instead of the assigned value. Direct assignment is simpler
and more reliable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:51:09 -03:00
ryan-crabbe
8aa7d53864
Merge pull request #22705 from BerriAI/litellm_feat_batch_expiry_setting_teams
Litellm feat batch expiry setting teams
2026-03-03 14:36:12 -08:00
Ryan Crabbe
08613b24cb feat(proxy): add team-level file expiry enforcement 2026-03-03 11:03:14 -08:00
Ryan Crabbe
3d15bcdb11 feat(proxy): add team-level batch output expiry enforcement 2026-03-03 10:58:31 -08:00
yuneng-jiang
4c1b15d685
Merge pull request #22687 from BerriAI/litellm_fix_spend_log_cleanup
[Fix] Spend Log Cleanup: lock tracking, integer retention, skip log level
2026-03-03 10:48:20 -08:00
Ryan Crabbe
43cec8c980 feat(batches): support output_expires_after passthrough 2026-03-03 10:46:45 -08:00
yuneng-jiang
224c617119 Fix spend log cleanup: lock tracking, integer retention, skip log level
- Only release distributed lock in finally if it was actually acquired;
  prevents spurious Redis release_lock calls on early returns
- Treat bare integer maximum_spend_logs_retention_period as days (e.g. 3 → "3d")
  instead of silently failing with a ValueError
- Elevate "Skipping cleanup" log from info to error so misconfigured
  retention settings are visible without verbose logging
- Add tests for all three fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 10:12:08 -08:00