MCP Server
What it is
FreeRouter exposes an MCP server at https://api.freerouter.com/mcp. Point Cursor, Claude, VS Code, or any Streamable HTTP MCP client at that URL and pass a management API key (fr_mgmt_…) as a Bearer token. The tools are the same operations as the management REST API: list gateways, store provider keys, mint / update / revoke FreeRouter keys, attach routing, plus usage and account.
This is not an inference endpoint. MCP cannot run /v1/chat/completions. Use a FreeRouter key (fr_live_…) against https://api.freerouter.com/v1 for that — see the API Reference. To attach catalog MCP servers to those chat calls, see MCP Tools.
Endpoint & auth
https://api.freerouter.com/mcp
Authorization: Bearer $FREEROUTER_MANAGEMENT_KEY
Transport is Streamable HTTP: POST JSON-RPC 2.0, application/json responses. GET returns 405. Missing, invalid, revoked, or inference-shaped secrets return 401.
Protocol versions. initialize accepts 2024-11-05, 2025-03-26 and 2025-11-25 and echoes the one you sent; any other value negotiates down to 2025-03-26, the server's own version. Every response carries an MCP-Protocol-Version: 2025-03-26 header. Sessions are stateless — there is no Mcp-Session-Id to keep.
The two key types stay split:
fr_mgmt_…authenticates/mcp(and the management REST API on the app host). Presenting one to/v1returns401.fr_live_…authenticates inference on/v1. Presenting one to/mcpreturns401.
IP allowlists restrict FreeRouter keys only. /mcp and management keys are not covered by them; the tools can set allowed_ips on FreeRouter keys.
Client config
Create a management key under Settings → Management API Keys, then drop it into the client. Store the secret in the client's env or secrets store — never commit it.
Cursor
{
"mcpServers": {
"freerouter": {
"url": "https://api.freerouter.com/mcp",
"headers": {
"Authorization": "Bearer ${FREEROUTER_MANAGEMENT_KEY}"
}
}
}
}
Claude / Claude Code
{
"mcpServers": {
"freerouter": {
"type": "http",
"url": "https://api.freerouter.com/mcp",
"headers": {
"Authorization": "Bearer ${FREEROUTER_MANAGEMENT_KEY}"
}
}
}
}
curl (initialize)
curl https://api.freerouter.com/mcp \
-H "Authorization: Bearer $FREEROUTER_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "curl", "version": "0" }
}
}'
Tools
v1 mirrors the management REST API. Tool results are JSON text. Write tools are marked below.
| Tool | What it does | Write? |
|---|---|---|
list_gateways | Catalog of gateway identifiers (openrouter, vercel, …). Use id as gateway when creating a provider key. | No |
list_provider_keys | List BYOK provider keys (metadata, never secrets). Each id is the UUID to pass as provider_key_id. Optional gateway filter. | No |
get_provider_key | Fetch one provider key by UUID. | No |
create_provider_key | Store a provider key. Secret never returned. Cloudflare needs config.account_id. | Yes |
update_provider_key | Rename (name/label) and/or disabled: true|false. Provider notes are dashboard-only. | Yes |
delete_provider_key | Delete and strip the UUID from every routing rule. | Yes |
list_api_keys | List FreeRouter keys (metadata, never secrets), including each key's routing rule. Optional offset. | No |
get_api_key | Fetch one key by id, including routing. | No |
create_api_key | Mint a FreeRouter key. Secret returned once as key. Optional name/label, api_shape, routing, companion_ads (Companion Ads), keyterms (Monetizable Keyterms; stored as false unless the operator has set FR_KEYTERMS_ENABLED), allowed_ips (IP allowlist), steering_message (steering), failover_ttfb_ms / upstream_timeout_ms (timeouts). The key's free-text notes are dashboard-only — not on this surface or the REST API. | Yes |
update_api_key | Rename (name/label), revoked: true|false (idempotent: true on a revoked key and false on a live one are no-ops),companion_ads: true|false, keyterms: true|false (same FR_KEYTERMS_ENABLED gate), allowed_ips ([] clears), steering_message (null clears), and/or failover_ttfb_ms / upstream_timeout_ms (timeouts; null resets to 5s / 60s). Every field is validated first and the call applies as one transaction, so it lands whole or changes nothing; a restore applies before the other fields and a revoke after them. Any other field on a key that stays revoked is a key_revoked tool error ("Restore it first with { revoked: false }"), as is set_routing on a revoked key. | Yes |
revoke_api_key | Revoke by id (row retained; restore with update_api_key). Idempotent: an already-revoked key answers as it is. | Yes |
get_routing | Fetch the routing rule for a FreeRouter key. | No |
set_routing | Replace routing. Attach stored providers by UUID (provider_key_id), not gateway slug. strategy priority or split. A target's optional ttfb_ms is its own failover timeout (omit to keep the stored one, null to clear). Optional model_remaps rewrites one incoming model to a fixed provider/model (enabled: false stages a remap without serving it). Optional decisioner: { provider_key_id, objective?, allow_model_override?, max_usd_m?, notes?, models? } is a TypeSafe, OpenRouter, Requesty, Vercel, or Ramp Router key that runs Jev as a pre-router on chat keys (objective cost / capability / efficiency); allow_model_override lets Jev pick a listed model; models is an explicit list of model ids (max 12); omit to turn it off. A call replaces the whole rule: leaving out model_remaps or decisioner clears them. Same limits as the REST API (what a rule may contain): 1–10 targets, never empty; split weights whole numbers 0–1,000,000 with one above 0; at most 20 remaps, ids up to 200 characters, enabled remaps per match totalling at most 100%; objective cost / capability / efficiency; max_usd_m above 0. | Yes |
get_usage_summary | Totals for range 24h|7d|30d. Optional api_key_id. | No |
get_usage_series | Zero-filled time buckets. Same filters. | No |
get_usage_breakdown | Top 12 by by=model|gateway. Same filters. | No |
get_account | Workspace profile + key/provider inventory. No secrets, no member emails. | No |
list_gateways → create_provider_key → create_api_key with routing (or set_routing later). Pass the provider UUID as provider_key_id — not the gateway slug. Calls on an unrouted key return 402.
Read-only keys
A management key flagged read-only can call every read tool. Write tools (create_provider_key, update_provider_key, delete_provider_key, create_api_key, update_api_key, revoke_api_key, set_routing) return a tool error: This management API key is read-only. Writes are not allowed. The HTTP status stays 200 — that is MCP isError, not a JSON-RPC transport failure. Flag the key in Settings; a key cannot escalate itself.
MCP vs the management REST API
Same workspace operations, two protocols:
- REST —
https://app.freerouter.com/api/v1(/gateways,/providers,/keys,/keys/:id/routing,/usage/*,/account). Best for backends and scripts. Documented on Management API Keys. - MCP —
https://api.freerouter.com/mcp. Best for agents and IDEs.
Both take Authorization: Bearer $FREEROUTER_MANAGEMENT_KEY. Inference stays off this surface — use an fr_live_… key against /v1 for that.