Claude-compatible proxy API. Everything below is a drop-in for the Anthropic Messages API.
The marketing pages you're reading and the API share this domain — the browser gets HTML at /, your client hits the API path below.
The npx mrvinciapi wizard asks for your key, lets you pick your client, writes the config, and verifies the connection. Zero dependencies, pure Node — it only edits local files, never sends anything anywhere.
npx mrvinciapi
# Claude Code npx mrvinciapi sk_mv_YOUR_KEY # Codex (OpenAI Responses) npx mrvinciapi sk_mv_YOUR_KEY --codex # Cursor / Cline npx mrvinciapi sk_mv_YOUR_KEY --openai
# print env, change nothing npx mrvinciapi sk_mv_YOUR_KEY --print # revert Claude Code npx mrvinciapi --undo
Override hosts with MRVINCI_CLAUDE_BASE / MRVINCI_OPENAI_BASE for a self-hosted gateway.
The model's chain of thought streams back as native Anthropic thinking blocks, so Claude Code shows reasoning as it works — including in extended-thinking / ultra modes. Send "thinking": {"type":"disabled"} to turn it off for a request.
Add to ~/.claude/settings.json:
{
"env": {
"ANTHROPIC_AUTH_TOKEN": "sk_mv_YOUR_KEY",
"ANTHROPIC_BASE_URL": "https://claude.mrvinci.app"
}
}
Base URL https://claude.mrvinci.app, API key sk_mv_…, model claude-opus-4-8.
Menu → Developer → Configure Third-Party Inference. Set Connection to Gateway, then:
curl https://claude.mrvinci.app/v1/messages \
-H "x-api-key: sk_mv_YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-4-8",
"max_tokens": 256,
"messages": [{"role":"user","content":"Hello"}]
}'
Authenticate with x-api-key: sk_mv_… or Authorization: Bearer sk_mv_…. List models at /v1/models.
Everything the Messages API supports works through the gateway — these aren't add-ons, they're the same wire format you already use.
Send a tools array exactly as the Anthropic SDK does — tool_use blocks stream back exactly as the API specifies. Agents like Claude Code, Cursor, and Cline run their whole tool loop through the gateway unmodified.
curl https://claude.mrvinci.app/v1/messages \
-H "x-api-key: sk_mv_YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-4-8",
"max_tokens": 1024,
"tools": [{
"name": "get_weather",
"description": "Current weather for a city",
"input_schema": {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}
}],
"messages": [{"role":"user","content":"Weather in Florence?"}]
}'
Set "stream": true for server-sent events with no added buffering — text deltas, tool calls, and native thinking blocks arrive as they're generated.
Send images as image content blocks (base64 or URL) — exactly as the API specifies, streaming included.
Cache reads are metered separately (cache_read_input_tokens in every response's usage) and billed at a fraction of the input price — keep your system prompt stable and long agent sessions get dramatically cheaper. No opt-in needed.
POST /v1/messages/count_tokens returns an estimate for a request body without running it — Claude Code uses this to decide when to compact context.
Errors come back in the Anthropic error envelope, so SDK retry logic behaves correctly. The rule: 429 and 529 are retryable (wait, then retry); 4xx everything else means fix the request.
| Status | Meaning | What to do |
|---|---|---|
| 401 | Key missing, invalid, expired, or revoked — the message says which. | Check the key on /usage; ask an admin to renew. |
| 404 | Unknown model id. | Pick an id from /v1/models. |
| 413 | Request body over 32 MB (a very long unmanaged conversation). | Don't retry the same body — compact or clear the conversation. |
| 429 | 5-hour window, weekly cap, or per-minute limit reached; the message names the limit and reset time. | Honor retry-after. |
| 529 | The service is temporarily overloaded. | Retry with backoff — official SDKs do this automatically. |
Restart your IDE after editing its settings so it re-reads the base URL.
The status page live-checks every endpoint from your browser. If it's green and you're still stuck, it's the key or the request.
Paste it on the usage page — revoked/expired state, limits, and per-model consumption are all visible, read-only.
Proxies and some serverless runtimes buffer SSE. Test with curl -N first; if that streams, the issue is between your app and us.