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

bash
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:

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:

python
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:

bash
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.