Woow LiteLLM MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Woow LiteLLM MCP Serverlist all models configured on the LiteLLM gateway"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Overview
A LiteLLM gateway is a powerful thing to hand to an AI agent and a dangerous thing to hand to one carelessly. Its admin API can mint virtual keys, delete model deployments, evict team members and read every request's spend record. This repository is the layer in between: it exposes that API as 40 named MCP tools, each one classified by category, CRUD operation and blast radius, so an operator can decide exactly which subset a given agent is allowed to touch — and then prove, from a single source of truth, that the decision is being enforced.
The suite is deployed and running. The gateway it administers is LiteLLM
v1.83.14-stable (community edition) serving five OpenRouter-backed model
deployments; the admin console is reachable at https://litellm-mcp.woowtech.io and
the gateway itself at https://litellm.woowtech.io. Every number, table and screenshot
in this document was pulled from those live services rather than written from memory —
the usage figures in Screenshots are the real seven-day window ending
5 August 2026, and the tool catalogue in API Reference was generated
by importing the registry module itself.
Three properties define the design. The registry is the single source of truth:
woow_litellm_mcp_server/registry.py holds all 40 ToolSpec records, and the MCP
server, the gating layer and the admin GUI all read from it — a test
(tests/test_mcp_surface.py) fails the build if the GUI could ever name a tool the
server does not register. The MCP child never listens publicly: it binds
127.0.0.1 and the only route in is a path-token proxy whose token must match the
stored mcp_auth_token. Nothing needs a private registry: the Kubernetes manifests
clone this public repo in an initContainer and build in place, so a kubectl apply
is the entire deployment story.
Related MCP server: Multi-LLM Gateway MCP
Features
Forty tools across eight categories. Model lifecycle (6), OpenAI-compatible chat
and token counting (2), virtual-key governance (8), teams (7), internal users (5),
spend and cost reporting (3), health probes (2) and the Claude-Code skill hub (7).
Eighteen of the forty are strictly read-only; eight are flagged dangerous and carry a
[DESTRUCTIVE] docstring prefix that MCP clients surface to the model before it calls
them.
Four independent gating axes. Disable whole categories
(LITELLM_MCP_DISABLED_CATEGORIES=keys,teams), individual tools
(LITELLM_MCP_DISABLED_TOOLS=litellm_delete_key), CRUD operations across the board
(LITELLM_MCP_DISABLED_OPERATIONS=delete), or flip
LITELLM_MCP_READONLY=true to drop every mutating tool at registration time. Gates
apply before the tool is registered, so a disabled tool is not merely refused — it is
absent from tools/list entirely, and no prompt-injection can talk the model into
calling something that does not exist.
A real admin console, not a config file. Eight React Router pages — dashboard, tool manager, connection config, token manager, live log viewer, permission editor, settings and login — served by FastAPI behind JWT auth. The tool manager renders one switch per registry entry, grouped by category, with the dangerous ones visually marked. The log viewer streams the server's ring buffer over SSE.
Path-token isolation for the public endpoint. The console publishes exactly one
MCP door: /private_<mcp_auth_token>/mcp/. Rotating the token from the Tokens page
kills the old URL instantly. The token lives in the path rather than a query string
deliberately — uvicorn logs full request lines, and a query-string secret would end up
in every access log entry.
Registryless Kubernetes deployment. k8s-deploy.yaml and
k8s-admin-deploy.yaml use initContainers (alpine/git to clone, node:20-alpine
to build the SPA, python:3.12-slim to seed the config PVC) so the cluster pulls only
public upstream images. Cold start is about two and a half to three minutes; the SPA
build step ends in exit 0 by design so a frontend build failure degrades the console
rather than crash-looping the pod.
Live-verified against a real gateway. The test suite carries an opt-in live
marker that probes the actual deployment; the default run mocks LiteLLM's HTTP surface
and asserts each tool builds the right request and parses the right response.
Architecture
System topology
The suite is one container running one uvicorn process that fronts three things: the admin API, the SPA, and a reverse proxy to a loopback-bound MCP child.
┌───────────────────────── single container ───────────────────────────┐
Claude / MCP client │ │
│ │ uvicorn litellm_mcp_admin.main:app (0.0.0.0:8080) │
│ HTTPS │ ├─ AuthMiddleware (JWT) ── /api/* admin GUI + API │
▼ │ ├─ proxy /private_{token}/mcp/ ──┐ │
Cloudflare edge ─────┼──► └─ SPA (React) │ reverse proxy (nginx-free) │
│ ▼ │
│ McpProcessManager ► woow_litellm_mcp_server (127.0.0.1) │
│ │ transport=http /mcp/ │
└───────────────────────────────────────┼──────────────────────────────┘
▼
LiteLLM gateway (Bearer master key, port 4000)flowchart TB
subgraph client["MCP clients"]
C1["Claude.ai connector"]
C2["Claude Code / CLI"]
C3["Any MCP client"]
end
CF["Cloudflare edge<br/>TLS termination"]
subgraph pod["k3s pod · litellm-mcp-admin · :8080"]
UV["uvicorn<br/>litellm_mcp_admin.main:app"]
AUTH["AuthMiddleware<br/>JWT + httpOnly cookie"]
API["/api/* admin API"]
SPA["React SPA<br/>8 routes"]
PX["Reverse proxy<br/>/private_{token}/mcp/"]
PM["McpProcessManager"]
MCP["woow_litellm_mcp_server<br/>127.0.0.1:3000 · /mcp/"]
end
LLM["LiteLLM gateway v1.83.14<br/>litellm.svc.cluster.local:4000"]
OR["OpenRouter<br/>5 model deployments"]
C1 --> CF
C2 --> CF
C3 --> CF
CF --> UV
UV --> AUTH
AUTH --> API
AUTH --> SPA
UV --> PX
PX --> MCP
PM -.spawns.-> MCP
API -.controls.-> PM
MCP -->|"Bearer master key"| LLM
LLM --> OR
style MCP fill:#6E56CF,color:#fff
style LLM fill:#00A3E0,color:#fff
style PX fill:#D97706,color:#fffReading the diagram. Everything inside the pod box shares one process boundary
except the MCP child, which McpProcessManager spawns as a subprocess bound to
loopback. That binding is the security invariant: there is no network path to the MCP
child that does not pass through the proxy, and the proxy refuses any request whose
path token does not equal the stored mcp_auth_token. The dashed arrows are control
rather than data — the admin API tells the process manager to start, stop or restart
the child, but admin traffic never flows through it. The single solid arrow leaving the
pod carries the LiteLLM master key as a Bearer header; that key exists only in a
Kubernetes Secret and in the container's environment, never in this repository.
Request lifecycle
A tool call from Claude traverses six hops before it reaches OpenRouter, and each hop can reject it.
Claude Cloudflare Proxy route MCP child LiteLLM OpenRouter
│ │ │ │ │ │
│ tools/call ─────►│ │ │ │ │
│ │ TLS + WAF ─────►│ │ │ │
│ │ │ token match? │ │ │
│ │ │ ✗ → 404 │ │ │
│ │ │ ✓ ─────────────►│ │ │
│ │ │ │ gated? ✗ → n/a │ │
│ │ │ │ ✓ build req ──►│ │
│ │ │ │ │ route ───────►│
│ │ │ │ │◄── completion │
│ │ │ │◄── JSON │ │
│◄──────────────── structured MCP result ────────────────│ │ │sequenceDiagram
autonumber
participant CL as Claude
participant CF as Cloudflare
participant PX as Proxy /private_{tok}/
participant MC as MCP child
participant LL as LiteLLM :4000
participant OR as OpenRouter
CL->>CF: POST /private_{tok}/mcp/ (tools/call)
CF->>PX: forward over tunnel
alt token mismatch
PX-->>CL: 404 Not Found
else token matches
PX->>MC: proxied request
Note over MC: gating already applied<br/>at registration — a disabled<br/>tool is absent from tools/list
MC->>LL: HTTP + Bearer master key
LL->>OR: upstream model call
OR-->>LL: completion
LL-->>MC: JSON response
MC-->>CL: structured MCP result
endReading the diagram. The critical detail is the note in the middle: gating is not a
runtime check on an incoming call, it happens once at registration. If
litellm_delete_key is gated off, the MCP child never registers it, so tools/list
never advertises it and a tools/call naming it fails as an unknown tool rather than
as a permission denial. That distinction matters for agent safety — a model cannot be
persuaded to invoke a capability it has never been told about. The 404 on token
mismatch is likewise deliberate: a wrong token yields the same response as a wrong
path, so probing the endpoint reveals nothing about whether a valid token exists.
Tool registry model
Every tool is a frozen ToolSpec. The dataclass is small on purpose — seven fields
that together answer "what does this touch, how, and how badly can it go wrong".
ToolSpec
├── name litellm_delete_key
├── category ToolCategory.KEYS
├── description "[DESTRUCTIVE] Delete a virtual key…"
├── method POST
├── path /key/delete
├── operations ("delete",)
└── dangerous True
│
├──► gating.py — decides registration
├──► server.py — registers with FastMCP
└──► admin GUI — renders the switch + ⚠ badgeclassDiagram
class ToolSpec {
+str name
+ToolCategory category
+str description
+str method
+str path
+tuple operations
+bool dangerous
}
class ToolCategory {
<<enumeration>>
MODELS
CHAT
KEYS
TEAMS
USERS
SPEND
HEALTH
PLUGINS
}
class TOOL_REGISTRY {
<<40 entries>>
+list~ToolSpec~
}
class Gating {
+disabled_categories
+disabled_tools
+disabled_operations
+readonly
+is_enabled(spec) bool
}
class AdminGUI {
+renders one switch per spec
}
class FastMCPServer {
+registers enabled specs only
}
ToolSpec --> ToolCategory
TOOL_REGISTRY o-- ToolSpec
Gating ..> TOOL_REGISTRY : reads
FastMCPServer ..> Gating : asks
AdminGUI ..> TOOL_REGISTRY : readsReading the diagram. Both consumers — the server and the GUI — depend on
TOOL_REGISTRY and neither maintains its own list. litellm_mcp_admin/tool_registry.py
is a pure re-export of the server's module with no additions, which is what makes the
invariant testable: tests/test_mcp_surface.py compares the GUI's tool names against
the server's registered set and fails if they diverge. The operations tuple is what
LITELLM_MCP_DISABLED_OPERATIONS matches against, and it is a tuple rather than a
single value because a few tools legitimately span two verbs.
Deployment topology
Two namespaces, two deployments, one shared cluster DNS name between them.
┌── namespace: litellm ─────────────┐ ┌── namespace: litellm-mcp ──────────────────┐
│ │ │ │
│ Deployment litellm │ │ Deployment litellm-mcp-admin │
│ image ghcr.io/berriai/litellm │ │ strategy: Recreate │
│ :v1.83.14-stable │ │ ├─ init git-clone alpine/git │
│ │ │ ├─ init spa-build node:20-alpine │
│ Service litellm :4000 ◄───────┼───┼── └─ init seed-config python:3.12-slim│
│ │ │ └─ main admin :8080 │
│ Secret master key, salt key │ │ PVC litellm-mcp-data → /data/config.json │
└───────────────────────────────────┘ └────────────────────────────────────────────┘
▲ ▲
│ Cloudflare tunnel │ Cloudflare tunnel
litellm.woowtech.io litellm-mcp.woowtech.ioflowchart LR
subgraph ns1["namespace: litellm"]
D1["Deployment litellm<br/>ghcr.io/berriai/litellm:v1.83.14-stable"]
S1["Service litellm :4000"]
SEC["Secret<br/>master key · salt key"]
D1 --- S1
SEC -.-> D1
end
subgraph ns2["namespace: litellm-mcp"]
subgraph init["initContainers"]
I1["git-clone<br/>alpine/git"]
I2["spa-build<br/>node:20-alpine<br/>ends in exit 0"]
I3["seed-config<br/>python:3.12-slim"]
end
D2["Deployment litellm-mcp-admin<br/>strategy: Recreate · :8080"]
PVC[("PVC litellm-mcp-data<br/>/data/config.json")]
I1 --> I2 --> I3 --> D2
PVC --- D2
end
T1["cloudflared → litellm.woowtech.io"]
T2["cloudflared → litellm-mcp.woowtech.io"]
D2 -->|"litellm.litellm.svc.cluster.local:4000"| S1
T1 --- S1
T2 --- D2
style D1 fill:#00A3E0,color:#fff
style D2 fill:#6E56CF,color:#fff
style I2 fill:#D97706,color:#fffReading the diagram. The init chain runs in order and the middle step is the
interesting one: spa-build ends in exit 0 unconditionally, so a broken npm run build produces a console without a freshly built SPA rather than a pod stuck in
Init:CrashLoopBackOff — the previously built dist/ committed to the repo still
serves. strategy: Recreate rather than RollingUpdate is required because /repo is
an emptyDir repopulated on every restart and the PVC is ReadWriteOnce; two pods
cannot hold it at once. The cross-namespace arrow uses the cluster-internal DNS name,
so gateway traffic never leaves the cluster even though both services also have public
tunnels.
Packages
Every constituent package sits at the repository root — there is no wrapper directory,
so a pip install . from a fresh clone gets the MCP server and pip install ".[admin]"
adds the console.
Package | Purpose | Key modules |
| The FastMCP server. Owns the canonical tool registry, the gating layer, the typed LiteLLM client and all 40 tool implementations. |
|
| One module per category; each builds a request, calls the shared client and shapes the response. |
|
| Product-agnostic admin core, reusable across the Woow MCP family. JWT middleware, file-backed config store, MCP subprocess manager, the reverse proxy and the SSE wrapper. |
|
| The LiteLLM-specific console: FastAPI app, routers and the registry re-export the GUI reads. |
|
| Vite + React 19 SPA with React Router 7. Eight routes, JWT in |
|
| Optional Workers that give the MCP endpoint its own hostname and an OAuth discovery fallback. |
|
| 13 test modules, 135 collected cases, mocked by default with an opt-in |
|
| Supplementary design notes and every screenshot in this README. |
|
Deployment and packaging artefacts also live at the root: Dockerfile (two-stage,
node:20-alpine → python:3.12-slim, EXPOSE 8080), docker-compose.yml,
k8s-deploy.yaml, k8s-admin-deploy.yaml, k8s-secret.example.yaml, pyproject.toml,
mcp_admin_core.pyproject.toml, pytest.ini and .env.example.
The Python packages total 7,206 lines; the frontend adds 3,507 lines of JSX and JS.
Screenshots
Every image below was captured from the running deployment on 5 August 2026 through a
headless Chromium session — no mockups, no staged data. The console screenshots come
from https://litellm-mcp.woowtech.io, the gateway screenshots from
https://litellm.woowtech.io/ui/.
Admin console — login
The single unauthenticated route. Submitting the form posts { password } to
/api/auth/login, which returns a JWT and simultaneously sets an httpOnly
mcp-admin-token cookie so the SSE log stream can authenticate without putting the
token in a query string.
Admin console — dashboard
The landing route after login. It reports the MCP child's live process state — at
capture time PID: 93 · Restarts: 14 · running — alongside the configured LiteLLM
target and the tool-surface summary. The restart counter is cumulative across the pod's
lifetime and is the fastest way to spot a child that is failing to stay up.
Admin console — tool manager
All 40 tools, grouped into the eight categories, one switch each. The destructive eight
are badged so an operator disabling risky capabilities does not have to remember which
ones they are. Because this page renders straight from TOOL_REGISTRY, a tool added to
the server appears here on the next deploy with no frontend change.
Admin console — connection
Where the gateway target and credentials are set. The master key is write-only in the
API: it can be replaced but never read back, and every response masks it. The probe
button performs a real /health/readiness call against the configured base URL so a
typo surfaces immediately rather than at first tool call.
Admin console — tokens
Manages mcp_auth_token, the secret embedded in the public MCP URL. Generating
previews a candidate without committing it; rotating replaces the live value and kills
the previous URL immediately, which disconnects every connected MCP client until they
are repointed. The distinction between generate and rotate is deliberate — it makes the
destructive action a separate, explicit click.
Admin console — logs
A live tail of the server's in-memory ring buffer over Server-Sent Events. At capture
time the header read Live · 1504 shown · 1504 buffered, meaning nothing had yet aged
out of the buffer. The stream uses EventSource with withCredentials: true so it
rides the httpOnly cookie rather than appending the JWT to the URL.
Admin console — permissions
The category, operation and read-only gates, edited without touching environment variables. Changes here write through to the config store on the PVC and take effect on the next child restart, because gating is applied at tool-registration time rather than per call.
Admin console — settings
Process-level controls: the admin password, JWT expiry, and the proxy timeout — set to
86400 seconds (24 hours) on this deployment so long-lived MCP sessions are not cut
off mid-conversation. Restarting the MCP child from this page is the supported way to
apply a permission change.
LiteLLM gateway — login
The upstream gateway's own UI at https://litellm.woowtech.io/ui/. This is a separate
authentication domain from the MCP console: it takes the LiteLLM admin credentials,
not the console's admin_password. The MCP server never uses this UI — it talks to the
gateway's REST API with the master key.
LiteLLM gateway — dashboard
The gateway's virtual-key overview. Every key the MCP keys tools create, block or
regenerate appears here, which makes this page the independent check on whether a tool
call actually did what it reported.
LiteLLM gateway — models
The five deployments this gateway serves, all routed through OpenRouter and all
reporting healthy at capture time (healthy_count: 5, unhealthy_count: 0).
Model name | Upstream | Context | Input $/tok | Output $/tok | Notable |
|
| 1,000,000 | 3.0e-6 | 1.5e-5 | vision, computer use, cache write 3.75e-6 / read 3.0e-7 |
|
| 202,800 | 4.0e-7 | 1.75e-6 | function calling, reasoning, prompt caching; max_tokens 131,000 |
|
| 204,800 | 2.55e-7 | 1.02e-6 | lowest cost per token of the paid tier |
|
| — | 0 | 0 | cost tracking not configured |
|
| — | 0 | 0 | cost tracking not configured |
LiteLLM gateway — MCP servers
LiteLLM v1.83.14 can itself register MCP servers, which is a distinct concern from this repository: that feature lets the gateway call MCP tools, whereas this project lets MCP clients call the gateway. The page is included because the two are easy to confuse when reading the LiteLLM docs.
LiteLLM gateway — usage
The real seven-day window, 29 July to 5 August 2026: $0.0111 total spend, 174
requests of which 141 succeeded and 33 failed, 7,467 tokens, averaging
$0.0001 per request. All spend is attributed to the single openrouter provider.
The 33 failures are the expected shape for a period that included live gating and
error-path tests — a request rejected by a gate never reaches the provider, so it
counts as failed here while costing nothing.
LiteLLM gateway — logs
Per-request records with model, token counts and cost. Cross-referencing an MCP
litellm_chat_completion call against this page is how the end-to-end path was
verified: the tool reports a completion, and the row appears here with a matching token
count.
Installation
Option 1 — bare MCP server
The smallest useful deployment: no console, no proxy, just the 40 tools over stdio or Streamable-HTTP.
git clone https://github.com/WOOWTECH/Woow_litellm_mcp_server.git
cd Woow_litellm_mcp_server
pip install .
export LITELLM_MCP_BASE_URL=http://localhost:4000
export LITELLM_MCP_MASTER_KEY=sk-... # never commit this
# Streamable-HTTP (the deployed default)
python -m woow_litellm_mcp_server.server \
--transport http --host 0.0.0.0 --port 8000 --path /mcp/
# or stdio, for a local MCP client
python -m woow_litellm_mcp_server.server --transport stdioOption 2 — admin console via Docker Compose
cp .env.example .env # set JWT_SECRET and the LITELLM_MCP_* values
docker compose up --buildThe two-stage Dockerfile builds the SPA on node:20-alpine, then runs
uvicorn litellm_mcp_admin.main:app on python:3.12-slim at :8080. Log in with the
admin_password from the config store (default admin — change it on first login),
point the Connection page at your gateway, and toggle tools on the Tools page.
Option 3 — Kubernetes, bare server
No image build and no private registry: an initContainer clones this public repo into
an emptyDir and the main container pip installs it.
kubectl apply -f k8s-secret.example.yaml # after filling in the real master key
kubectl apply -f k8s-deploy.yamlIn-cluster consumers then reach it at
http://litellm-mcp.litellm-mcp.svc.cluster.local:8000/mcp/.
Option 4 — Kubernetes, console + encrypted proxy
k8s-deploy.yaml alone gives a bare, unauthenticated MCP server that is safe only
because it never leaves the cluster. To publish it, apply the admin manifest too — same
git-clone trick, plus the SPA build and a seeded config PVC.
kubectl apply -f k8s-deploy.yaml # namespace + litellm-mcp-secret
kubectl apply -f k8s-admin-deploy.yaml # console + encrypted proxy + MCP childPoint a Cloudflare tunnel or any ingress at
http://litellm-mcp-admin.litellm-mcp.svc.cluster.local:8080. The only public MCP door
is then /private_<mcp_auth_token>/mcp/. Design notes, verification commands and the
Cloudflare Bot Fight Mode caveat are in
docs/encrypted-proxy.md.
Expect a two-and-a-half to three minute cold start while the three init containers run.
Connecting an MCP client
Add the endpoint as a custom connector:
https://<your-admin-hostname>/private_<mcp_auth_token>/mcp/Rotating mcp_auth_token from the Tokens page invalidates that URL immediately, so
plan rotations around connected clients.
Configuration
Server settings use the LITELLM_MCP_ prefix and are read by
woow_litellm_mcp_server/settings.py via pydantic-settings.
Environment variable | Default | Meaning |
|
| Gateway base URL, no path suffix. |
| (empty) | Bearer master/admin key. Keep it in a Secret. |
|
| Drop every mutating tool at registration. |
| (empty) | CSV of categories to drop, e.g. |
| (empty) | CSV of tool names to drop. |
| (empty) | CSV of |
|
| Default page size for list tools. |
|
| Hard ceiling on page size. |
|
| Per-request HTTP timeout, seconds. |
Console settings: MCP_ADMIN_CONFIG (path to the JSON config store, /data/config.json
on the PVC deployment), JWT_SECRET and JWT_EXPIRY_HOURS. The proxy timeout is stored
in the config rather than the environment and is set to 86400 on the live deployment.
Python dependencies, from pyproject.toml:
dependencies = ["fastmcp>=2.0", "mcp>=1.2", "httpx>=0.27",
"pydantic>=2.6", "pydantic-settings>=2.2"]
[project.optional-dependencies]
admin = ["fastapi>=0.115", "uvicorn[standard]>=0.30", "pyjwt>=2.9",
"python-multipart>=0.0.9", "sse-starlette>=2.1"]
test = ["pytest>=8.0", "pytest-asyncio>=0.23", "httpx>=0.27"]
dev = ["woow-litellm-mcp-server[admin,test]", "ruff>=0.5"]Security
What "encrypted proxy" means here, precisely. It means path-token isolation, a
JWT-gated GUI and TLS at the Cloudflare edge. It does not mean at-rest payload
encryption: the config store is plaintext JSON protected by file permissions
(chmod 600) and by secret-masking in every API response. Saying so plainly matters
more than the marketing word.
Secrets never enter the repository. The LiteLLM master key, the salt key and the
admin password live in Kubernetes Secrets and the container environment only.
k8s-secret.example.yaml ships placeholders. Every config API response masks secret
fields, and the master key is write-only — settable, never readable.
LITELLM_SALT_KEY must be set once and never rotated. LiteLLM uses it to encrypt
columns in its database; rotating it renders every previously encrypted value
undecryptable. This is a property of the upstream gateway, not of this project, and it
is the single most damaging mistake available in this stack.
Rotate mcp_auth_token deliberately. Rotation is instant and unforgiving: the old
/private_<token>/mcp/ URL stops resolving the moment the new one is written, and every
connected MCP client fails until repointed. The Tokens page separates "generate a
preview" from "rotate the live value" for exactly this reason.
Destructive tools are opt-out, not opt-in. All eight ship enabled. For any agent
that does not need them, set LITELLM_MCP_READONLY=true or list them in
LITELLM_MCP_DISABLED_TOOLS. Because gating happens at registration, a disabled tool
is invisible rather than merely refused — the stronger of the two guarantees.
The MCP child is loopback-only. It binds 127.0.0.1 and is reachable exclusively
through the proxy route. A misconfigured ingress cannot accidentally expose it, because
there is no address to expose.
API Reference
All 40 tools, generated from woow_litellm_mcp_server/registry.py. Every name is
prefixed litellm_. "Ops" is the operations tuple that
LITELLM_MCP_DISABLED_OPERATIONS matches against; "Danger" marks the eight tools whose
docstrings carry the [DESTRUCTIVE] prefix.
Tool | Category | Method | Path | Ops | Danger |
| models | GET |
| read | — |
| models | GET |
| read | — |
| models | GET |
| read | — |
| models | POST |
| create | — |
| models | POST |
| update | — |
| models | POST |
| delete | ⚠ |
| chat | POST |
| create | — |
| chat | POST |
| read | — |
| keys | POST |
| create | — |
| keys | GET |
| read | — |
| keys | GET |
| read | — |
| keys | POST |
| update | — |
| keys | POST |
| delete | ⚠ |
| keys | POST |
| update | ⚠ |
| keys | POST |
| update | — |
| keys | POST |
| update | ⚠ |
| teams | POST |
| create | — |
| teams | GET |
| read | — |
| teams | GET |
| read | — |
| teams | POST |
| update | — |
| teams | POST |
| delete | ⚠ |
| teams | POST |
| create | — |
| teams | POST |
| delete | ⚠ |
| users | POST |
| create | — |
| users | GET |
| read | — |
| users | GET |
| read | — |
| users | POST |
| update | — |
| users | POST |
| delete | ⚠ |
| spend | GET |
| read | — |
| spend | GET |
| read | — |
| spend | POST |
| read | — |
| health | GET |
| read | — |
| health | GET |
| read | — |
| plugins | GET |
| read | — |
| plugins | GET |
| read | — |
| plugins | POST |
| create | — |
| plugins | DELETE |
| delete | ⚠ |
| plugins | POST |
| update | — |
| plugins | POST |
| update | — |
| plugins | GET |
| read | — |
TOTAL | 8 categories | 18 read-only | 8 dangerous |
Admin HTTP API
Route | Method | Purpose |
| POST | Exchange |
| POST | Expire the cookie. |
| GET / PUT | Read and write the connection config (secrets masked on read). |
| GET / PUT | Read and write per-tool enablement. |
| POST | Preview a candidate |
| POST | Commit a new token. Destroys the live MCP URL. |
| GET (SSE) | Tail the ring buffer. |
| GET | Console and MCP-child health. |
| ANY | The proxied MCP endpoint. |
SPA routes
/login, / (dashboard), /tools, /config, /tokens, /logs, /permissions,
/settings, and a catch-all that redirects to /.
Testing
pip install -e ".[admin,test]"
pytest # mocked; live probes deselected by default
pytest -m live # opt-in; requires a reachable LiteLLM gatewayLatest run: 133 passed, 2 deselected, 1 warning in 0.98s — 135 cases collected across 13 modules.
Module | Covers |
| The registry↔GUI invariant: the console can never name a tool the server lacks. |
| All four gating axes, individually and in combination. |
| A gated tool is absent from |
| Each tool builds the correct method, path and body. |
| Model-tool parameter shapes against LiteLLM's schema. |
| Spend and cost-report response parsing. |
| The console's tool enable/disable API. |
| The Connection page's readiness probe. |
| Config store → client construction. |
| httpx client creation, reuse and teardown. |
| LiteLLM error bodies surface intact to the MCP caller. |
| SSE ring-buffer streaming. |
| Opt-in probes against a real gateway (the 2 deselected). |
TOTAL | 135 collected · 133 passing · 2 deselected |
Changelog
v0.3.0 — August 2026
Documentation and verification pass against the live deployment. Corrected the tool
count from 38 to 40 (FINDING-001): the README had drifted from the registry after
litellm_plugin_info and litellm_delete_plugin were added, and the plugins category
was under-documented by two entries. Added the full 40-row generated tool catalogue so
the count can no longer drift silently. Captured fourteen screenshots and every metric
in this document from the running services rather than from memory (FINDING-002).
Added bilingual READMEs, four architecture diagrams in both ASCII and Mermaid, and the
docs/ supplement set.
v0.2.0 — July 2026
Encrypted proxy and admin console. Added mcp_admin_core as a product-agnostic layer,
the path-token proxy route, the JWT-gated React console and the registryless Kubernetes
manifests. Fixed the SSE stream leaking the JWT into uvicorn's access log by moving
authentication to an httpOnly cookie with withCredentials (BUG-1). Fixed the
config PVC being clobbered on redeploy by making seed-config idempotent (BUG-2).
Fixed RollingUpdate deadlocking on the ReadWriteOnce PVC by switching to Recreate
(BUG-3). Made the SPA build non-fatal so a frontend break degrades the console
instead of crash-looping the pod (BUG-4).
v0.1.0 — June 2026
Initial release. FastMCP server, the ToolSpec registry, the four gating axes, the
typed LiteLLM client and the mocked test suite.
Support
Issues and feature requests — open an issue on the GitHub repository.
Deployment questions — start with
docs/deployment.mdanddocs/encrypted-proxy.md, which cover the runbook, the proxy design, verification commands and the Cloudflare Bot Fight Mode caveat that bites most first-time tunnel setups.Contributing — see CONTRIBUTING.md. New tools must be added to
registry.pyfirst;tests/test_mcp_surface.pywill fail the build otherwise.
License
Released under the MIT License.
LiteLLM is licensed separately by BerriAI; this project administers a LiteLLM gateway but does not redistribute it.
Model access is subject to the terms of the upstream providers reached through OpenRouter.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server for Portkey Admin API - 116 tools for prompts, configs, analytics & more.Last updated1003805MIT
- Alicense-qualityCmaintenanceAn MCP server that functions as an intelligent gateway for multiple LLM backends including OpenAI, Claude, and Ollama. It supports automatic provider fallback, streaming responses via Server-Sent Events, and real-time monitoring for robust AI integration.Last updatedMIT
- Alicense-qualityDmaintenanceMCPGate aggregates multiple MCP servers into a single unified endpoint, enabling centralized tool management with granular filtering, automatic namespacing, and observability. Features a real-time web dashboard and optional PostgreSQL-backed audit trails for monitoring and controlling AI tool access across local and remote deployments.Last updated26Apache 2.0
- Alicense-qualityCmaintenanceMCP server that provides tools to interact with the LiteLLM proxy API, enabling LLM completions, embeddings, image generation, and admin operations.Last updated18MIT
Related MCP Connectors
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
An MCP server for Arcjet - the runtime security platform that ships with your AI code.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/WOOWTECH/Woow_litellm_mcp_server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server