Skip to main content

MCP OAuth

LiteLLM supports two OAuth 2.0 flows for MCP servers:

FlowUse CaseHow 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 agentsclient_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

See Claude Code Tutorial

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

  1. Resource Discovery: The client fetches MCP resource metadata from LiteLLM's .well-known/oauth-protected-resource endpoint to understand scopes and capabilities.
  2. Authorization Server Discovery: The client retrieves the OAuth server metadata (token endpoint, authorization endpoint, supported PKCE methods) through LiteLLM's .well-known/oauth-authorization-server endpoint.
  3. 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_secret in LiteLLM (e.g., GitHub MCP) and the flow proceeds the same way.
  4. 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.
  5. 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.
  6. 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​

You can configure M2M OAuth via the LiteLLM UI or config.yaml.

UI Setup​

Navigate to the MCP Servers page and click + Add New MCP Server.

Enter a name for your server and select HTTP as the transport type.

Paste the MCP server URL.

Under Authentication, select OAuth.

Choose Machine-to-Machine (M2M) as the OAuth flow type. This is for server-to-server authentication using the client_credentials grant — no browser interaction required.

Fill in the Client ID and Client Secret provided by your OAuth provider.

Enter the Token URL — this is the endpoint LiteLLM will call to fetch access tokens using client_credentials.

Scroll down and review the server URL and all fields, then click Create MCP Server.

Once created, open the server and navigate to the MCP Tools tab to verify that LiteLLM can connect and list available tools.

Select a tool (e.g. echo) to test it. Fill in the required parameters and click Call Tool.

LiteLLM automatically fetches an OAuth token behind the scenes and calls the tool. The result confirms the M2M OAuth flow is working end-to-end.

Config.yaml Setup​

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

How It Works​

  1. On first MCP request, LiteLLM POSTs to token_url with grant_type=client_credentials
  2. The access token is cached in-memory with TTL = expires_in - 60s
  3. Subsequent requests reuse the cached token
  4. 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​

FieldRequiredDescription
auth_typeYesMust be oauth2
client_idYesOAuth2 client ID. Supports os.environ/VAR_NAME
client_secretYesOAuth2 client secret. Supports os.environ/VAR_NAME
token_urlYesToken endpoint URL
scopesNoList of scopes to request