MCP server, a ceiling the agent can consult
MCPPyPI 0.2.2agentbill-mcp is an MCP server with two tools, preflight and record_event. Add it to an agent host and the model can ask a job's ceiling before it starts work, and read the answer. It is a ceiling the agent consults. It is not a gate on the host's own model calls.
Install
uvx agentbill-mcp
uvx runs it without an install step. Add it to your host's MCP servers:
{
"mcpServers": {
"agentbill": {
"command": "uvx",
"args": ["agentbill-mcp"],
"env": {
"AGENTBILL_API_KEY": "agb_your_key_here"
}
}
}
}Put your key where agb_your_key_here is. AGENTBILL_BASE_URL, set beside it in env, points the server at another host.
The two tools
| Tool | Takes | Answers |
|---|---|---|
| preflight | agent_id, customer_id, estimated_units, ceiling, task_ref, task_ceiling, idempotency_key | approved: true with what remains, or approved: false with a reason and a sentence the model can read. A refusal is a value, not an error. |
| record_event | agent_id, units, customer_id, metadata | Records units against a customer's balance. It takes no task_ref. |
The host decides
Nothing forces the call. The model decides whether to call preflight and what to do with approved: false. The server never sees the host's own model requests, so it does not limit what the host itself spends. Tell the agent in its instructions to call preflight before expensive work, and what to do when the answer is no.
Settling a job: record_event takes no task_ref
preflight with a task_ref reserves units against that job's ceiling. record_event cannot settle that reservation, because it takes no task_ref. So with the MCP server alone, every reservation is held until it expires, 60 minutes by default, and its units then come back to the job. The ceiling bounds what is reserved at any one time, not what the whole job spends.
To count a job's spend against its ceiling, settle from code with the same task_ref: record() in the Python or Node SDK, or POST /events:
curl -X POST https://agentbill.dev/events \
-H "Authorization: Bearer $AGENTBILL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"customer_id":"default","event_type":"researcher","idempotency_key":"job-142-step-3","units":12,"task_ref":"job-142"}'customer_id is default because that is what the preflight tool sends when the model passes none, and a settle matches on the customer and the task_ref together.
When to use the SDK instead
When the calls are in code you own, put preflight and record in that code, next to the model call: the quick start, or a guide from the integrations list. The SDK raises on a ceiling refusal, so the refusal reaches your except clause instead of depending on what a model chooses to do.
Source and listing
agentbill-mcp is on PyPI at pypi.org/project/agentbill-mcp, built from the mcp directory of the AgentBill repository.