MCP OAuth
LiteLLM supports two OAuth 2.0 flows for MCP servers:
| Flow | Use Case | How It Works |
|---|---|---|
| Interactive (PKCE) | User-facing apps (Claude Code, Cursor) | Browser-based consent, per-user tokens |
| Machine-to-Machine (M2M) | Backend services, CI/CD, automated agents | client_credentials grant, proxy-managed tokens |
Interactive OAuth (PKCE)​
For user-facing MCP clients (Claude Code, Cursor), LiteLLM supports the full OAuth 2.0 authorization code flow with PKCE.
Setup​
config.yaml
mcp_servers:
github_mcp:
url: "https://api.githubcopilot.com/mcp"
auth_type: oauth2
client_id: os.environ/GITHUB_OAUTH_CLIENT_ID
client_secret: os.environ/GITHUB_OAUTH_CLIENT_SECRET
How It Works​
Participants
- Client -- The MCP-capable AI agent (e.g., Claude Code, Cursor, or another IDE/agent) that initiates OAuth discovery, authorization, and tool invocations on behalf of the user.
- LiteLLM Proxy -- Mediates all OAuth discovery, registration, token exchange, and MCP traffic while protecting stored credentials.
- Authorization Server -- Issues OAuth 2.0 tokens via dynamic client registration, PKCE authorization, and token endpoints.
- MCP Server (Resource Server) -- The protected MCP endpoint that receives LiteLLM's authenticated JSON-RPC requests.
- User-Agent (Browser) -- Temporarily involved so the end user can grant consent during the authorization step.
Flow Steps
- Resource Discovery: The client fetches MCP resource metadata from LiteLLM's
.well-known/oauth-protected-resourceendpoint to understand scopes and capabilities. - Authorization Server Discovery: The client retrieves the OAuth server metadata (token endpoint, authorization endpoint, supported PKCE methods) through LiteLLM's
.well-known/oauth-authorization-serverendpoint. - Dynamic Client Registration: The client registers through LiteLLM, which forwards the request to the authorization server (RFC 7591). If the provider doesn't support dynamic registration, you can pre-store
client_id/client_secretin LiteLLM (e.g., GitHub MCP) and the flow proceeds the same way. - User Authorization: The client launches a browser session (with code challenge and resource hints). The user approves access, the authorization server sends the code through LiteLLM back to the client.
- Token Exchange: The client calls LiteLLM with the authorization code, code verifier, and resource. LiteLLM exchanges them with the authorization server and returns the issued access/refresh tokens.
- MCP Invocation: With a valid token, the client sends the MCP JSON-RPC request (plus LiteLLM API key) to LiteLLM, which forwards it to the MCP server and relays the tool response.
See the official MCP Authorization Flow for additional reference.
Machine-to-Machine (M2M) Auth​
LiteLLM automatically fetches, caches, and refreshes OAuth2 tokens using the client_credentials grant. No manual token management required.
Setup​
- config.yaml
- LiteLLM UI
config.yaml
mcp_servers:
my_mcp_server:
url: "https://my-mcp-server.com/mcp"
auth_type: oauth2
client_id: os.environ/MCP_CLIENT_ID
client_secret: os.environ/MCP_CLIENT_SECRET
token_url: "https://auth.example.com/oauth/token"
scopes: ["mcp:read", "mcp:write"] # optional
Navigate to MCP Servers → Add Server → Authentication → OAuth, then fill in client_id, client_secret, and token_url.
How It Works​
- On first MCP request, LiteLLM POSTs to
token_urlwithgrant_type=client_credentials - The access token is cached in-memory with TTL =
expires_in - 60s - Subsequent requests reuse the cached token
- When the token expires, LiteLLM fetches a new one automatically
Test with Mock Server​
Use BerriAI/mock-oauth2-mcp-server to test locally:
Terminal 1 - Start mock server
pip install fastapi uvicorn
python mock_oauth2_mcp_server.py # starts on :8765
config.yaml
mcp_servers:
test_oauth2:
url: "http://localhost:8765/mcp"
auth_type: oauth2
client_id: "test-client"
client_secret: "test-secret"
token_url: "http://localhost:8765/oauth/token"
Terminal 2 - Start proxy and test
litellm --config config.yaml --port 4000
# List tools
curl http://localhost:4000/mcp-rest/tools/list \
-H "Authorization: Bearer sk-1234"
# Call a tool
curl http://localhost:4000/mcp-rest/tools/call \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-1234" \
-d '{"name": "echo", "arguments": {"message": "hello"}}'
Config Reference​
| Field | Required | Description |
|---|---|---|
auth_type | Yes | Must be oauth2 |
client_id | Yes | OAuth2 client ID. Supports os.environ/VAR_NAME |
client_secret | Yes | OAuth2 client secret. Supports os.environ/VAR_NAME |
token_url | Yes | Token endpoint URL |
scopes | No | List of scopes to request |