Find a file
Yassin Kortam 0cb759772c
fix(ui): show indirectly granted and name-keyed MCP servers in the tool matrix (#35154)
* fix(ui): show indirectly granted and name-keyed MCP servers in the tool matrix

The MCP tool permission editor was fed the direct server list only, so a server a
principal reaches through an access group or a toolset never appeared in the matrix.
That single blind spot produced two opposite bugs depending on how a save handler
filtered mcp_tool_permissions: filtering by the selected servers deletes an indirect
server's allowlist, and because a missing entry means "no restriction from this
level", the principal silently gains every tool on it; not filtering leaves a stale
entry that keeps a removed access group's server reachable, since a server named
under mcp_tool_permissions is entitled on purpose.

The editor now resolves the selected access groups and toolsets to their servers and
renders them alongside the direct ones, badged with where the grant comes from, so an
admin can see and clear an inherited server's tools like any other. Resolution reuses
the data the selector already loads: access groups resolve from each server's
mcp_access_groups, toolsets from the toolset's own tool list. When that data cannot be
loaded the editor says so instead of rendering an empty list, because an absent
inherited server reads as "there are none". Servers named only by an
mcp_tool_permissions key are listed too, which is what makes a leftover entry
visible; the opt-out sentinel still renders nothing, since it short-circuits the
backend resolver to zero servers.

Opening the editor no longer applies the delete-blocked-by-default allowlist to an
inherited server. Writing an entry for one would narrow a grant the admin never
touched just by opening the form; direct servers keep that default.

Both components also matched on server_id alone, while the backend accepts a server
id, name or alias interchangeably. A grant or allowlist written by API or config with
a name rendered as a selected server with no tools under it, which reads as "this
server has no tools". Matching now covers all three identifiers, and an edit writes
back to the key the entry already uses rather than forking a second id-keyed entry.

The same mismatch could also put one server under several keys at once, its id and
its name for instance. The backend unions every key's list, so reading one key
understated what was in force and writing one key left the others granting. The
resolver now reports, per server, the key an edit keeps, the equivalent keys it
supersedes, and the union those keys allow; the card renders the union and every
write goes through one function that writes the kept key and drops the superseded
ones. A key that also names a DIFFERENT server, which happens when two servers share
a name, is never dropped, because dropping it would strip the neighbouring server's
restriction; the card names such a key and says its tools stay allowed until the
servers no longer share the name, so an admin is told rather than left to infer it
from an edit that bounces back.

A third divergence from the backend sat in the same matching. The backend resolves an
identifier with exact-id precedence: a string that is a registry server id names that
server and stops, and only a string that is no server's id falls back to name and alias,
which can name several. Matching all three fields at once meant a server merely named
after another server's id joined the matrix as if it had been selected, and because it
landed there as a directly selected server it also received the delete-blocked default
write on open. Since an mcp_tool_permissions key is itself a grant source, saving then
handed out a server nobody granted, with no admin gesture involved. Identifier
resolution now mirrors the backend's precedence, and a key is read as this server's only
when it resolves back to it, so an entry that belongs to the id's owner is neither read
into this server's allowlist nor overwritten by an edit made against it.

A toolset grant was also invisible to the tool matrix. The backend unions a toolset's
tools with whatever mcp_tool_permissions allows, so a toolset-only grant restricts the
server to that toolset's tools; the editor read the map alone, found no entry and
rendered every tool on the server as allowed. Deselecting one from that state wrote all
the others as a permission entry, and the union turned a revocation into a grant of
every tool the toolset never included. The resolved entry now carries the toolset's
tools, so the matrix opens on what is actually in force, the delete-blocked default is
withheld from a server a toolset restricts, and a write keeps out the tools only the
toolset accounts for so a grant that ends with the toolset does not become a standing
one. Those tools cannot be revoked from this screen at all, since the backend unions
them in; they render allowed and locked and the card says which of them a toolset holds
open and where to go to revoke them.

That guard originally covered only the keys an edit supersedes, on the assumption that
the key it keeps names one server. It does not when a shared key is a server's only
entry: it then becomes the key an edit writes, and writing it moves the other server's
allowlist too, which is the widening the guard exists to prevent. The key an edit writes
is now the first one naming this server and no other, falling back to the server's own
id, so a shared key is never written through and an edit against one card cannot reach
the server behind the other. Both cards say the shared key holds tools open, since
neither can revoke them.

No owner's save handler changes here. With the full effective set now available to
the editor, the key and team handlers can filter against it instead of guessing,
which makes the internal-user surface's unfiltered save redundant

Resolves LIT-4963
Resolves LIT-4958

* chore: drop tsbuildinfo churn from merge

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): satisfy dashboard lint budgets

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): keep MCP tool allowlists for indirect grants

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): keep standing MCP grants on team save

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* style(ui): format TeamInfo and hoist inline object args

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): keep MCP tool allowlists for team servers granted indirectly (#35153)

* fix(ui): filter team MCP tool allowlists against the effective server set

Saving a team filtered mcp_tool_permissions down to the directly selected servers. A server reached
through an access group or a toolset is never in that list, so any save dropped its entry, including
a save that only changed the team alias. Because the resolver unions tool-permission keys into the
entitled server set and treats a missing entry as "no restriction from this level", the team kept
the server and lost the tool allowlist on it

Filtering on the direct list alone cannot get this right in either direction. Keeping every entry a
level did not directly select leaves a removed access group's server reachable through its own stale
entry, which breaks revocation. Dropping on deselection alone widens a server that an access group
still supplies

The save handler now resolves the effective server set with resolveEffectiveMcpServers and keeps an
entry only when something other than the entry itself still grants that server: a direct selection, a
selected access group, or a selected toolset. Unified access group ids are added when that selection
is untouched, since the loaded server list is then still accurate

When the server or toolset list cannot be resolved, every entry is kept and the admin is told the
allowlists were saved unchanged. Pruning on incomplete knowledge is the direction that silently
widens, so it only happens when the editor can show the server became unreachable. A failed lookup
and a changed access group selection are separate cases in a tagged union, so the notice names what
actually happened instead of describing the intentional one as a failure, and both hooks gate the
filter symmetrically so a save fired before toolsets settle cannot resolve against an empty toolset
list

Resolves LIT-4961

* fix(ui): resolve team MCP grants from access group metadata and refuse unsafe saves

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): resolve team access group grants from team info when the access group list is role-gated

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): match every selected access group by id instead of by count

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): reload team access group grants at save time

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): keep frontend lint budget within limit

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(ui): cover a standing allowlist no group grant covers at load or save

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(ui): keep MCP grant inputs in named variables for the lint budget

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): guard MCP default write on toolset load, keep create toolsets, fix flat view

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-05 14:49:30 -07:00
.cargo ci: harden cargo fetches during maturin builds (#31348) 2026-06-25 14:31:05 -07:00
.circleci ci: report every failing test in a job instead of stopping at the first 2026-09-04 11:05:58 -07:00
.devcontainer build: migrate packaging, CI, and Docker from Poetry to uv (#25007) 2026-04-09 11:46:23 -07:00
.githooks chore(hooks): enforce Conventional Commits and Conventional Branches (#30174) 2026-06-11 10:00:23 -07:00
.github fix(ci): grant pull_requests write for release wheel reporter (#39922) 2026-09-05 13:04:31 -07:00
.semgrep/rules security: remove .claude/settings.json and add semgrep rule to prevent re-adding 2026-03-25 11:57:43 -07:00
backend fix(docker): install saml extra in litellm-backend image (#39291) 2026-09-02 08:01:54 -07:00
ci_cd fix(gpt-5): resolve temperature support from the model's default reasoning effort 2026-08-27 18:46:18 -07:00
cookbook feat(cli): store the lite login credential in the OS keychain 2026-08-19 18:57:35 -07:00
db_scripts fix: keep schema reconciliation from fighting a partitioned LiteLLM_SpendLogs (#38452) 2026-08-27 12:52:52 -07:00
docker fix(docker): match USE_DDTRACE case-insensitively and route build_from_pip through prod_entrypoint.sh (#39344) 2026-09-03 15:10:33 -07:00
enterprise fix(hide-secrets): stop redacting benign identifiers (#39879) 2026-09-05 11:47:36 -07:00
examples chore: litellm oss staging (#31185) 2026-06-26 09:17:44 -07:00
gateway Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gigachat_passthrough_25886 2026-08-31 15:25:10 -07:00
helm feat(helm): render nodeSelector, tolerations, and affinity on the componentized chart migrations Job 2026-09-04 18:28:53 -07:00
litellm Merge pull request #39853 from BerriAI/litellm_guardrail_usage_cost_ui 2026-09-05 14:41:11 -07:00
litellm-proxy-extras bump: litellm-enterprise 0.1.64 -> 0.1.65, litellm-proxy-extras 0.4.93 -> 0.4.94 2026-09-05 09:58:44 -07:00
litellm-rust feat(python): rename Rust rollout API (#39704) 2026-09-04 08:40:44 -07:00
migrations fix(docker): bump wolfi-base for glibc 2.44 and pin apk python to 3.13 in migrations image 2026-08-31 09:53:01 -07:00
packaging/homebrew feat(cli): per-agent lite claude / codex / opencode commands that wrap coding agents through the proxy (#29850) 2026-06-10 13:52:26 -07:00
scripts Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_deflake_20260902 2026-09-04 19:06:33 -07:00
terraform feat(terraform/gcp): dependencies-only mode and bring-your-own-network for GKE (#39695) 2026-09-05 12:22:52 -07:00
tests Merge pull request #39853 from BerriAI/litellm_guardrail_usage_cost_ui 2026-09-05 14:41:11 -07:00
ui fix(ui): show indirectly granted and name-keyed MCP servers in the tool matrix (#35154) 2026-09-05 14:49:30 -07:00
.dockerignore build(docker): build the Admin UI from source in a build-platform-pinned stage (#31130) 2026-06-25 23:41:08 -07:00
.env.example Add new model provider Novita AI (#7582) (#9527) 2025-05-12 21:49:30 -07:00
.git-blame-ignore-revs chore: ignore the mechanical lint and typing sweeps in git blame 2026-08-06 11:39:34 +00:00
.gitattributes feat(ui): generate dashboard API types from the proxy OpenAPI spec (#29816) 2026-06-05 17:20:01 -07:00
.gitguardian.yaml build: migrate packaging, CI, and Docker from Poetry to uv (#25007) 2026-04-09 11:46:23 -07:00
.gitignore fix(ci): let the mutation workflow find covered lines so it generates mutants 2026-08-25 23:16:40 -07:00
.npmrc [Fix] CI/Tooling: Correct min-release-age value in .npmrc files 2026-04-29 19:49:27 -07:00
AGENTS.md docs: hand-written CLAUDE.md; point GEMINI.md and AGENTS.md at it (#29252) 2026-05-29 00:05:05 -07:00
ARCHITECTURE.md feat(litellm): add models and repository layers (#29686) 2026-06-06 20:59:33 -07:00
basedpyright-code-budget.json feat(proxy): serve Prometheus /metrics from a separate process via --prometheus_metrics_port (#39889) 2026-09-05 13:26:09 -07:00
CLAUDE.md revert: default the proxy back to the v1 migration resolver 2026-09-01 12:56:08 -07:00
codecov.yaml fix(proxy): run SMTP send_email off the event loop with a connection timeout (#38473) 2026-08-29 16:05:57 -07:00
CONTRIBUTING.md chore: make it more concise 2026-08-19 15:11:37 -07:00
cosign.pub [Infra] Add release workflow and cosign public key 2026-03-31 14:30:27 -07:00
docker-compose.hardened.yml [Feature] Download Prisma binaries at build time instead of at runtime for Security Restricted environments (#17695) 2025-12-16 21:25:53 +05:30
docker-compose.yml feat: add read-replica routing for Prisma DB via DATABASE_URL_READ_REPLICA (#27493) 2026-05-08 21:05:50 -07:00
Dockerfile fix(docker): install bedrock-realtime extra in monolith proxy images (#39223) 2026-09-01 17:51:55 -07:00
GEMINI.md docs: hand-written CLAUDE.md; point GEMINI.md and AGENTS.md at it (#29252) 2026-05-29 00:05:05 -07:00
LICENSE refactor: creating enterprise folder 2024-02-15 12:54:13 -08:00
license_cache.json Add granian as a ASGI compliant web server. Provider better throughput stability, (#26027) 2026-05-21 19:08:37 -07:00
Makefile feat(ci): freeze the conftest save/restore inventory so it can only shrink (#37621) 2026-08-20 21:39:59 +00:00
mcp_servers.json Add ScrapeGraph MCP server configuration (#18923) 2026-01-11 21:57:46 +05:30
model_prices_and_context_window.json fix(cost-map): azure/gpt-6-astra accepts reasoning_effort none on Foundry 2026-09-04 17:29:55 -07:00
model_prices_and_context_window.schema.json feat(registry): add OpenRouter catalog gaps, Fireworks DeepSeek V4 Flash Vision, Together MiniMax M2.7 and Qwen2.5 7B Turbo pricing 2026-09-04 19:19:08 +00:00
osv-scanner.toml ci(osv): ignore GHSA-h7x2-h6g9-p789 until mlflow ships a fix 2026-08-31 13:58:53 -07:00
package-lock.json chore(deps): refresh dependency locks 2026-05-04 11:36:18 -07:00
package.json chore(deps): refresh dependency locks 2026-05-04 11:36:18 -07:00
policy_templates.json feat: Add Canadian PII protection (PIPEDA) (#22951) 2026-03-06 18:27:31 -08:00
prometheus.yml build(docker-compose.yml): add prometheus scraper to docker compose 2024-07-24 10:09:23 -07:00
provider_endpoints_support.json docs(vector_stores): register mongodb in the provider endpoint support matrix 2026-09-02 13:14:56 -07:00
proxy_server_config.yaml fix(ci): let the E2E proxy accept the mock testing params its suite sends 2026-08-01 14:57:42 -07:00
pyproject.toml bump: litellm-enterprise 0.1.64 -> 0.1.65, litellm-proxy-extras 0.4.93 -> 0.4.94 2026-09-05 09:58:44 -07:00
pyrightconfig.json test(e2e): move Admin UI Playwright suite to tests/e2e/ui (#34196) 2026-07-22 19:43:10 +00:00
qa_sticky_session.sh feat(sandbox): reuse e2b container across requests when metadata.session_id is set (#31688) 2026-06-30 18:58:09 -07:00
README.md feat(dashscope): add qwencloud and qwen_ai_platform provider aliases 2026-09-01 11:20:36 -07:00
render.yaml build(render.yaml): fix health check route 2024-05-24 09:45:28 -07:00
router_plugins.json feat(router): add router plugin reference catalog (#33746) 2026-07-17 18:46:20 +00:00
ruff-strict-budget.json Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_decrease_anys_opus5_r4 2026-09-04 21:02:19 -07:00
ruff-strict.toml feat(guardrails): add Alice guardrail (#38898) 2026-09-01 12:33:39 -07:00
ruff-tests.toml test: gate the test tree on fifteen assertion and handler rules it already satisfies (#38361) 2026-08-26 16:05:34 -07:00
ruff.toml fix(proxy): give every requests call a timeout so a silent server cannot hang the caller 2026-08-25 10:12:33 -07:00
rust-toolchain.toml fix(ci): pin workflow toolchain dependencies 2026-09-02 12:16:25 -07:00
schema.prisma feat(shadow_eval): scope a job to model groups, ANDed with its key, team, and user targets (#39828) 2026-09-04 20:50:46 -07:00
security.md docs(security): require a reproduction video for vulnerability reports (#30048) (#30063) 2026-06-09 14:59:50 -07:00
taplo.toml fix(agentcore): simplify agentcore streaming (#17141) 2026-01-19 05:20:24 -08:00
test-quality-budget.json fix(proxy): gate the OpenAI websocket passthrough behind an explicit opt-in 2026-09-04 18:14:44 -07:00
type-discipline-budget.json fix(mcp): scan and mask MCP tool call arguments in unified guardrails (#35142) 2026-09-05 20:51:25 +00:00
uv.lock bump: litellm-enterprise 0.1.64 -> 0.1.65, litellm-proxy-extras 0.4.93 -> 0.4.94 2026-09-05 09:58:44 -07:00
whitelisted_bedrock_models.txt fix(models): absorb open registry PRs: govcloud bedrock and mantle, azure gov, openai tiered long-context, scaleway, together qwen3.8, azure ai cache and kimi k2.7 code, azure mai deprecations 2026-09-02 14:48:51 +00:00

🚅 LiteLLM

LiteLLM AI Gateway

Open Source AI Gateway for 100+ LLMs. Self-hosted. Enterprise-ready. Call any LLM in OpenAI format.

Deploy to Render Deploy on Railway Deploy on AWS Deploy on GCP

LiteLLM Proxy Server (AI Gateway) | Hosted Proxy | Enterprise Tier | Website

PyPI Version GitHub Stars Y Combinator W23 Whatsapp Discord Slack CodSpeed

LiteLLM AI Gateway

What is LiteLLM

LiteLLM is an open source AI Gateway that gives you a single, unified interface to call 100+ LLM providers — OpenAI, Anthropic, Gemini, Bedrock, Azure, and more — using the OpenAI format.

Use it as a Python SDK for direct library integration, or deploy the AI Gateway (Proxy Server) as a centralized service for your team or organization.

Jump to LiteLLM Proxy (LLM Gateway) Docs
Jump to Supported LLM Providers


Why LiteLLM

Managing LLM calls across providers gets complicated fast — different SDKs, auth patterns, request formats, and error types for every model. LiteLLM removes that friction:

  • Unified API — one interface for 100+ LLMs, no provider-specific SDK juggling
  • Drop-in OpenAI compatibility — swap providers without rewriting your code
  • Production-ready gateway — virtual keys, spend tracking, guardrails, load balancing, and an admin dashboard out of the box
  • 8ms P95 latency at 1k RPS (benchmarks)

OSS Adopters

Stripe image Google ADK Greptile OpenHands

Netflix

OpenAI Agents SDK

Features

LLMs - Call 100+ LLMs (Python SDK + AI Gateway)

All Supported Endpoints - /chat/completions, /responses, /embeddings, /images, /audio, /batches, /rerank, /a2a, /messages and more.

Python SDK

uv add litellm
from litellm import completion
import os

os.environ["OPENAI_API_KEY"] = "your-openai-key"
os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-key"

# OpenAI
response = completion(model="openai/gpt-4o", messages=[{"role": "user", "content": "Hello!"}])

# Anthropic  
response = completion(model="anthropic/claude-sonnet-4-20250514", messages=[{"role": "user", "content": "Hello!"}])

AI Gateway (Proxy Server)

Getting Started - E2E Tutorial - Setup virtual keys, make your first request

uv tool install 'litellm[proxy]'
litellm --model gpt-4o
import openai

client = openai.OpenAI(api_key="anything", base_url="http://0.0.0.0:4000")
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}]
)

Docs: LLM Providers

Agents - Invoke A2A Agents (Python SDK + AI Gateway)

Supported Providers - LangGraph, Vertex AI Agent Engine, Azure AI Foundry, Bedrock AgentCore, Pydantic AI

Python SDK - A2A Protocol

from litellm.a2a_protocol import A2AClient
from a2a.types import SendMessageRequest, MessageSendParams
from uuid import uuid4

client = A2AClient(base_url="http://localhost:10001")

request = SendMessageRequest(
    id=str(uuid4()),
    params=MessageSendParams(
        message={
            "role": "user",
            "parts": [{"kind": "text", "text": "Hello!"}],
            "messageId": uuid4().hex,
        }
    )
)
response = await client.send_message(request)

AI Gateway (Proxy Server)

Step 1. Add your Agent to the AI Gateway — set protocolVersion to 1.0 or 0.3 per agent

Step 2. Call Agent via A2A SDK (requires a2a-sdk>=1.1.0)

import httpx
from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
from a2a.types import Message, Part, Role, SendMessageRequest
from a2a.utils.constants import TransportProtocol
from uuid import uuid4

base_url = "http://localhost:4000/a2a/my-agent"  # LiteLLM proxy + agent name
headers = {"Authorization": "Bearer sk-1234"}    # LiteLLM Virtual Key

async with httpx.AsyncClient(headers=headers, timeout=60.0) as http_client:
    resolver = A2ACardResolver(httpx_client=http_client, base_url=base_url)
    agent_card = await resolver.get_agent_card()
    config = ClientConfig(
        httpx_client=http_client,
        streaming=False,
        supported_protocol_bindings=[TransportProtocol.JSONRPC, TransportProtocol.HTTP_JSON],
    )
    client = ClientFactory(config).create(agent_card)

    request = SendMessageRequest(
        message=Message(
            message_id=uuid4().hex,
            role=Role.ROLE_USER,
            parts=[Part(text="Hello!")],
        )
    )
    async for event in client.send_message(request):
        populated = event.ListFields()
        if populated and populated[0][0].name in ("message", "msg"):
            print("".join(getattr(p, "text", "") or "" for p in populated[0][1].parts))

Docs: A2A Agent Gateway

MCP Tools - Connect MCP servers to any LLM (Python SDK + AI Gateway)

Python SDK - MCP Bridge

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from litellm import experimental_mcp_client
import litellm

server_params = StdioServerParameters(command="python", args=["mcp_server.py"])

async with stdio_client(server_params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()

        # Load MCP tools in OpenAI format
        tools = await experimental_mcp_client.load_mcp_tools(session=session, format="openai")

        # Use with any LiteLLM model
        response = await litellm.acompletion(
            model="gpt-4o",
            messages=[{"role": "user", "content": "What's 3 + 5?"}],
            tools=tools
        )

AI Gateway - MCP Gateway

Step 1. Add your MCP Server to the AI Gateway

Step 2. Call MCP tools via /chat/completions

curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Summarize the latest open PR"}],
    "tools": [{
      "type": "mcp",
      "server_url": "litellm_proxy/mcp/github",
      "server_label": "github_mcp",
      "require_approval": "never"
    }]
  }'

Use with Cursor IDE

{
  "mcpServers": {
    "LiteLLM": {
      "url": "http://localhost:4000/mcp/",
      "headers": {
        "x-litellm-api-key": "Bearer sk-1234"
      }
    }
  }
}

Docs: MCP Gateway

Supported Providers (Website Supported Models | Docs)

Provider /chat/completions /messages /responses /embeddings /image/generations /audio/transcriptions /audio/speech /moderations /batches /rerank
Abliteration (abliteration)
AI/ML API (aiml)
AI21 (ai21)
AI21 Chat (ai21_chat)
Aleph Alpha
Amazon Nova
Anthropic (anthropic)
Anthropic Text (anthropic_text)
Anyscale
AssemblyAI (assemblyai)
Auto Router (auto_router)
AWS - Bedrock (bedrock)
AWS - Sagemaker (sagemaker)
Azure (azure)
Azure AI (azure_ai)
Azure Text (azure_text)
Baseten (baseten)
Bytez (bytez)
Cerebras (cerebras)
Clarifai (clarifai)
Cloudflare AI Workers (cloudflare)
Codestral (codestral)
Cognition (cognition)
Cohere (cohere)
Cohere Chat (cohere_chat)
CometAPI (cometapi)
CompactifAI (compactifai)
Custom (custom)
Custom OpenAI (custom_openai)
Dashscope (dashscope)
Databricks (databricks)
DataRobot (datarobot)
Deepgram (deepgram)
DeepInfra (deepinfra)
Deepseek (deepseek)
ElevenLabs (elevenlabs)
Empower (empower)
Fal AI (fal_ai)
Featherless AI (featherless_ai)
Fireworks AI (fireworks_ai)
FriendliAI (friendliai)
Galadriel (galadriel)
GitHub Copilot (github_copilot)
GitHub Models (github)
Google - PaLM
Google - Vertex AI (vertex_ai)
Google AI Studio - Gemini (gemini)
GradientAI (gradient_ai)
Groq AI (groq)
Heroku (heroku)
Hosted VLLM (hosted_vllm)
Huggingface (huggingface)
Hyperbolic (hyperbolic)
IBM - Watsonx.ai (watsonx)
Infinity (infinity)
Jina AI (jina_ai)
Lambda AI (lambda_ai)
Lemonade (lemonade)
LiteLLM Proxy (litellm_proxy)
Llamafile (llamafile)
LM Studio (lm_studio)
Maritalk (maritalk)
Meta - Llama API (meta_llama)
Mistral AI API (mistral)
ModelScope (modelscope)
Moonshot (moonshot)
Morph (morph)
Nebius AI Studio (nebius)
NLP Cloud (nlp_cloud)
Novita AI (novita)
Nscale (nscale)
Nvidia NIM (nvidia_nim)
OCI (oci)
Ollama (ollama)
Ollama Chat (ollama_chat)
Oobabooga (oobabooga)
OpenAI (openai)
OpenAI-like (openai_like)
OpenRouter (openrouter)
OVHCloud AI Endpoints (ovhcloud)
Perplexity AI (perplexity)
Petals (petals)
Pinstripes (pinstripes)
Predibase (predibase)
Qwen AI Platform (qwen_ai_platform)
QwenCloud (qwencloud)
Recraft (recraft)
Replicate (replicate)
Sagemaker Chat (sagemaker_chat)
Sambanova (sambanova)
Snowflake (snowflake)
Text Completion Codestral (text-completion-codestral)
Text Completion OpenAI (text-completion-openai)
Together AI (together_ai)
Topaz (topaz)
Triton (triton)
V0 (v0)
Vercel AI Gateway (vercel_ai_gateway)
VLLM (vllm)
Volcengine (volcengine)
Voyage AI (voyage)
WandB Inference (wandb)
Watsonx Text (watsonx_text)
xAI (xai)
Xinference (xinference)

Read the Docs


Get Started

You can use LiteLLM through either the Proxy Server or Python SDK. Both give you a unified interface to access multiple LLMs (100+ LLMs). Choose the option that best fits your needs:

LiteLLM AI Gateway LiteLLM Python SDK
Use Case Central service (LLM Gateway) to access multiple LLMs Use LiteLLM directly in your Python code
Who Uses It? Gen AI Enablement / ML Platform Teams Developers building LLM projects
Key Features Centralized API gateway with authentication and authorization, multi-tenant cost tracking and spend management per project/user, per-project customization (logging, guardrails, caching), virtual keys for secure access control, admin dashboard UI for monitoring and management Direct Python library integration in your codebase, Router with retry/fallback logic across multiple deployments (e.g. Azure/OpenAI) - Router, application-level load balancing and cost tracking, exception handling with OpenAI-compatible errors, observability callbacks (Lunary, MLflow, Langfuse, etc.)

Stable Release: Use docker images with the -stable tag. These have undergone 12 hour load tests, before being published. More information about the release cycle here

Support for more providers. Missing a provider or LLM Platform, raise a feature request.

Deploy on AWS or GCP with Terraform

Run the LiteLLM proxy as a production-ready componentized stack (gateway, backend, UI on separate services; managed Postgres + Redis + object store) using the published Terraform modules. Both modules are on the public Terraform Registry — no auth needed.

AWS — ECS Fargate + Aurora + ElastiCache + ALB

Launch in AWS CloudShell — opens an in-browser shell, already authenticated to your AWS account. Once inside, run:

git clone https://github.com/BerriAI/litellm.git
cd litellm/terraform/litellm/aws/examples/default
cp terraform.tfvars.example terraform.tfvars   # edit region/tenant/env
terraform init && terraform apply

Module page →

Or call the module from your own root config:

# main.tf
terraform {
  required_version = ">= 1.6.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.60" }
  }
}

provider "aws" {
  region = "us-west-2"
}

module "litellm" {
  source  = "BerriAI/litellm/aws"
  version = "~> 1.89"

  region = "us-west-2"
  azs    = ["us-west-2a", "us-west-2b"]
  tenant = "acme"
  env    = "prod"

  # Production: provide an ACM cert. Without one, set allow_plaintext_alb = true
  # (dev/trial only).
  # acm_certificate_arn = "arn:aws:acm:us-west-2:111122223333:certificate/..."
  allow_plaintext_alb = true
}

output "litellm_url" {
  value = module.litellm.alb_dns_name
}
terraform init
terraform apply

Provider API keys live in AWS Secrets Manager; reference ARNs via gateway_extra_secrets. Full input list and architecture diagram on the registry page.

GCP — Cloud Run + Cloud SQL + Memorystore + HTTPS LB

Open in Cloud Shell

Real 1-click. Opens Cloud Shell, clones this repo, and walks you through terraform apply via a built-in DeployStack tutorial — pick the project, the tutorial sets up the Artifact Registry remote repo, writes terraform.tfvars from your answers, and runs apply.

Module page →

To call the module from your own config instead, Cloud Run can't pull from ghcr.io directly, so first set up a one-time Artifact Registry remote repo backed by GHCR:

gcloud artifacts repositories create litellm \
  --location=us-central1 \
  --repository-format=docker \
  --mode=remote-repository \
  --remote-docker-repo=https://ghcr.io \
  --project=my-gcp-project

Then:

# main.tf
terraform {
  required_version = ">= 1.6.0"
  required_providers {
    google      = { source = "hashicorp/google",      version = "~> 6.10" }
    google-beta = { source = "hashicorp/google-beta", version = "~> 6.10" }
  }
}

provider "google"      { project = "my-gcp-project"; region = "us-central1" }
provider "google-beta" { project = "my-gcp-project"; region = "us-central1" }

module "litellm" {
  source  = "BerriAI/litellm/google"
  version = "~> 1.89"

  project_id = "my-gcp-project"
  region     = "us-central1"
  tenant     = "acme"
  env        = "prod"

  # Replace my-gcp-project with your GCP project ID (same value as project_id above).
  image_registry = "us-central1-docker.pkg.dev/my-gcp-project/litellm/berriai"

  # Production: provide DNS already pointing at the LB IP for Google-managed certs.
  # Without one, set allow_plaintext_lb = true (dev/trial only).
  # lb_domains         = ["proxy.example.com"]
  allow_plaintext_lb = true
}

output "litellm_url" {
  value = module.litellm.load_balancer_url
}
terraform init
terraform apply

Provider API keys live in Secret Manager; reference resource IDs (e.g. projects/my-gcp-project/secrets/openai-api-key) via gateway_extra_secrets. Full input list and architecture diagram on the registry page.

Both stacks include

  • The full componentized split (gateway / backend / UI as independent services)
  • Managed Postgres (writer + reader) and Redis
  • Versioned object store for proxy state + file uploads
  • An auto-generated LITELLM_MASTER_KEY in your cloud's secret manager
  • A one-off migration job that runs prisma migrate deploy before the proxy starts
  • The same proxy_config surface as the Helm chart — pass YAML as a typed map

The Terraform modules live at terraform/litellm/aws/ and terraform/litellm/gcp/ in this repo; the registry entries are read-only mirrors updated on each release.

Run in Developer Mode

Services

  1. Setup .env file in root
  2. Run dependent services docker-compose up db prometheus

Backend

  1. Run make bootstrap
  2. Start proxy backend: uv run python litellm/proxy/proxy_cli.py

Frontend

  1. Navigate to ui/litellm-dashboard (dependencies were already installed w/ make bootstrap)
  2. Start dashboard: npm run dev

Verify Docker Image Signatures

All LiteLLM Docker images published to GHCR are signed with cosign. Every release is signed with the same key introduced in commit 0112e53.

Verify using the pinned commit hash (recommended):

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:<release-tag>

Verify using a release tag (convenience):

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/<release-tag>/cosign.pub \
  ghcr.io/berriai/litellm:<release-tag>

Replace <release-tag> with the version you are deploying (e.g. v1.83.0-stable).


Enterprise

For companies that need better security, user management and professional support

Get an Enterprise License Talk to founders

This covers:

  • Features under the LiteLLM Commercial License:
  • Feature Prioritization
  • Custom Integrations
  • Professional Support - Dedicated discord + slack
  • Custom SLAs
  • Secure access with Single Sign-On

Contributing

We welcome contributions to LiteLLM! Whether you're fixing bugs, adding features, or improving documentation, we appreciate your help.

Quick Start for Contributors

This requires uv to be installed.

git clone https://github.com/BerriAI/litellm.git
cd litellm
make install-dev    # Install development dependencies
make format         # Format your code
make lint           # Run all linting checks
make test-unit      # Run unit tests
make format-check   # Check formatting only

For detailed contributing guidelines, see CONTRIBUTING.md.

📖 Contributing to documentation? The LiteLLM docs have moved to a separate repository: BerriAI/litellm-docs. Please open doc PRs there. Docs are served at docs.litellm.ai.

Code Quality / Linting

LiteLLM follows the Google Python Style Guide.

Our automated checks include:

  • Black for code formatting
  • Ruff for linting and code quality
  • MyPy for type checking
  • Circular import detection
  • Import safety checks

All these checks must pass before your PR can be merged.

Support / talk with founders

Contributors