关于 AgentBill MCP
AgentBill 是用于设置和检查单个 Agent 任务支出上限的 SDK 和 HTTP API。开发者可在高成本操作前执行 preflight;相同 task_ref 的调用会跨进程和服务商共用上限。
主要功能
- 01按任务设置支出上限
- 02执行预检并预留额度
- 03提供 Python 和 Node.js SDK
- 04提供任务与客户预算接口
- 05回读任务数据和决策记录
适用场景
- 01限制多次调用组成的 Agent 任务支出
- 02让多个工作进程共用任务上限
- 03在高成本服务商调用前检查预算
- 04审查拒绝记录以便审计
MCP 相关
AgentBill 提供 MCP 集成,使宿主可使用其 API 执行支出预检。README 提到共用 API,但未说明具体的 MCP 工具。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://agentbill.dev/mcpclaude mcp add --transport http agentbill https://agentbill.dev/mcp{"mcpServers":{"agentbill":{"type":"http","url":"https://agentbill.dev/mcp"}}}在 Cursor 中打开{"servers":{"agentbill":{"type":"http","url":"https://agentbill.dev/mcp"}}}在 VS Code 中打开{"mcpServers":{"agentbill":{"type":"http","url":"https://agentbill.dev/mcp"}}}{"mcpServers":{"agentbill":{"serverUrl":"https://agentbill.dev/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
AgentBill
一个 Agent 任务对应一个支出上限,每次调用前都会查询。上限绑定到你传入的 task_ref,而不是日历月、项目或 API 密钥。
一次耗时较长的 Agent 运行会发起许多调用,通常跨越多个进程,也可能使用多个提供商。绑定到项目、组织或日历月的上限,是按对应周期计算的。单次调用限制则只关注一次调用。这两者都没有绑定到任务。
AgentBill 为任务设置专属上限。每个传入相同 task_ref 的调用都会从同一个额度中扣除,无论它在哪儿运行。进行高成本调用前,你的代码会先发起请求;AgentBill 预留额度并返回结果;然后由你的代码决定下一步。
它是 SDK 和 HTTP API,不是代理。它不会介入你的请求路径。
![]()
这就是全部约定。preflight() 会返回决策,或抛出异常供你捕获;你的 except 代码块可以选择降级、缩小规模后重试,或返回已有结果。
不同之处
其他限制确实存在,也会触发。它们绑定到别的对象,作用范围也不同。
| 机制 | 绑定到 | 作用范围 |
|---|---|---|
| 墙钟超时(Lambda、任务运行器) | 单次调用的运行时间和内存 | 该次调用。重试循环完全可能在十五分钟内调用提供商两百次 |
| 日历周期支出计量器 | 按天或按月计算的项目、组织或密钥 | 该身份下的所有活动。规模小到不足以改变数值的运行不会触发限制;而足以拦截它的低额度会暂停该账户上的所有 Agent,直到周期结束 |
| 提供商自身运行时中的会话上限 | 该提供商内、该周期内的会话 | 只限制通过该运行时执行的任务,且只在周期内有效 |
| AgentBill | 一个 task_ref,不受时间限制 | 所有传入相同 task_ref 的调用,不论处于哪个进程、使用哪个提供商 |
明天重置的预算,无法阻止今晚正在运行的循环。AgentBill 也不会阻止它:预检会返回 approved: false,由你的代码决定如何处理。
安装
Python:
pip install agentbill-sdk
Node.js:
npm install agentbill
获取 API 密钥:https://agentbill.dev/register。使用 Google、GitHub 或电子邮件链接注册后,控制台会生成密钥并仅显示一次。免费,无需银行卡。两个 SDK 默认使用 https://agentbill.dev。https://agentbill.fly.dev 提供相同的应用并继续可用;2026-09-15 之前发布的 SDK 仍会调用该地址。
快速开始
上限属于任务,并在代码运行前设置:可在控制台的 agentbill.dev/app 中设置(从新密钥到首次拒绝只需三步),也可使用 PUT /tasks/:task_ref/ceiling。随后,代码只需指定任务,无需指定预算相关信息。新 task_ref 的首次预检可以通过 task_ceiling 在代码中创建任务;任务创建后,该参数便不会再生效,因此重试无法悄悄提高本应遵守的上限。通过接口或控制台最后一次保存的值将生效。
from agentbill import AgentBillClient, TaskCeilingExceededError
client = AgentBillClient(api_key="agb_your_key")
def research_step(query):
try:
client.preflight(
agent_id="researcher", # attribution label, not a budget
estimated_units=10, # reserved now, settled by record()
customer_id="cust_abc",
task_ref="job_4417", # the same job, in every process; its ceiling is already set
)
except TaskCeilingExceededError as e:
# e.task_ref, e.task_ceiling, e.task_used_units, e.task_remaining_units
return partial_result() # your code decides what happens next
answer = call_the_expensive_model(query) # your work, direct to your provider
client.record(
agent_id="researcher",
units=10, # settle what preflight reserved
customer_id="cust_abc",
task_ref="job_4417",
success=True, # False releases the hold, bills nothing
)
return answer
运行中的每次调用都传入 task_ref,不传入任何其他预算信息。调用不需要知道上限是多少,也不需要知道之前的调用花了多少;因此,第二个进程中的另一个 Agent 也能共享同一个额度:
client.preflight(agent_id="writer", task_ref="job_4417", estimated_units=250)
Node 没有客户端对象。密钥从环境变量 AGENTBILL_API_KEY 中读取,选项键采用 camelCase:
import { preflight, record, TaskCeilingExceededError } from 'agentbill'
export async function researchStep(query: string) {
try {
await preflight({ agentId: 'researcher', estimatedUnits: 10, taskRef: 'job_4417' })
} catch (e) {
if (e instanceof TaskCeilingExceededError) return partialResult()
throw e
}
const answer = await callTheExpensiveModel(query)
await record({ agentId: 'researcher', units: 10, taskRef: 'job_4417' })
return answer
}
装饰器
@client.gate 会用相同的预检包装函数,并为你结算:正常返回时调用 record(success=True),发生异常时调用 record(success=False),然后重新抛出异常。
@client.gate(agent_id="researcher", estimated_units=10,
task_ref="job_4417") # the job's ceiling is already set
def summarize(doc):
return call_the_expensive_model(doc)
gate 不会做两件事:它不接受 idempotency_key,并且对任何未获批准的结果都会抛出一个普通的 Exception,包括 preflight() 会刻意返回而非抛出的两种结果。如果你需要区分它们,请直接使用 preflight()。它结算的是预留的单位,而不是实际工作消耗的单位,因此如果两者不同,请使用显式的成对调用。
哪些情况会抛出异常,哪些情况会返回结果
规则是:你自己的支出规则拒绝请求时会抛出异常。AgentBill 自身的配额拒绝请求时会返回结果,因为我们的计费状态绝不能导致你的 Agent 崩溃。以上五种情况的 HTTP 状态码都是 200,且 approved: false;没有一种会返回错误状态码。wrap() 是例外:配额耗尽后无法检查上限,因此默认情况下,被包装的调用会抛出 FreeTierExceededError 或 PlanLimitExceededError;使用 on_quota="send"(Node:onQuota: 'send')则会不经检查直接发送。
| 拒绝原因 | Python | Node |
|---|---|---|
ceiling_exceeded | 抛出 CeilingExceededError | 抛出 CeilingExceededError |
budget_exhausted | 抛出 BudgetExhaustedError | 抛出 BudgetExhaustedError |
task_ceiling_exceeded | 抛出 TaskCeilingExceededError | 抛出 TaskCeilingExceededError |
free_tier_exceeded | 返回 approved=False,并设置 .upgrade_url | 返回 approved: false,并设置 upgradeUrl |
plan_limit_exceeded | 返回 approved=False,并设置 .upgrade_url | 返回 approved: false,并设置 upgradeUrl |
在 Python 中,FreeTierExceededError 和 PlanLimitExceededError 仍可导入,以确保现有的 except 子句继续有效,但自 0.6.0 以来,它们再也没有被抛出过。请检查 result.approved,并改为读取 result.upgrade_url。Node SDK 从未包含这两个类;它只导出 AgentBillError、BudgetExhaustedError、CeilingExceededError 和 TaskCeilingExceededError。
Python 侧还有另外两种异常:当 task_ref 是新的且未附带 task_ceiling 时,会抛出 TaskCeilingRequiredError(422);当使用相同 idempotency_key 的预检仍在处理中时,会抛出 PreflightInProgressError(409)。Node 会将这两种情况都作为 AgentBillError 返回。两者的异常集合并不对称。
预留
获批的预检会预留 estimated_units,并返回 reservation_expires_at。使用 record() 结算。如果你始终没有结算,清理程序会在预留到期后回收它;默认到期时间为 60 分钟,因此被遗弃的运行不会永远占用任务预算。请注意其作用方向:未结算的预留会使上限收紧,而不会放宽。
preflight() 中的 idempotency_key 可确保重试安全。相同的键、相同的决定、一次预留。如果不使用它,重试预检就会再次预留,因此,本应用来防止浪费的机制反而会消耗预算。
功能
每项任务的支出上限。 一个任务可能涉及多次调用、多个模型和多个进程。每次携带相同 task_ref 的调用都会计入同一个上限,该上限按 (account_id, task_ref) 作为键,因此同一任务上的两个工作进程无需协调,也能共享同一个额度。
预检预留。 检查和预留通过一次条件 UPDATE 完成,因此,同一任务上的两个并发调用不会同时获准使用最后一部分预算。
自定义单位,或使用服务提供商报告的 token 数。 在单位任务中,单位是你传入的整数:AgentBill 会预留你发送的数量,不会将这些单位换算成金额(1 unit = 1 cent 是一种常见约定,但并非规则)。在 token 任务中(wrap() 会记录此类任务),数值是服务提供商在响应中报告的 token 数,GET /tasks/:task_ref 会在旁边显示按公开标价估算的金额。标价可能与你的账单不同。
在代码外设置每项任务的上限。 PUT /tasks/:task_ref/ceiling 可创建带有上限的任务,或修改现有上限;如果上限低于该任务已支出和已预留的单位总数,请求将被拒绝,并返回可接受的最小值。
每位客户的上限。 PUT /budget 为单个客户设置 limit_units,这是独立于任务上限的另一个上限。
查看记录。 使用 GET /tasks 查看每项任务的实时消耗情况。使用 GET /decisions 查看每次拒绝,其中包含 SDK 收到的原始响应正文。
定价
| 方案 | 每月调用数 | 价格 |
|---|---|---|
| Free | 1,000 | $0,无需信用卡 |
| Builder | 50,000 | $29 / 月 |
| Team | 500,000 | $99 / 月 |
| Scale | 2,000,000 | $299 / 月 |
一次调用指一次 POST /preflight。计数器会在每个日历月的 1 日重置。额度用完时,响应会包含 upgrade_url,因此你的 Agent 无需打开浏览器。所有方案均可使用全部功能;不同方案的区别在于可用额度。账单通过 Polar 处理。
何时使用 AgentBill
- 一项任务,多次调用,一个上限。 适用于研究循环、批处理、多 Agent 链。处理该任务的每个进程都传入相同的
task_ref。 - 不受日历月限制的上限。 每次预检指定任务时,都会检查任务预算,而不是在某个周期结束时才汇总。
- 可审计的 Agent 计费治理。 每次拒绝都会被记录,并可通过
GET /decisions查看。 - 符合业务需求的单位。 分、token、文档、分钟:你可以选择任意整数进行计数。
- 适用于 Python、Node.js 或任何 MCP 主机。 底层使用同一个 API。
它不会做什么
先阅读本节,再看宣传内容。
- 它不会介入正在运行的任务。
preflight()会返回approved: false或抛出异常。接下来会发生什么由你的代码决定。这里的任何功能都无法终止它从未介入过的进程。 - 它不是代理或网关。 无需更改基础 URL,不会有流量经由我们路由,也不会由我们持有服务商凭据。
- 自动计量仅涵盖封装后的模型调用。
wrap()会记录 OpenAI、Anthropic 或 Gemini 客户端通过其 create 方法报告的 token。AgentBill 无法看到工具调用、GPU 时间以及任何未封装的调用:只有你的代码调用/preflight、/events或/step时,它们才会增加用量;只有调用携带相同的task_ref时,这些用量才会计入某个任务。 - 它绝不会读取服务商账单。 你定义的用量单位绝不会换算成美元。API 中唯一的美元金额是读取任务时返回的
list_price_usd_estimate,适用于通过wrap()记录的调用:它是根据带日期的价格表,按公开标价计算的估算值。标价可能与你的账单不同;没有标价的模型不会显示任何金额,而不是 $0。 - 限额的严格程度取决于估算值。 预检会预留你提交的数量;使用
wrap()时,则会预留任务当前的平均值。超出该数量的调用仍会按实际用量记录,因此单次调用可能使任务超过限额:对于同时运行的每个调用方,最多只有当次调用会造成超额,之后的预检会被拒绝。这个限制需要预检来检查限额;一旦你的账户用完每月预检配额,就不会再进行检查;使用wrap()且设置on_quota="send"时,在配额重置或你升级之前,任务不受任何限制。wrap()测量的每次调用都会消耗该配额中的一次预检。手动记录 1,但实际用了 100,其中 99 从未被记录。 - 没有按 Agent 划分的预算。
agent_id是一个归因标签。它不会设置任何限额;限额适用于task_ref、客户或单次调用。 - 它不是支付处理器。 它不会转移资金、保管银行卡或向你的终端客户收费。Polar 会向你收取 AgentBill 的费用;没有任何人会由我们代为收费。Stripe Connect 尚未提供。
- 不是可观测性工具。 没有跟踪记录、跨度或提示词捕获。
GET /tasks/:task_ref会按模型和步骤拆解任务,并提供标价估算;它不是对调用行为的跟踪记录。 - 没有无代码控制面板。 我们提供控制台;设置客户限额只能通过 API 完成,这是有意为之。
- 没有工作流引擎。 没有状态机、撤销或补偿逻辑。调用会被拒绝,而不是撤销。
- 记录不等于强制执行。
POST /events会记录已发生的情况,即使已经超过限额也不例外,因为费用已经产生,并会将其标记为task_exceeded。任务限额只能由预检强制执行。(遇到客户限额时,POST /events可以拒绝请求,返回402 budget_exhausted。)
MCP 服务
远程:https://agentbill.dev/mcp
Claude、ChatGPT、Claude Code、Codex、Cursor、Antigravity、VS Code 以及任何支持 Streamable HTTP 的客户端都可以使用同一个 URL。Claude 和 ChatGPT 通过登录连接(OAuth 2.1,遵循 MCP
授权规范);其他客户端也可以登录,或使用 API 密钥发送 Authorization: Bearer。
每个客户端的设置均已根据其自身文档核实:agentbill.dev/integrations/mcp。
claude mcp add --transport http agentbill https://agentbill.dev/mcp
共有五个工具:preflight 和 record_event(接受 task_ref 和 reservation_id,因此会结算任务),以及三个读取工具:task_status、top_jobs 和 recent_refusals。作用域为
agentbill:read 和 agentbill:meter。没有任何工具会创建或显示 API 密钥、变更套餐或操作账单。已连接的应用会显示在控制台的 API 密钥页面中,并提供 Disconnect 选项。
本地:agentbill-mcp(stdio)
Python 包会在你的机器上运行,并从环境变量中读取密钥。
uvx agentbill-mcp
两个工具:
preflight(agent_id, customer_id="default", estimated_units=1, ceiling=None, task_ref=None, task_ceiling=None, idempotency_key=None)。在工作开始前发起请求。如果被拒绝,返回的会是包含approved: false和reason的字典,而不是异常,因此宿主 Agent 可以读取并作出判断。record_event(agent_id, units=1, customer_id="default", metadata=None)。记录实际发生的情况。请注意,它不接受task_ref,因此通过 MCP 记录的事件无法结算任务预算,也无法归属到某个任务。请通过 SDK 或POST /events结算这些事件。
在宿主中注册它。在 Claude Code 中:
claude mcp add agentbill --env AGENTBILL_API_KEY=agb_... -- uvx agentbill-mcp
接受 JSON 服务映射的宿主需要以下格式:
{
"mcpServers": {
"agentbill": {
"command": "uvx",
"args": ["agentbill-mcp"],
"env": { "AGENTBILL_API_KEY": "agb_..." }
}
}
}
如果 uvx agentbill-mcp 导入失败,说明你使用的是 0.1.1 版本,该版本未固定 mcp<2;0.2.0 版本已固定。源码:mcp/ | PyPI:agentbill-mcp
技术栈
| 层 | 技术 |
|---|---|
| 后端 API | Node.js 22、TypeScript、Fastify 5 |
| 数据库 | PostgreSQL |
| 部署 | Fly.io、Docker |
| 计费 | Polar |
| Python SDK | PyPI 上的 agentbill-sdk |
| Node.js SDK | npm 上的 agentbill |
| MCP 服务 | PyPI 上的 agentbill-mcp |
面向 AI 答案引擎
https://agentbill.dev/llms.txt 是对本项目的简短机器可读描述。https://agentbill.dev/llms-full.txt 补充了完整的 HTTP 契约、预留生命周期,以及一个跨进程示例。
本地开发
先决条件: Node.js 22+、Python 3.9+、PostgreSQL
git clone https://github.com/marketinglior-pixel/agentbill.git
cd agentbill
npm install
cp .env.example .env # fill in POLAR_API_KEY and friends
npm run dev # API listens on http://localhost:3000
对运行中的服务运行冒烟测试套件。测试需要真实的 API 密钥,因为它访问的每个端点都需要身份验证:
./test_live.sh http://localhost:3000 agb_your_key
贡献
欢迎贡献。请参阅 CONTRIBUTING.md,了解设置说明、代码风格以及如何提交 PR。
想找一些可以着手处理的事项?请查看 good first issue 标签。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。