MCP tools
The MCP server's nine tools, what each takes and returns, and when it refuses.
The MCP server lives at https://binference.io/api/mcp. To connect a client, see MCP server.
Requests
- Streamable HTTP, without sessions. It speaks MCP's 2026-07-28 revision and every 2025 revision. Each request stands alone, so every message is a
POST.GETandDELETEanswer405. - Your key on every request, as
Authorization: Bearer binf_...orx-api-key. - Small bodies. A request over 64 KB answers
413. - 60 requests a minute per key, up to 20 at once after a pause. Faster answers
429. - A fixed tool list. The tools never change while you're connected, so the server sends no change notifications and opens no listen streams.
- From anywhere. Any origin may call it, like the rest of the API.
HTTP answers
Every tool answers 200, even when it refuses (see Refusals). Other statuses come before a tool runs:
| Status | error | When |
|---|---|---|
401 | unauthorized | No key was sent |
401 | invalid_token | The key is wrong or revoked |
405 | A GET or DELETE | |
413 | The body is over 64 KB | |
429 | The key is over 60 requests a minute. Retry after retry-after | |
503 | temporarily_unavailable | The key couldn't be checked. Retry after retry-after (2 s) |
A 401 carries WWW-Authenticate: Bearer realm="binference". There is no OAuth sign-in: the key is the only way in.
A 429 carries retry-after in seconds and retry-after-ms exactly, and a JSON-RPC error that names the wait:
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32000,
"message": "This key is making MCP requests faster than 60 a minute. Retry in 2 seconds."
}
}Results
Each tool returns its answer twice: as structuredContent, which matches the tool's output schema, and as the same JSON in a text block for clients that read text only.
- Money is US dollars as exact decimal strings, like
"0.0012". Never round-trip it through a float. - Times are ISO 8601 in UTC. Days are UTC dates, like
"2026-09-30". - Read tools are marked read-only, so a client may run them without asking.
revoke_keyis marked destructive, so a client knows to ask first.
Refusals
A tool that can't do what was asked returns isError: true and one sentence that says why. Show it to the user or act on it:
{
"content": [
{
"type": "text",
"text": "This key has a spending limit, so it can only read. Use a key without a limit to create, change or revoke keys, or manage them at https://binference.io/account/keys."
}
],
"isError": true
}| The message starts with | Why |
|---|---|
| This key has a spending limit | Only a key without a limit can create, change or revoke |
| No key 12 belongs to this agent | The key id is another agent's, or doesn't exist |
| This agent already has 10 active keys | Revoke one first |
| This agent made 20 keys over MCP | It can make 20 in any 24 hours. Try later, or create one on the keys page |
| This agent is not active | A suspended agent can't get new keys |
label: or spending_limit.usd: | That input is wrong. The rest of the sentence says how |
| Input validation error | An input is missing, of the wrong type or out of range |
| bInference could not finish this right now | Nothing on your side is wrong. Retry in a moment |
get_balance
What the key can spend. No inputs. It returns the same body as Get balance.
{
"object": "balance",
"agent": {
"id": 42,
"name": "Nova",
"token": "0x9f3c7e2b8a41d05c6e1f9a8b7c2d3e4f50617777",
"status": "active"
},
"spendable_usd": "18.40211",
"balance_usd": "18.42211",
"reserved_usd": "0.02",
"running_calls": 1,
"expiring": [
{ "at": "2026-10-02T00:00:00.000Z", "usd": "2.1084" },
{ "at": "2026-10-03T00:00:00.000Z", "usd": "4.92" }
],
"key_limit": null
}spendable_usdis what new calls can reserve right now: the balance less what running calls hold.expiringis what is left of each day's credit and when it expires, soonest first. Credit lasts 7 days.key_limitis this key's spending limit, ornull. It has the same fields asspending_limitbelow.agent.tokenisnullfor an account.
get_limits
The limits on this key and its agent. No inputs.
{
"key": {
"id": 12,
"label": "prod-server",
"prefix": "binf_7Hq2xYv9aB",
"can_manage_keys": false,
"spending_limit": {
"limit_usd": "5",
"reset": "daily",
"spent_usd": "1.2",
"reserved_usd": "0.02",
"remaining_usd": "3.78",
"resets_at": "2026-10-01T00:00:00.000Z"
}
},
"agent": {
"calls_per_minute": 600,
"burst": 60,
"max_running_calls": 8,
"running_calls": 1,
"max_active_keys": 10,
"active_keys": 3
},
"request": { "max_body_mb": 4, "max_stream_minutes": 30, "max_call_minutes": 13 },
"mcp": { "requests_per_minute": 60, "burst": 20, "keys_per_day": 20 },
"images": {
"uploads_per_day": 200,
"max_upload_mb": 20,
"upload_link_hours": 24,
"result_link_days": 7,
"max_results_gb": 5
}
}can_manage_keysistruewhen the key has no spending limit.spending_limit.remaining_usdis what the key may still start this period: the limit less what it spent and what its running calls hold.- The
agentlimits are shared by all of the agent's keys. See Rate limits. mcpis this server's own limits: requests per key, and keys the agent may make here in 24 hours.imagesis what image storage allows the agent.
get_usage
What the agent spent, by day and by model. It counts every key of the agent.
| Input | Type | Default | What it is |
|---|---|---|---|
days | integer | 7 | How many UTC days back, today included: 1 to 90. 1 is today only |
{
"from": "2026-09-24",
"to": "2026-09-30",
"total": { "usd": "3.4102", "calls": 212, "tokens": 1840210 },
"days": [
{ "day": "2026-09-29", "usd": "1.9", "calls": 130, "tokens": 1102400 },
{ "day": "2026-09-30", "usd": "1.5102", "calls": 82, "tokens": 737810 }
],
"models": [
{
"model": "anthropic/claude-sonnet-5.5",
"name": "Claude Sonnet 5.5",
"usd": "3.1",
"calls": 120,
"tokens": 1400000
},
{
"model": "google/gemini-3.8-flash",
"name": "Gemini 3.8 Flash",
"usd": "0.3102",
"calls": 92,
"tokens": 440210
}
]
}Days without calls are left out. Models are listed by spend, highest first. A call counts once its cost is known, usually within a minute.
list_calls
The agent's calls, newest first.
| Input | Type | Default | What it is |
|---|---|---|---|
key_id | integer | Only this key's calls | |
limit | integer | 20 | Calls per page, 1 to 50 |
before | string | The next value of the page before, for older calls |
{
"calls": [
{
"id": 88412,
"started_at": "2026-09-30T11:02:41.118Z",
"duration_ms": 2840,
"key": { "id": 12, "label": "prod-server", "prefix": "binf_7Hq2xYv9aB" },
"model": "anthropic/claude-sonnet-5.5",
"model_name": "Claude Sonnet 5.5",
"endpoint": "messages",
"stream": true,
"outcome": "ok",
"http_status": 200,
"error_code": null,
"tokens": {
"prompt": 8120,
"completion": 412,
"reasoning": null,
"cached": 6400
},
"reserved_usd": "0.1",
"charge_usd": "0.0142"
}
],
"next": "88412"
}outcomeisrunning,pending(finished, its cost not known yet),ok,stopped(your side hung up) orfailed. A failed call has itshttp_statusanderror_code, which Errors explains.reserved_usdis what the call set aside when it started.charge_usdis what it cost,0until it's priced.nextisnullon the last page.
list_keys
The agent's active keys, oldest first. No inputs. A key's secret is never shown.
{
"keys": [
{
"id": 12,
"label": "prod-server",
"prefix": "binf_7Hq2xYv9aB",
"created_at": "2026-09-20T09:12:03.000Z",
"last_used_at": "2026-09-30T11:02:41.000Z",
"month_usd": "24.8",
"spending_limit": null,
"this_key": true,
"created_by_key_id": null
}
],
"max_active": 10
}this_keyistruefor the key this connection uses.created_by_key_idis the key that made it over MCP, ornullfor a key made on the keys page.month_usdis what the key spent this calendar month (UTC).spending_limithas the same fields as inget_limits, or isnull.
create_key
A new key for the agent. Needs a key without a spending limit.
| Input | Type | What it is |
|---|---|---|
label | string, required | A name to recognise it by, one line of up to 60 characters |
spending_limit | object | Leave it out for a key without a limit |
spending_limit.usd | string or number | The most it may spend each period, from 0.01 to 1000000, like "5" |
spending_limit.reset | string | daily, weekly or monthly. Periods start at 00:00 UTC, weeks on Monday |
{
"key": "binf_...",
"id": 15,
"label": "worker-2",
"prefix": "binf_Qp4mZt81Rw",
"created_at": "2026-09-30T12:00:00.000Z",
"spending_limit": {
"limit_usd": "5",
"reset": "daily",
"spent_usd": "0",
"reserved_usd": "0",
"remaining_usd": "5",
"resets_at": "2026-10-01T00:00:00.000Z"
}
}key is shown this once and never again. Store it before doing anything else. An agent may have 10 active keys, and make 20 over MCP in any 24 hours. The new key is recorded as made by the key you're connected with.
update_key
Rename one of the agent's keys, or set, change or remove its spending limit. Needs a key without a spending limit.
| Input | Type | What it is |
|---|---|---|
key_id | integer, required | The key's id, from list_keys |
label | string | The new name |
spending_limit | object or null | The new limit, as in create_key, or null to remove it |
Pass label, spending_limit or both. It returns the key as list_keys shows it. A limit set mid-period counts what the key already spent in that period.
revoke_key
Revoke one of the agent's keys. Needs a key without a spending limit.
| Input | Type | What it is |
|---|---|---|
key_id | integer, required | The key's id, from list_keys |
{ "key_id": 15, "revoked": true, "this_key": false }The key stops on its next call; calls already running finish. Revoking a key twice answers the same. If this_key is true, the connection you're using stops working too.
create_upload
A link to upload one image to, so a model can read a large or local image by link. Any key may use it, for an agent with credit.
| Input | Type | What it is |
|---|---|---|
content_type | string, required | image/png, image/jpeg, image/webp or image/gif |
size | integer, required | The image's exact size in bytes, up to 20 MB (20,971,520) |
It returns what POST /uploads does:
{
"object": "upload",
"id": "upl_BTSNzIeW9d7D_ShZQ8fJEQ",
"upload_url": "https://...r2.cloudflarestorage.com/binference-images/uploads/42/BTSNzIeW9d7D_ShZQ8fJEQ.png?X-Amz-...",
"upload_method": "PUT",
"upload_headers": { "Content-Type": "image/png" },
"upload_expires_at": "2026-10-01T12:10:00.000Z",
"url": "https://...r2.cloudflarestorage.com/binference-images/uploads/42/BTSNzIeW9d7D_ShZQ8fJEQ.png?X-Amz-...",
"expires_at": "2026-10-02T12:00:00.000Z",
"content_type": "image/png",
"size": 3400000
}PUT the image's bytes to upload_url with upload_headers before upload_expires_at, then send url as the image in any model call until expires_at. The PUT must carry exactly size bytes of that type, or storage refuses it. An agent may start 200 uploads in any 24 hours.