agentbill-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentbill-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AgentBill MCP server. Add spend controls and billing to any AI agent in 3 lines.
|
|
5
|
+
Project-URL: Homepage, https://agentbill.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/marketinglior-pixel/agentbill
|
|
7
|
+
Project-URL: Documentation, https://github.com/marketinglior-pixel/agentbill#readme
|
|
8
|
+
Author-email: AgentBill <marketinglior@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: agent-billing,ai-agents,billing,claude,langchain,llm,mcp,preflight,spend-ceiling,usage-based
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Requires-Dist: mcp[cli]>=1.0.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# agentbill-mcp
|
|
26
|
+
|
|
27
|
+
AgentBill MCP server. Add spend controls and usage billing to any AI agent in 3 lines.
|
|
28
|
+
|
|
29
|
+
## What it does
|
|
30
|
+
|
|
31
|
+
Exposes two tools to any MCP-compatible agent host (Claude Code, Cursor, Windsurf, etc.):
|
|
32
|
+
|
|
33
|
+
- `preflight(agent_id, customer_id, estimated_units, ceiling)` — check if a customer has budget before starting work. Blocks if exhausted.
|
|
34
|
+
- `record_event(agent_id, units, customer_id, metadata)` — bill a customer after work completes. Idempotent.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uvx agentbill-mcp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
No install needed. `uvx` runs it directly.
|
|
43
|
+
|
|
44
|
+
## Configure
|
|
45
|
+
|
|
46
|
+
### Claude Code
|
|
47
|
+
|
|
48
|
+
Add to `~/.claude/settings.json`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"agentbill": {
|
|
54
|
+
"command": "uvx",
|
|
55
|
+
"args": ["agentbill-mcp"],
|
|
56
|
+
"env": {
|
|
57
|
+
"AGENTBILL_API_KEY": "sk_live_your_key_here"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Cursor / Windsurf / other MCP clients
|
|
65
|
+
|
|
66
|
+
Add to your MCP config:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"agentbill": {
|
|
71
|
+
"command": "uvx",
|
|
72
|
+
"args": ["agentbill-mcp"],
|
|
73
|
+
"env": {
|
|
74
|
+
"AGENTBILL_API_KEY": "sk_live_your_key_here"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Get your API key at [agentbill.dev/dashboard](https://agentbill.dev/dashboard).
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
Once configured, any agent using this MCP server can:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
# Before running a task:
|
|
88
|
+
preflight(agent_id="research_agent", customer_id="user_123", estimated_units=5)
|
|
89
|
+
|
|
90
|
+
# After completing the task:
|
|
91
|
+
record_event(agent_id="research_agent", units=5, customer_id="user_123")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The server blocks the run if the customer has no remaining budget. No code changes needed in your agent.
|
|
95
|
+
|
|
96
|
+
## Environment variables
|
|
97
|
+
|
|
98
|
+
| Variable | Required | Default | Description |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `AGENTBILL_API_KEY` | Yes | — | Your AgentBill API key |
|
|
101
|
+
| `AGENTBILL_BASE_URL` | No | `https://agentbill.fly.dev` | Override for self-hosted |
|
|
102
|
+
|
|
103
|
+
## Links
|
|
104
|
+
|
|
105
|
+
- Docs: [agentbill.dev](https://agentbill.dev)
|
|
106
|
+
- Python SDK: `pip install agentbill-sdk`
|
|
107
|
+
- GitHub: [github.com/marketinglior-pixel/agentbill](https://github.com/marketinglior-pixel/agentbill)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# agentbill-mcp
|
|
2
|
+
|
|
3
|
+
AgentBill MCP server. Add spend controls and usage billing to any AI agent in 3 lines.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Exposes two tools to any MCP-compatible agent host (Claude Code, Cursor, Windsurf, etc.):
|
|
8
|
+
|
|
9
|
+
- `preflight(agent_id, customer_id, estimated_units, ceiling)` — check if a customer has budget before starting work. Blocks if exhausted.
|
|
10
|
+
- `record_event(agent_id, units, customer_id, metadata)` — bill a customer after work completes. Idempotent.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uvx agentbill-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No install needed. `uvx` runs it directly.
|
|
19
|
+
|
|
20
|
+
## Configure
|
|
21
|
+
|
|
22
|
+
### Claude Code
|
|
23
|
+
|
|
24
|
+
Add to `~/.claude/settings.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"agentbill": {
|
|
30
|
+
"command": "uvx",
|
|
31
|
+
"args": ["agentbill-mcp"],
|
|
32
|
+
"env": {
|
|
33
|
+
"AGENTBILL_API_KEY": "sk_live_your_key_here"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Cursor / Windsurf / other MCP clients
|
|
41
|
+
|
|
42
|
+
Add to your MCP config:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"agentbill": {
|
|
47
|
+
"command": "uvx",
|
|
48
|
+
"args": ["agentbill-mcp"],
|
|
49
|
+
"env": {
|
|
50
|
+
"AGENTBILL_API_KEY": "sk_live_your_key_here"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Get your API key at [agentbill.dev/dashboard](https://agentbill.dev/dashboard).
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
Once configured, any agent using this MCP server can:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
# Before running a task:
|
|
64
|
+
preflight(agent_id="research_agent", customer_id="user_123", estimated_units=5)
|
|
65
|
+
|
|
66
|
+
# After completing the task:
|
|
67
|
+
record_event(agent_id="research_agent", units=5, customer_id="user_123")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The server blocks the run if the customer has no remaining budget. No code changes needed in your agent.
|
|
71
|
+
|
|
72
|
+
## Environment variables
|
|
73
|
+
|
|
74
|
+
| Variable | Required | Default | Description |
|
|
75
|
+
|---|---|---|---|
|
|
76
|
+
| `AGENTBILL_API_KEY` | Yes | — | Your AgentBill API key |
|
|
77
|
+
| `AGENTBILL_BASE_URL` | No | `https://agentbill.fly.dev` | Override for self-hosted |
|
|
78
|
+
|
|
79
|
+
## Links
|
|
80
|
+
|
|
81
|
+
- Docs: [agentbill.dev](https://agentbill.dev)
|
|
82
|
+
- Python SDK: `pip install agentbill-sdk`
|
|
83
|
+
- GitHub: [github.com/marketinglior-pixel/agentbill](https://github.com/marketinglior-pixel/agentbill)
|
|
File without changes
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import uuid
|
|
5
|
+
from typing import Optional
|
|
6
|
+
import httpx
|
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
|
8
|
+
|
|
9
|
+
mcp = FastMCP(
|
|
10
|
+
"agentbill",
|
|
11
|
+
instructions=(
|
|
12
|
+
"AgentBill is billing infrastructure for AI agents. "
|
|
13
|
+
"Call preflight() before starting any agent work to check if the customer has budget. "
|
|
14
|
+
"Call record_event() after work completes to bill the customer. "
|
|
15
|
+
"Set AGENTBILL_API_KEY in your environment before use."
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
BASE_URL = os.getenv("AGENTBILL_BASE_URL", "https://agentbill.fly.dev")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _headers() -> dict:
|
|
23
|
+
api_key = os.getenv("AGENTBILL_API_KEY")
|
|
24
|
+
if not api_key:
|
|
25
|
+
raise ValueError(
|
|
26
|
+
"AGENTBILL_API_KEY environment variable is not set. "
|
|
27
|
+
"Get your key at agentbill.dev/dashboard"
|
|
28
|
+
)
|
|
29
|
+
return {"Authorization": f"Bearer {api_key}"}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@mcp.tool()
|
|
33
|
+
def preflight(
|
|
34
|
+
agent_id: str,
|
|
35
|
+
customer_id: str = "default",
|
|
36
|
+
estimated_units: int = 1,
|
|
37
|
+
ceiling: Optional[int] = None,
|
|
38
|
+
) -> dict:
|
|
39
|
+
"""
|
|
40
|
+
Check if an agent is allowed to run before starting work.
|
|
41
|
+
|
|
42
|
+
Call this at the start of every agent invocation. Returns approved=True when
|
|
43
|
+
the customer has remaining budget. Returns approved=False with a reason when
|
|
44
|
+
the run should be blocked (budget_exhausted, ceiling_exceeded, free_tier_exceeded).
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
agent_id: Identifier for this agent or task type (e.g. "research_agent").
|
|
48
|
+
customer_id: Your internal customer identifier. Defaults to "default".
|
|
49
|
+
estimated_units: How many units this run is expected to consume. Used for ceiling check.
|
|
50
|
+
ceiling: Max units allowed per single run. Run is blocked if estimated_units exceeds this.
|
|
51
|
+
"""
|
|
52
|
+
payload: dict = {"agent_id": agent_id, "customer_id": customer_id}
|
|
53
|
+
if estimated_units is not None:
|
|
54
|
+
payload["estimated_units"] = estimated_units
|
|
55
|
+
if ceiling is not None:
|
|
56
|
+
payload["ceiling"] = ceiling
|
|
57
|
+
|
|
58
|
+
with httpx.Client(timeout=5) as client:
|
|
59
|
+
resp = client.post(f"{BASE_URL}/preflight", json=payload, headers=_headers())
|
|
60
|
+
|
|
61
|
+
data = resp.json()
|
|
62
|
+
|
|
63
|
+
if not data.get("approved", True):
|
|
64
|
+
reason = data.get("reason", "unknown")
|
|
65
|
+
return {
|
|
66
|
+
"approved": False,
|
|
67
|
+
"reason": reason,
|
|
68
|
+
"remaining_units": data.get("remaining_units"),
|
|
69
|
+
"upgrade_url": data.get("upgrade_url"),
|
|
70
|
+
"message": _blocked_message(reason, data),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
"approved": True,
|
|
75
|
+
"remaining_units": data.get("remaining_units"),
|
|
76
|
+
"estimated_units": data.get("estimated_units"),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@mcp.tool()
|
|
81
|
+
def record_event(
|
|
82
|
+
agent_id: str,
|
|
83
|
+
units: int = 1,
|
|
84
|
+
customer_id: str = "default",
|
|
85
|
+
metadata: Optional[dict] = None,
|
|
86
|
+
) -> dict:
|
|
87
|
+
"""
|
|
88
|
+
Record a billable event after agent work is complete.
|
|
89
|
+
|
|
90
|
+
Call this once per unit of work completed. Safe to call from retried or
|
|
91
|
+
parallel workflows — duplicate submissions are ignored automatically.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
agent_id: Identifier for this agent or task type. Appears in the dashboard.
|
|
95
|
+
units: Number of billable units this event represents. Default is 1.
|
|
96
|
+
customer_id: Your internal customer identifier. Defaults to "default".
|
|
97
|
+
metadata: Optional key-value pairs stored with the event (e.g. model name, latency).
|
|
98
|
+
"""
|
|
99
|
+
payload: dict = {
|
|
100
|
+
"customer_id": customer_id,
|
|
101
|
+
"event_type": agent_id,
|
|
102
|
+
"idempotency_key": f"{agent_id}-{uuid.uuid4()}",
|
|
103
|
+
"units": units,
|
|
104
|
+
}
|
|
105
|
+
if metadata:
|
|
106
|
+
payload["metadata"] = metadata
|
|
107
|
+
|
|
108
|
+
with httpx.Client(timeout=5) as client:
|
|
109
|
+
resp = client.post(f"{BASE_URL}/events", json=payload, headers=_headers())
|
|
110
|
+
|
|
111
|
+
if resp.status_code == 402:
|
|
112
|
+
data = resp.json()
|
|
113
|
+
return {
|
|
114
|
+
"recorded": False,
|
|
115
|
+
"reason": "budget_exhausted",
|
|
116
|
+
"message": data.get("message", "Customer budget is exhausted."),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
resp.raise_for_status()
|
|
120
|
+
data = resp.json()
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
"recorded": True,
|
|
124
|
+
"event_id": data.get("event_id"),
|
|
125
|
+
"status": data.get("status"),
|
|
126
|
+
"customer_remaining_units": data.get("customer_remaining_units"),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _blocked_message(reason: str, data: dict) -> str:
|
|
131
|
+
if reason == "ceiling_exceeded":
|
|
132
|
+
return (
|
|
133
|
+
f"Run blocked: estimated {data.get('estimated_units')} units "
|
|
134
|
+
f"exceeds per-request ceiling of {data.get('ceiling')}."
|
|
135
|
+
)
|
|
136
|
+
if reason == "budget_exhausted":
|
|
137
|
+
return "Run blocked: customer budget is exhausted."
|
|
138
|
+
if reason == "free_tier_exceeded":
|
|
139
|
+
url = data.get("upgrade_url", "agentbill.dev/dashboard")
|
|
140
|
+
return f"Run blocked: free tier limit reached. Upgrade at {url}"
|
|
141
|
+
return f"Run blocked: {reason}"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def main():
|
|
145
|
+
mcp.run()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agentbill-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AgentBill MCP server. Add spend controls and billing to any AI agent in 3 lines."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp[cli]>=1.0.0",
|
|
14
|
+
"httpx>=0.27",
|
|
15
|
+
]
|
|
16
|
+
authors = [
|
|
17
|
+
{ name = "AgentBill", email = "marketinglior@gmail.com" }
|
|
18
|
+
]
|
|
19
|
+
keywords = [
|
|
20
|
+
"mcp",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"billing",
|
|
23
|
+
"llm",
|
|
24
|
+
"agent-billing",
|
|
25
|
+
"spend-ceiling",
|
|
26
|
+
"preflight",
|
|
27
|
+
"usage-based",
|
|
28
|
+
"langchain",
|
|
29
|
+
"claude",
|
|
30
|
+
]
|
|
31
|
+
classifiers = [
|
|
32
|
+
"Development Status :: 3 - Alpha",
|
|
33
|
+
"Intended Audience :: Developers",
|
|
34
|
+
"License :: OSI Approved :: MIT License",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.9",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"Programming Language :: Python :: 3.11",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://agentbill.dev"
|
|
45
|
+
Repository = "https://github.com/marketinglior-pixel/agentbill"
|
|
46
|
+
Documentation = "https://github.com/marketinglior-pixel/agentbill#readme"
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
agentbill-mcp = "agentbill_mcp.server:main"
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.wheel]
|
|
52
|
+
packages = ["agentbill_mcp"]
|