Wire up the Litmus MCP server with Clerk OAuth or an API key from Claude Code, Claude Desktop, Cursor, or a custom client.
Authentication
Litmus accepts two bearer-token shapes: Clerk OAuth for interactive clients (Claude Desktop, Claude Code, Cursor) and API keys for headless agents and CI. Both resolve to the same Clerk org — pick whichever fits the calling context.
All examples on this page use the trailing-slash form
https://litmushiring.com/mcp/. The trailing / matters — without it,
most HTTP clients drop the Authorization header across the 308 redirect
and you'll see a confusing 401.
OAuth
Modern MCP clients discover Litmus's OAuth flow automatically. Point the
client at https://litmushiring.com/mcp/ and on first call it'll open a
browser for Clerk sign-in, get a scoped token, and reuse it for subsequent
requests.
OAuth access is admin-only — non-admin members of your Clerk org get a
401 even after a successful sign-in. Same policy as API-key minting.
Claude Code
claude mcp add --transport http litmus https://litmushiring.com/mcp/Verify with /mcp inside a Claude Code session.
Claude Desktop
Open Settings → Connectors → Add custom connector, paste
https://litmushiring.com/mcp/, and follow the Clerk sign-in popup. No
config file edit needed.
Cursor
Add to your mcp.json:
{
"mcpServers": {
"litmus": {
"type": "http",
"url": "https://litmushiring.com/mcp/"
}
}
}Cursor runs the OAuth flow on first use.
API keys
OAuth covers any client a human signs into. API keys cover the rest: CI runners, cron jobs, backend services, and one-off scripts where opening a browser isn't an option. Unlike OAuth tokens, API keys don't expire — they're valid until you revoke them.
Mint a key
In your dashboard, go to Settings → API Keys → Create key, name it, and copy the value — Litmus only shows it once. Revoke anytime from the same page; revocation takes effect on the next request.
Direct bearer (Python / TypeScript / your own agent)
Set the Authorization header on the connection:
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
headers = {"Authorization": "Bearer litmus_sk_..."}
async with streamablehttp_client(
"https://litmushiring.com/mcp/", headers=headers
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
for t in tools.tools:
print(t.name)
asyncio.run(main())The same header works for the artifact streaming URLs returned by
get_submission — one credential covers
the whole surface.
Claude Code (headless / CI)
For service-account use where you don't want OAuth's browser step:
claude mcp add --transport http litmus https://litmushiring.com/mcp/ \
--header "Authorization: Bearer litmus_sk_..."Pass --scope project to write a shared .mcp.json (reference the token
via ${LITMUS_MCP_TOKEN} so the secret isn't committed).
Older clients
Anything that doesn't speak HTTP MCP natively used to need the
mcp-remote stdio-to-HTTP bridge.
We don't recommend it.
CVE-2025-6514 (command
injection, CVSS 9.6) lets a malicious MCP server run arbitrary commands on
the user's machine. Upgrade to a client version with native HTTP MCP support
instead.
Rate limits
The MCP surface is rate-limited per-org, defaulting to 60 requests per minute. All API keys on an org share one bucket, and artifact streaming URLs count against it too — minting more keys won't buy more headroom.
When you exceed the limit you'll get a 429 with a Retry-After header;
see Troubleshooting → 429 Too Many Requests
for the response shape and a backoff snippet. If your workload needs a
higher ceiling, email founders@litmus.build.
