Machine-to-Machine (M2M) Access with API Tokens
Building a backend service, agent platform, or anything else that can't open a browser to sign in? CourtListener's MCP server supports machine-to-machine authentication with API tokens.
The MCP server accepts two credentials: OAuth for interactive clients like Claude and ChatGPT, and CourtListener API tokens for machine-to-machine use. This page covers the API token path.
Why Not OAuth for M2M?
OAuth on the MCP server uses the standard authorization-code flow: a human signs in, approves access, and the client receives short-lived access tokens plus a refresh token. Two properties of that flow make it a poor fit for server-to-server deployments:
- Refresh tokens are single-use and rotate on every refresh — Each refresh invalidates the previous refresh token. A fleet of stateless instances can't share one, and a lost response mid-rotation forces a full re-authorization, which requires a human in a browser.
- There is no client-credentials grant — Every OAuth authorization is tied to an interactive consent step.
API tokens have neither problem: they don't expire, never rotate, and any number of instances can send the same token concurrently.
Setup
Before beginning, you will need a CourtListener account. Create an account if you do not already have one.
- Copy your API token from your profile settings — the same token used for the REST API
- Send it on every request to
https://mcp.courtlistener.com/, using the same header scheme the REST API uses:
Authorization: Token <your-api-token>
No OAuth flow, no dynamic client registration, nothing to refresh.
Example: Raw HTTP
curl -X POST https://mcp.courtlistener.com/ \
-H "Authorization: Token <your-api-token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "my-backend", "version": "1.0"}
}
}'
Example: MCP Client Configuration
Most MCP SDKs and clients accept custom headers on an HTTP transport. A typical configuration looks like:
{
"url": "https://mcp.courtlistener.com/",
"headers": {
"Authorization": "Token <your-api-token>"
}
}
In the Python and TypeScript MCP SDKs, pass the header wherever the Streamable HTTP transport accepts request headers. If your framework only exposes a "bearer token" field, that won't work here — see the next section.
The Scheme Is Binding
The Authorization scheme tells the server what kind of credential you're
presenting, and it is checked strictly:
Token <api-token>— a CourtListener API token, verified against the CourtListener APIBearer <access-token>— an OAuth access token, verified against CourtListener's OpenID Connect endpoint
An API token sent as Bearer returns 401 — the server never retries a
credential against the other verifier. If your framework hard-codes Bearer,
you'll need to set the raw Authorization header instead.
Things to Know
- An API token grants full access to your account's API surface, including alert and subscription tools. Treat it like a password: keep it out of source control, inject it from your secret store, and regenerate it at your profile if it leaks. Regeneration invalidates the old token immediately, fleet-wide.
- One account per token — All requests using a token act as that account and share its rate limits. For per-member isolation, use separate CourtListener accounts.
- Session state is keyed to the credential — Pagination cursors and citation-analysis jobs started under an API token are shared by every instance sending that token (useful for stateless fleets), but are not visible to the same account connected over OAuth. This state expires after an hour regardless.
- Rate limits are your account's API limits — The MCP server adds no limits of its own. Check your allowance and current usage on your API usage page. Elevated access is available through a Free Law Project membership or commercial agreement — see "Increased Usage" on the overview page.
Troubleshooting
Every request returns 401.
Check the scheme first: Authorization: Token <api-token>, not Bearer. If
the scheme is right, confirm the token is current in your
profile settings — regenerating a token invalidates the old one
immediately.
Tool calls fail with "CourtListener rejected the request as unauthorized." The token was valid recently (the server caches verifications briefly) but CourtListener now rejects it — usually a regenerated token. Update the header; the next request re-verifies from scratch.
Server status.
https://mcp.courtlistener.com/health returns JSON with server status and the
deployed version — useful if you need to report an incident.
Learn More
Found a bug or missing feature? File an issue in the MCP server repository. If you'd like to discuss commercial access or higher usage tiers, please get in touch.