Skip to main content
Glama
junwayne66

litellm-admin-mcp

by junwayne66
README.md
# litellm-admin-mcp

LiteLLM Admin MCP server for [OpenClaw](https://github.com/openclaw/openclaw). Exposes LiteLLM Proxy admin APIs (internal users, virtual keys, spend logs) as MCP tools over **streamable-http**, so agents can manage LiteLLM without custom HTTP glue.

> 将 LiteLLM Proxy 的管理能力封装为 MCP Server,供 OpenClaw Agent 通过 `streamable-http` 调用。

## Overview

| Item | Detail |
|------|--------|
| Transport | MCP Streamable HTTP at `/mcp` |
| Backend | LiteLLM Proxy REST API (`LITELLM_BASE_URL`) |
| Auth | `Authorization: Bearer sk-*` pass-through per request (not env var) |
| Tools | 18 admin tools (`litellm_user_*`, `litellm_key_*`, `litellm_model_*`, `litellm_usage_*`) |
| Health | `GET /health` → `{"status":"ok"}` |

```
OpenClaw Agent ──streamable-http + Bearer sk-*──► litellm-admin-mcp :3100/mcp
                                                        │
                                                        ▼ Authorization pass-through
                                                  LiteLLM Proxy
```

## Prerequisites

- **Node.js 20+** (`engines.node` in `package.json`)
- A running **LiteLLM Proxy** with a valid **admin key** (`sk-*`)
- For OpenClaw integration: OpenClaw CLI with MCP support

## Install & Run

```bash
# Install dependencies
npm install

# Development (hot reload)
npm run dev

# Production build
npm run build
npm start
```

Default listen address: `http://0.0.0.0:3100`

- Health: `http://localhost:3100/health`
- MCP: `http://localhost:3100/mcp`

## Docker Deployment

### Quick start (docker compose)

```bash
docker compose up -d --build
docker compose logs -f litellm-admin-mcp
curl -s http://localhost:3100/health
```

Optional `.env` beside `docker-compose.yml`:

```bash
LITELLM_BASE_URL=http://192.168.91.200:8888
LITELLM_V1_BASE_URL=http://192.168.91.200:8888/v1
PORT=3100
```

> **Network note:** The container must reach LiteLLM at `LITELLM_BASE_URL`. From inside Docker, `127.0.0.1` points to the container itself — use the host LAN IP or `host.docker.internal` (Docker Desktop).

### Build and run manually

```bash
docker build -t litellm-admin-mcp:latest .

docker run -d \
  --name litellm-admin-mcp \
  -p 3100:3100 \
  -e LITELLM_BASE_URL=http://192.168.91.200:8888 \
  --restart unless-stopped \
  litellm-admin-mcp:latest
```

Stop: `docker compose down` or `docker stop litellm-admin-mcp && docker rm litellm-admin-mcp`

## Environment Variables

Copy `.env.example` and adjust as needed:

```bash
cp .env.example .env
```

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `LITELLM_BASE_URL` | No | `http://192.168.91.200:8888` | LiteLLM Proxy base URL (no trailing slash) |
| `LITELLM_V1_BASE_URL` | No | `{LITELLM_BASE_URL}/v1` | OpenAI-compatible base URL used in `key_generate` onboarding (`BASE_URL` in `message_zh`) |
| `PORT` | No | `3100` | HTTP port for this MCP server |
| `HOST` | No | `0.0.0.0` | Bind address |

Example:

```bash
export LITELLM_BASE_URL=http://your-litellm-host:8888
export PORT=3100
export HOST=0.0.0.0
npm run dev
```

**Admin key is not an environment variable.** Configure it in the MCP client (e.g. OpenClaw headers), not in this server's env.

## Authentication

Every request to `/mcp` must include:

```http
Authorization: Bearer sk-<your-litellm-admin-key>
```

Behavior:

1. Missing or invalid header (must start with `Bearer sk-`) → **401** from this server; LiteLLM is not called.
2. Valid header → forwarded **unchanged** to LiteLLM API calls made by tool handlers.

OpenClaw (or any MCP client) supplies the key per session. Rotate keys in the client config without redeploying this server.

## OpenClaw Configuration

> 推荐用 **双 Agent** 隔离管理员与员工自助场景;权限由 LiteLLM RBAC + OpenClaw tool 白名单共同约束,MCP 本身不重复实现鉴权层。

### Recommended architecture: dual agents

| Agent | `Authorization` | Use case |
|-------|-------------------|----------|
| `litellm-admin` | `Bearer sk-<proxy_admin>` | Ops: users, keys, models, global usage reports |
| `litellm-self` | Employee self-serve key or scoped admin key | Feishu bot DM: request API key, check own usage |

```
Feishu Bot (litellm-self)          Admin Agent (litellm-admin)
        │                                    │
        └──────── streamable-http ───────────┘
                         │
              litellm-admin-mcp :3100/mcp
                         │
                         ▼ Authorization pass-through
                   LiteLLM Proxy
```

### MCP server connection

Add to OpenClaw MCP config (e.g. `~/.openclaw/openclaw.json` or project-level MCP settings):

```json
{
  "mcp": {
    "servers": {
      "litellm-admin": {
        "url": "http://192.168.91.200:3100/mcp",
        "transport": "streamable-http",
        "headers": {
          "Authorization": "Bearer sk-your-admin-key"
        }
      },
      "litellm-self": {
        "url": "http://192.168.91.200:3100/mcp",
        "transport": "streamable-http",
        "headers": {
          "Authorization": "Bearer sk-your-self-serve-key"
        }
      }
    }
  }
}
```

Replace:

- `url` — host/port where `litellm-admin-mcp` runs (path must be `/mcp`)
- `litellm-admin` → LiteLLM proxy admin key (`sk-*`)
- `litellm-self` → a **scoped** key (self-serve or limited admin); do not reuse the root admin key for employee-facing bots

Network notes:

- OpenClaw and MCP on the same host: `http://127.0.0.1:3100/mcp`
- MCP in Docker, OpenClaw on host: use the **host LAN IP**, not container `127.0.0.1`
- OpenClaw must reach both this MCP server **and** LiteLLM is not required — only MCP needs `LITELLM_BASE_URL`

### Tool allowlists

Restrict tools per agent so employee bots cannot invoke destructive admin operations.

**Employee self-serve (`litellm-self`, e.g. Feishu bot):**

```
litellm_key_generate
litellm_key_list
litellm_key_info
litellm_user_info
litellm_model_list
litellm_model_info
litellm_usage_spend_logs
litellm_usage_user_activity
```

**Administrator (`litellm-admin`):** all 18 tools (see [MCP Tools](#mcp-tools-18) below).

Configure and verify:

```bash
openclaw mcp configure litellm-self \
  --include litellm_key_generate,litellm_key_list,litellm_key_info,litellm_user_info,litellm_model_list,litellm_model_info,litellm_usage_spend_logs,litellm_usage_user_activity

openclaw mcp doctor litellm-admin --probe
openclaw mcp doctor litellm-self --probe
openclaw mcp tools litellm-admin   # expect 18
openclaw mcp tools litellm-self    # expect 8 (after allowlist)
```

### Feishu bot agent prompt (template)

Attach this system prompt to the `litellm-self` agent bound to your Feishu channel:

```
你是公司内网 LLM 服务助手。员工通过私聊可申请 API Key、查询可用模型和 token 用量。

## 申请 API Key
1. 确认员工身份(飞书 user_id / 工号);必要时用 litellm_user_info 核对是否已有账号
2. 调用 litellm_key_generate,建议 key_alias 设为唯一标识(如 feishu:<user_id>)
3. 将返回的 onboarding.message_zh 完整发给用户,必须包含 virtual_key
4. 明确告知:API Key 仅显示一次,请勿外传,仅在内网使用

## 查模型
- litellm_model_list / litellm_model_info

## 查用量
- litellm_usage_spend_logs(按 user_id 或时间范围)
- litellm_user_info(预算、累计 spend)

## 查已有 Key
- litellm_key_list / litellm_key_info(用 key_alias)
- 注意:LiteLLM 的 key_list / key_info 不会返回完整 virtual_key,只能查元数据

## 禁止
不要创建/删除用户、删模型、全局报表等管理员操作;引导用户联系 IT/管理员。
```

### Responsibilities: MCP vs OpenClaw

| Responsibility | MCP (this server) | OpenClaw |
|----------------|-------------------|----------|
| LiteLLM API wrappers | 18 tools | Select tools per agent |
| Chinese tool descriptions / keywords | Yes | — |
| Onboarding template (`curl`, `BASE_URL`) | `onboarding.message_zh` on `key_generate` | Forward to employee |
| Feishu `user_id` → LiteLLM `user_id` mapping | — | Your agent logic |
| Multi-turn chat, intent routing | — | Yes |
| Admin vs employee isolation | Pass-through `Authorization` | Separate agents + allowlists |

**User mapping suggestion:** map `feishu:ou_xxx` to a LiteLLM `user_id` on first request (`litellm_user_create` + `litellm_key_generate`), or rely on `key_alias=feishu:ou_xxx` if your Proxy config allows it.

### Key behavior reminders

1. **`virtual_key` is returned only once** at `litellm_key_generate` — send `onboarding.message_zh` to the user immediately; afterwards use `lookup_token` or `key_alias` for management.
2. **`key_list` / `key_info` never return the full key** — LiteLLM limitation, not an MCP bug.
3. **Set `LITELLM_V1_BASE_URL`** on the MCP server if employees reach LiteLLM through a reverse proxy (no `:8888` in the public URL); otherwise onboarding `curl` examples will point at the wrong host.

### OpenClaw rollout checklist

```bash
# 1. MCP health (no auth)
curl -s http://192.168.91.200:3100/health

# 2. OpenClaw connectivity
openclaw mcp doctor litellm-admin --probe
openclaw mcp doctor litellm-self --probe

# 3. Tool counts
openclaw mcp tools litellm-admin
openclaw mcp tools litellm-self
```

## MCP Tools (18)

### Users (5)

| Tool | Description |
|------|-------------|
| `litellm_user_list` | List internal users (pagination, filters) |
| `litellm_user_create` | Create internal user with role/budget/models |
| `litellm_user_update` | Update user role, budget, models |
| `litellm_user_delete` | Delete internal users |
| `litellm_user_info` | User details, keys, spend (self or admin) |

### Keys (5)

| Tool | Description |
|------|-------------|
| `litellm_key_list` | List virtual keys (`key_alias`, masked name, `lookup_token`) |
| `litellm_key_generate` | Create virtual key; returns `virtual_key` + `onboarding.message_zh` **once** |
| `litellm_key_update` | Update models, budget, rate limits |
| `litellm_key_delete` | Revoke virtual keys |
| `litellm_key_info` | Key details and spend; supports `key_alias` |

### Models (5)

| Tool | Description |
|------|-------------|
| `litellm_model_list` | List configured proxy models |
| `litellm_model_info` | Single model config details |
| `litellm_model_create` | Add model route (admin) |
| `litellm_model_update` | Update model params (admin) |
| `litellm_model_delete` | Remove model config (admin) |

### Usage (3)

| Tool | Description |
|------|-------------|
| `litellm_usage_spend_logs` | Per-request token/spend logs |
| `litellm_usage_global_report` | Platform-wide spend summary (admin) |
| `litellm_usage_user_activity` | Daily user activity trends |

Tool responses use a unified envelope:

```json
{ "success": true, "data": {} }
```

```json
{ "success": false, "error": { "status": 400, "message": "...", "detail": {} } }
```

## Verification

### Health check (no auth)

```bash
curl -s http://localhost:3100/health
# {"status":"ok"}
```

### OpenClaw MCP probe

With the server running and OpenClaw configured:

```bash
openclaw mcp doctor --probe
```

Confirm `litellm-admin` (or your server alias) reports a healthy streamable-http connection and lists all 18 tools.

## Testing

```bash
# Unit tests (default, no live LiteLLM)
npm test

# Optional integration tests against a real LiteLLM instance
RUN_INTEGRATION=1 npm test

# With custom LiteLLM URL / admin key for integration
LITELLM_BASE_URL=http://your-host:8888 LITELLM_ADMIN_KEY=sk-your-key RUN_INTEGRATION=1 npm test
```

Integration tests are read-only (`user/list`, `key/list`). They are skipped unless `RUN_INTEGRATION=1`.

## Security

**Treat the LiteLLM admin key (`sk-*`) as a root credential.**

- It can create/delete users and keys, change budgets, and read spend data.
- Store it only in trusted MCP client config (OpenClaw headers), secret managers, or CI secrets — **never** commit it to git.
- This server does not add a second auth layer; anyone who can reach `/mcp` with a valid admin key can perform admin actions on your LiteLLM Proxy.
- Bind to `127.0.0.1` or place the service behind a private network / reverse proxy with TLS if exposed beyond localhost.
- Do not log full `sk-*` values. `key_generate` may return a new plaintext key once (LiteLLM behavior); handle that response carefully.

## Project Layout

```
Dockerfile            # Multi-stage production image
docker-compose.yml    # One-command deployment
src/
  server.ts           # Hono app, /health, /mcp transport
  litellm-client.ts   # LiteLLM HTTP client with auth pass-through
  tools/
    users.ts          # 5 user tools
    keys.ts           # 5 key tools (+ onboarding on generate)
    models.ts         # 5 model tools
    usage.ts          # 3 usage tools
    index.ts          # MCP server registration
  utils/
    response.ts       # ok() / fail() helpers
    onboarding.ts     # virtual key quickstart / message_zh
tests/                # Vitest unit + optional integration tests
```

## License

See repository license file if present.