@billium/mcp 0.1.0
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.
- package/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/index.js +552 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@billium/mcp` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [0.1.0]
|
|
6
|
+
|
|
7
|
+
Initial public release of the Billium MCP server.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **stdio MCP server** exposing the Billium API to any [Model Context Protocol](https://modelcontextprotocol.io) host — Claude Code, Claude Desktop, Cursor, and others. Run with `npx -y @billium/mcp` (bin: `billium-mcp`).
|
|
12
|
+
- **23 tools** across five resources: invoices (`create_invoice`, `get_invoice`, `list_invoices`, `cancel_invoice`), webhooks (`create_webhook`, `list_webhooks`, `update_webhook`, `delete_webhook`, `ping_webhook`), customers (`list_customers`, `get_customer`, `get_customer_stats`, `update_customer`), products (`create_product`, `get_product`, `list_products`, `update_product`, `delete_product`), and wallets (`list_wallets`, `get_wallet`, `create_wallet`, `update_wallet`, `delete_wallet`).
|
|
13
|
+
- **Environment-based configuration.** Reads `BILLIUM_API_KEY` (`sk_...`) and `BILLIUM_MERCHANT_ID` (`mer_...`), with an optional `BILLIUM_BASE_URL` override for self-hosted or testing backends.
|
|
14
|
+
- **Zod-validated tool inputs.** Each tool validates its arguments before forwarding to the SDK, so malformed agent calls fail fast with a clear error rather than a generic API rejection.
|
|
15
|
+
- **Thin wrapper over [`@billium/node`](https://www.npmjs.com/package/@billium/node).** The server adds no custodial layer — your secret key stays on your machine and talks directly to the Billium API over HTTPS.
|
|
16
|
+
- **Automatic idempotency.** `create_invoice` always sends an idempotency key (generated if you don't pass one), so a retried tool call never creates a duplicate invoice.
|
|
17
|
+
- **npm provenance.** Published from GitHub Actions via OIDC Trusted Publishing, so every release carries a verifiable attestation tying the tarball to its source commit. Verify with `npm audit signatures @billium/mcp`.
|
|
18
|
+
|
|
19
|
+
[0.1.0]: https://github.com/BilliumHQ/billium-node/releases/tag/mcp-v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Billium
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @billium/mcp
|
|
2
|
+
|
|
3
|
+
The official **Billium MCP server** — manage non-custodial crypto invoices and webhooks from any [Model Context Protocol](https://modelcontextprotocol.io) host: Claude Code, Claude Desktop, Cursor, and others.
|
|
4
|
+
|
|
5
|
+
Once connected, you can just ask:
|
|
6
|
+
|
|
7
|
+
> _"Create a $49.99 invoice for order #1234 and give me the checkout link."_
|
|
8
|
+
> _"List my last 10 invoices and tell me which are still awaiting payment."_
|
|
9
|
+
> _"Add a webhook to https://api.myshop.com/billium that fires on invoice.paid."_
|
|
10
|
+
|
|
11
|
+
…and the agent calls Billium directly.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Node.js ≥ 18
|
|
16
|
+
- A Billium **secret** API key (`sk_...`) and your **merchant ID** (`mer_...`), from the dashboard under **Settings → Developer → API keys**.
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
The server reads three environment variables:
|
|
21
|
+
|
|
22
|
+
| Variable | Required | Description |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `BILLIUM_API_KEY` | ✅ | Secret API key (`sk_...`) |
|
|
25
|
+
| `BILLIUM_MERCHANT_ID` | ✅ | Merchant ID (`mer_...`) |
|
|
26
|
+
| `BILLIUM_BASE_URL` | — | Override the API base URL (self-hosted / testing) |
|
|
27
|
+
|
|
28
|
+
### Claude Code
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
claude mcp add billium \
|
|
32
|
+
--env BILLIUM_API_KEY=sk_your_key \
|
|
33
|
+
--env BILLIUM_MERCHANT_ID=mer_your_id \
|
|
34
|
+
-- npx -y @billium/mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Claude Desktop / Cursor
|
|
38
|
+
|
|
39
|
+
Add to your MCP config (`claude_desktop_config.json`, or Cursor's `mcp.json`):
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"billium": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["-y", "@billium/mcp"],
|
|
47
|
+
"env": {
|
|
48
|
+
"BILLIUM_API_KEY": "sk_your_key",
|
|
49
|
+
"BILLIUM_MERCHANT_ID": "mer_your_id"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Tools
|
|
57
|
+
|
|
58
|
+
23 tools across invoices, webhooks, customers, products, and wallets.
|
|
59
|
+
|
|
60
|
+
**Invoices**
|
|
61
|
+
|
|
62
|
+
| Tool | Description |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `create_invoice` | Create a crypto payment invoice (auto idempotency key) |
|
|
65
|
+
| `get_invoice` | Fetch an invoice by ID with status, payments, and timeline |
|
|
66
|
+
| `list_invoices` | List invoices with pagination and search |
|
|
67
|
+
| `cancel_invoice` | Cancel an unpaid invoice |
|
|
68
|
+
|
|
69
|
+
**Webhooks**
|
|
70
|
+
|
|
71
|
+
| Tool | Description |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `create_webhook` | Register a webhook endpoint for invoice/payment events |
|
|
74
|
+
| `list_webhooks` | List configured webhook endpoints |
|
|
75
|
+
| `update_webhook` | Update a webhook's URL, events, or settings |
|
|
76
|
+
| `delete_webhook` | Delete a webhook endpoint |
|
|
77
|
+
| `ping_webhook` | Send a test event to a webhook endpoint |
|
|
78
|
+
|
|
79
|
+
**Customers**
|
|
80
|
+
|
|
81
|
+
| Tool | Description |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `list_customers` | List customers with pagination and search |
|
|
84
|
+
| `get_customer` | Fetch a customer by ID |
|
|
85
|
+
| `get_customer_stats` | Revenue and invoice stats for a customer |
|
|
86
|
+
| `update_customer` | Update a customer's name/address/phone |
|
|
87
|
+
|
|
88
|
+
**Products**
|
|
89
|
+
|
|
90
|
+
| Tool | Description |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `create_product` | Create a product for hosted checkout |
|
|
93
|
+
| `get_product` | Fetch a product by ID |
|
|
94
|
+
| `list_products` | List products with pagination and search |
|
|
95
|
+
| `update_product` | Update a product |
|
|
96
|
+
| `delete_product` | Delete a product |
|
|
97
|
+
|
|
98
|
+
**Wallets**
|
|
99
|
+
|
|
100
|
+
| Tool | Description |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `list_wallets` | List wallet configurations (public config only) |
|
|
103
|
+
| `get_wallet` | Fetch a wallet by ID |
|
|
104
|
+
| `create_wallet` | Add a DIRECT_WALLET (address) or XPUB_WALLET (xpub) |
|
|
105
|
+
| `update_wallet` | Update a wallet's config |
|
|
106
|
+
| `delete_wallet` | Delete a wallet |
|
|
107
|
+
|
|
108
|
+
## Security
|
|
109
|
+
|
|
110
|
+
- Your secret key never leaves your machine — the server runs locally and talks
|
|
111
|
+
directly to the Billium API over HTTPS.
|
|
112
|
+
- Settlement is **non-custodial**: payments go straight to your wallet; Billium
|
|
113
|
+
never holds funds.
|
|
114
|
+
- `create_invoice` always sends an idempotency key (generated if you don't pass
|
|
115
|
+
one), so a retried call never creates a duplicate invoice.
|
|
116
|
+
|
|
117
|
+
## How it works
|
|
118
|
+
|
|
119
|
+
This server is a thin [MCP](https://modelcontextprotocol.io) wrapper over the
|
|
120
|
+
[`@billium/node`](https://www.npmjs.com/package/@billium/node) SDK, exposed over
|
|
121
|
+
stdio. Each tool validates its input with [zod](https://zod.dev) and forwards it
|
|
122
|
+
to the SDK.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
|
|
6
|
+
// src/config.ts
|
|
7
|
+
import { Billium } from "@billium/node";
|
|
8
|
+
function billiumFromEnv(env = process.env) {
|
|
9
|
+
const apiKey = env.BILLIUM_API_KEY?.trim();
|
|
10
|
+
const merchantId = env.BILLIUM_MERCHANT_ID?.trim();
|
|
11
|
+
const missing = [];
|
|
12
|
+
if (!apiKey) missing.push("BILLIUM_API_KEY");
|
|
13
|
+
if (!merchantId) missing.push("BILLIUM_MERCHANT_ID");
|
|
14
|
+
if (missing.length > 0) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Missing required environment variable(s): ${missing.join(", ")}. Generate a secret API key in the Billium dashboard under Settings \u2192 Developer \u2192 API keys.`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return new Billium({
|
|
20
|
+
apiKey,
|
|
21
|
+
merchantId,
|
|
22
|
+
baseUrl: env.BILLIUM_BASE_URL?.trim() || void 0
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/server.ts
|
|
27
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
28
|
+
|
|
29
|
+
// src/tools.ts
|
|
30
|
+
import { randomUUID } from "crypto";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
var WEBHOOK_EVENTS = [
|
|
33
|
+
"invoice.*",
|
|
34
|
+
"invoice.created",
|
|
35
|
+
"invoice.updated",
|
|
36
|
+
"invoice.paid",
|
|
37
|
+
"invoice.underpaid",
|
|
38
|
+
"invoice.overpaid",
|
|
39
|
+
"invoice.expired",
|
|
40
|
+
"invoice.cancelled",
|
|
41
|
+
"payment.*",
|
|
42
|
+
"payment.created",
|
|
43
|
+
"payment.updated",
|
|
44
|
+
"payment.detected",
|
|
45
|
+
"payment.confirmed",
|
|
46
|
+
"payment.paid",
|
|
47
|
+
"payment.underpaid",
|
|
48
|
+
"payment.overpaid",
|
|
49
|
+
"payment.expired"
|
|
50
|
+
];
|
|
51
|
+
function ok(data) {
|
|
52
|
+
const text = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
53
|
+
return { content: [{ type: "text", text }] };
|
|
54
|
+
}
|
|
55
|
+
function fail(err) {
|
|
56
|
+
const status = err?.status;
|
|
57
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
58
|
+
const text = status ? `Billium API error (${status}): ${message}` : `Billium error: ${message}`;
|
|
59
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
60
|
+
}
|
|
61
|
+
function registerTools(server, billium) {
|
|
62
|
+
server.registerTool(
|
|
63
|
+
"create_invoice",
|
|
64
|
+
{
|
|
65
|
+
title: "Create invoice",
|
|
66
|
+
description: "Create a new crypto payment invoice for the merchant and return it, including the hosted checkout URL. The customer pays in crypto; settlement is non-custodial (funds go straight to the merchant wallet). An idempotency key is generated automatically unless you pass one.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
name: z.string().describe('Invoice display name, e.g. "Order #1234".'),
|
|
69
|
+
rawAmount: z.number().positive().describe("Amount in the given currency (e.g. 99.99)."),
|
|
70
|
+
currency: z.string().optional().describe("Currency code, e.g. 'USD'. Defaults to USD."),
|
|
71
|
+
customerEmail: z.string().email().optional(),
|
|
72
|
+
customerName: z.string().optional(),
|
|
73
|
+
customerAddress: z.string().optional(),
|
|
74
|
+
customerPhoneNumber: z.string().optional(),
|
|
75
|
+
description: z.string().optional(),
|
|
76
|
+
redirectUrl: z.string().url().optional().describe("URL to send the customer to after a successful payment."),
|
|
77
|
+
idempotencyKey: z.string().optional().describe(
|
|
78
|
+
"Optional dedup key. If omitted, a UUID is generated so retries never create duplicate invoices."
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
async ({ idempotencyKey, ...params }) => {
|
|
83
|
+
try {
|
|
84
|
+
const invoice = await billium.invoices.create(params, {
|
|
85
|
+
idempotencyKey: idempotencyKey ?? randomUUID()
|
|
86
|
+
});
|
|
87
|
+
return ok(invoice);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
return fail(err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
server.registerTool(
|
|
94
|
+
"get_invoice",
|
|
95
|
+
{
|
|
96
|
+
title: "Get invoice",
|
|
97
|
+
description: "Fetch a single invoice by ID, including its current status, customer, payments, and status timeline.",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
invoiceId: z.string().describe("The invoice ID (inv_...).")
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
async ({ invoiceId }) => {
|
|
103
|
+
try {
|
|
104
|
+
return ok(await billium.invoices.get(invoiceId));
|
|
105
|
+
} catch (err) {
|
|
106
|
+
return fail(err);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
server.registerTool(
|
|
111
|
+
"list_invoices",
|
|
112
|
+
{
|
|
113
|
+
title: "List invoices",
|
|
114
|
+
description: "List the merchant\u2019s invoices with pagination and optional search. Returns a page of invoices plus total/page metadata.",
|
|
115
|
+
inputSchema: {
|
|
116
|
+
page: z.number().int().positive().optional(),
|
|
117
|
+
limit: z.number().int().positive().max(100).optional().describe("Results per page (max 100). Defaults to 10."),
|
|
118
|
+
search: z.string().optional().describe("Filter by invoice name, description, or ID.")
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
async (params) => {
|
|
122
|
+
try {
|
|
123
|
+
return ok(await billium.invoices.list(params));
|
|
124
|
+
} catch (err) {
|
|
125
|
+
return fail(err);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
server.registerTool(
|
|
130
|
+
"cancel_invoice",
|
|
131
|
+
{
|
|
132
|
+
title: "Cancel invoice",
|
|
133
|
+
description: "Cancel an invoice that has not yet been paid. Returns the updated invoice. Already-terminal invoices (paid/expired/cancelled) cannot be cancelled.",
|
|
134
|
+
inputSchema: {
|
|
135
|
+
invoiceId: z.string().describe("The invoice ID (inv_...).")
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
async ({ invoiceId }) => {
|
|
139
|
+
try {
|
|
140
|
+
return ok(await billium.invoices.cancel(invoiceId));
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return fail(err);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
server.registerTool(
|
|
147
|
+
"create_webhook",
|
|
148
|
+
{
|
|
149
|
+
title: "Create webhook",
|
|
150
|
+
description: "Register a webhook endpoint that Billium will POST events to. Use 'invoice.*' or 'payment.*' to subscribe to every event in a category.",
|
|
151
|
+
inputSchema: {
|
|
152
|
+
url: z.string().url().describe("HTTPS URL Billium will POST events to."),
|
|
153
|
+
events: z.array(z.enum(WEBHOOK_EVENTS)).nonempty().describe("Event types to subscribe to."),
|
|
154
|
+
description: z.string().optional(),
|
|
155
|
+
isActive: z.boolean().optional(),
|
|
156
|
+
retryCount: z.number().int().min(0).max(10).optional(),
|
|
157
|
+
timeout: z.number().int().min(1e3).max(3e4).optional()
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
async (params) => {
|
|
161
|
+
try {
|
|
162
|
+
return ok(await billium.webhooks.create(params));
|
|
163
|
+
} catch (err) {
|
|
164
|
+
return fail(err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
server.registerTool(
|
|
169
|
+
"list_webhooks",
|
|
170
|
+
{
|
|
171
|
+
title: "List webhooks",
|
|
172
|
+
description: "List all webhook endpoints configured for the merchant.",
|
|
173
|
+
inputSchema: {}
|
|
174
|
+
},
|
|
175
|
+
async () => {
|
|
176
|
+
try {
|
|
177
|
+
return ok(await billium.webhooks.list());
|
|
178
|
+
} catch (err) {
|
|
179
|
+
return fail(err);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
server.registerTool(
|
|
184
|
+
"update_webhook",
|
|
185
|
+
{
|
|
186
|
+
title: "Update webhook",
|
|
187
|
+
description: "Update an existing webhook endpoint (URL, subscribed events, active state, retries, or timeout). Only the fields you pass are changed.",
|
|
188
|
+
inputSchema: {
|
|
189
|
+
webhookId: z.string().describe("The webhook ID (wh_...)."),
|
|
190
|
+
url: z.string().url().optional(),
|
|
191
|
+
events: z.array(z.enum(WEBHOOK_EVENTS)).nonempty().optional(),
|
|
192
|
+
description: z.string().optional(),
|
|
193
|
+
isActive: z.boolean().optional(),
|
|
194
|
+
retryCount: z.number().int().min(0).max(10).optional(),
|
|
195
|
+
timeout: z.number().int().min(1e3).max(3e4).optional()
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
async ({ webhookId, ...params }) => {
|
|
199
|
+
try {
|
|
200
|
+
return ok(await billium.webhooks.update(webhookId, params));
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return fail(err);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
server.registerTool(
|
|
207
|
+
"delete_webhook",
|
|
208
|
+
{
|
|
209
|
+
title: "Delete webhook",
|
|
210
|
+
description: "Permanently delete a webhook endpoint.",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
webhookId: z.string().describe("The webhook ID (wh_...).")
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
async ({ webhookId }) => {
|
|
216
|
+
try {
|
|
217
|
+
await billium.webhooks.delete(webhookId);
|
|
218
|
+
return ok(`Webhook ${webhookId} deleted.`);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
return fail(err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
server.registerTool(
|
|
225
|
+
"ping_webhook",
|
|
226
|
+
{
|
|
227
|
+
title: "Ping webhook",
|
|
228
|
+
description: "Send a test event to a webhook endpoint to verify it is reachable and that your signature verification works.",
|
|
229
|
+
inputSchema: {
|
|
230
|
+
webhookId: z.string().describe("The webhook ID (wh_...).")
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
async ({ webhookId }) => {
|
|
234
|
+
try {
|
|
235
|
+
await billium.webhooks.ping(webhookId);
|
|
236
|
+
return ok(`Ping sent to webhook ${webhookId}.`);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
return fail(err);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// src/tools-merchant.ts
|
|
245
|
+
import { z as z2 } from "zod";
|
|
246
|
+
var CRYPTOCURRENCIES = [
|
|
247
|
+
"BTC",
|
|
248
|
+
"ETH",
|
|
249
|
+
"USDT",
|
|
250
|
+
"USDC",
|
|
251
|
+
"BNB",
|
|
252
|
+
"SHIB",
|
|
253
|
+
"POL",
|
|
254
|
+
"LTC",
|
|
255
|
+
"DAI",
|
|
256
|
+
"CRO",
|
|
257
|
+
"TRX",
|
|
258
|
+
"UNI"
|
|
259
|
+
];
|
|
260
|
+
var NETWORKS = ["BTC", "ETH", "BNB", "POL", "LTC", "CRO", "TRX"];
|
|
261
|
+
var WALLET_TYPES = ["DIRECT_WALLET", "XPUB_WALLET"];
|
|
262
|
+
var PRODUCT_CURRENCIES = ["USD", "EUR", "GBP", "CAD", "AUD", "JPY"];
|
|
263
|
+
var paginationShape = {
|
|
264
|
+
page: z2.number().int().positive().optional(),
|
|
265
|
+
limit: z2.number().int().positive().max(100).optional(),
|
|
266
|
+
search: z2.string().optional().describe("Free-text search filter.")
|
|
267
|
+
};
|
|
268
|
+
function registerMerchantTools(server, billium) {
|
|
269
|
+
server.registerTool(
|
|
270
|
+
"list_customers",
|
|
271
|
+
{
|
|
272
|
+
title: "List customers",
|
|
273
|
+
description: "List the merchant\u2019s customers (auto-created from invoices) with pagination and optional search by email/name/phone/address.",
|
|
274
|
+
inputSchema: paginationShape
|
|
275
|
+
},
|
|
276
|
+
async (params) => {
|
|
277
|
+
try {
|
|
278
|
+
return ok(await billium.customers.list(params));
|
|
279
|
+
} catch (err) {
|
|
280
|
+
return fail(err);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
server.registerTool(
|
|
285
|
+
"get_customer",
|
|
286
|
+
{
|
|
287
|
+
title: "Get customer",
|
|
288
|
+
description: "Fetch a single customer by ID, including derived location when known.",
|
|
289
|
+
inputSchema: { customerId: z2.string().describe("Customer ID (cus_...).") }
|
|
290
|
+
},
|
|
291
|
+
async ({ customerId }) => {
|
|
292
|
+
try {
|
|
293
|
+
return ok(await billium.customers.get(customerId));
|
|
294
|
+
} catch (err) {
|
|
295
|
+
return fail(err);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
server.registerTool(
|
|
300
|
+
"get_customer_stats",
|
|
301
|
+
{
|
|
302
|
+
title: "Get customer stats",
|
|
303
|
+
description: "Get a customer\u2019s aggregate spend and invoice stats: total revenue from paid invoices, invoice counts, and paid rate.",
|
|
304
|
+
inputSchema: { customerId: z2.string().describe("Customer ID (cus_...).") }
|
|
305
|
+
},
|
|
306
|
+
async ({ customerId }) => {
|
|
307
|
+
try {
|
|
308
|
+
return ok(await billium.customers.stats(customerId));
|
|
309
|
+
} catch (err) {
|
|
310
|
+
return fail(err);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
server.registerTool(
|
|
315
|
+
"update_customer",
|
|
316
|
+
{
|
|
317
|
+
title: "Update customer",
|
|
318
|
+
description: "Update a customer\u2019s name, address, or phone number. Email cannot be changed (it is the key that ties a customer to their invoices).",
|
|
319
|
+
inputSchema: {
|
|
320
|
+
customerId: z2.string().describe("Customer ID (cus_...)."),
|
|
321
|
+
name: z2.string().optional(),
|
|
322
|
+
address: z2.string().optional(),
|
|
323
|
+
phoneNumber: z2.string().optional()
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
async ({ customerId, ...params }) => {
|
|
327
|
+
try {
|
|
328
|
+
return ok(await billium.customers.update(customerId, params));
|
|
329
|
+
} catch (err) {
|
|
330
|
+
return fail(err);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
server.registerTool(
|
|
335
|
+
"create_product",
|
|
336
|
+
{
|
|
337
|
+
title: "Create product",
|
|
338
|
+
description: "Create a product the merchant can sell through a hosted checkout page. Price is a fiat amount; the customer pays the crypto equivalent.",
|
|
339
|
+
inputSchema: {
|
|
340
|
+
name: z2.string().describe("Product display name."),
|
|
341
|
+
price: z2.number().positive().describe("Fiat price (e.g. 19.99). Returned as a string."),
|
|
342
|
+
currency: z2.enum(PRODUCT_CURRENCIES).optional(),
|
|
343
|
+
description: z2.string().optional(),
|
|
344
|
+
image: z2.string().optional().describe("Storage key of a previously uploaded image."),
|
|
345
|
+
isActive: z2.boolean().optional(),
|
|
346
|
+
askForName: z2.boolean().optional(),
|
|
347
|
+
askForAddress: z2.boolean().optional(),
|
|
348
|
+
askForPhoneNumber: z2.boolean().optional()
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
async (params) => {
|
|
352
|
+
try {
|
|
353
|
+
return ok(await billium.products.create(params));
|
|
354
|
+
} catch (err) {
|
|
355
|
+
return fail(err);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
server.registerTool(
|
|
360
|
+
"get_product",
|
|
361
|
+
{
|
|
362
|
+
title: "Get product",
|
|
363
|
+
description: "Fetch a single product by ID (with a presigned image URL).",
|
|
364
|
+
inputSchema: { productId: z2.string().describe("Product ID (prd_...).") }
|
|
365
|
+
},
|
|
366
|
+
async ({ productId }) => {
|
|
367
|
+
try {
|
|
368
|
+
return ok(await billium.products.get(productId));
|
|
369
|
+
} catch (err) {
|
|
370
|
+
return fail(err);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
);
|
|
374
|
+
server.registerTool(
|
|
375
|
+
"list_products",
|
|
376
|
+
{
|
|
377
|
+
title: "List products",
|
|
378
|
+
description: "List the merchant\u2019s products with pagination and optional search.",
|
|
379
|
+
inputSchema: paginationShape
|
|
380
|
+
},
|
|
381
|
+
async (params) => {
|
|
382
|
+
try {
|
|
383
|
+
return ok(await billium.products.list(params));
|
|
384
|
+
} catch (err) {
|
|
385
|
+
return fail(err);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
server.registerTool(
|
|
390
|
+
"update_product",
|
|
391
|
+
{
|
|
392
|
+
title: "Update product",
|
|
393
|
+
description: "Update a product. Only the fields you pass are changed.",
|
|
394
|
+
inputSchema: {
|
|
395
|
+
productId: z2.string().describe("Product ID (prd_...)."),
|
|
396
|
+
name: z2.string().optional(),
|
|
397
|
+
price: z2.number().positive().optional(),
|
|
398
|
+
currency: z2.enum(PRODUCT_CURRENCIES).optional(),
|
|
399
|
+
description: z2.string().optional(),
|
|
400
|
+
image: z2.string().optional(),
|
|
401
|
+
isActive: z2.boolean().optional(),
|
|
402
|
+
askForName: z2.boolean().optional(),
|
|
403
|
+
askForAddress: z2.boolean().optional(),
|
|
404
|
+
askForPhoneNumber: z2.boolean().optional()
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
async ({ productId, ...params }) => {
|
|
408
|
+
try {
|
|
409
|
+
return ok(await billium.products.update(productId, params));
|
|
410
|
+
} catch (err) {
|
|
411
|
+
return fail(err);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
server.registerTool(
|
|
416
|
+
"delete_product",
|
|
417
|
+
{
|
|
418
|
+
title: "Delete product",
|
|
419
|
+
description: "Delete a product.",
|
|
420
|
+
inputSchema: { productId: z2.string().describe("Product ID (prd_...).") }
|
|
421
|
+
},
|
|
422
|
+
async ({ productId }) => {
|
|
423
|
+
try {
|
|
424
|
+
return ok(await billium.products.delete(productId));
|
|
425
|
+
} catch (err) {
|
|
426
|
+
return fail(err);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
server.registerTool(
|
|
431
|
+
"list_wallets",
|
|
432
|
+
{
|
|
433
|
+
title: "List wallets",
|
|
434
|
+
description: "List the merchant\u2019s crypto wallet configurations (DIRECT_WALLET / XPUB_WALLET). Only public config is returned \u2014 never private keys.",
|
|
435
|
+
inputSchema: {}
|
|
436
|
+
},
|
|
437
|
+
async () => {
|
|
438
|
+
try {
|
|
439
|
+
return ok(await billium.wallets.list());
|
|
440
|
+
} catch (err) {
|
|
441
|
+
return fail(err);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
);
|
|
445
|
+
server.registerTool(
|
|
446
|
+
"get_wallet",
|
|
447
|
+
{
|
|
448
|
+
title: "Get wallet",
|
|
449
|
+
description: "Fetch a single wallet configuration by ID.",
|
|
450
|
+
inputSchema: { walletId: z2.string().describe("Wallet ID (wal_...).") }
|
|
451
|
+
},
|
|
452
|
+
async ({ walletId }) => {
|
|
453
|
+
try {
|
|
454
|
+
return ok(await billium.wallets.get(walletId));
|
|
455
|
+
} catch (err) {
|
|
456
|
+
return fail(err);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
);
|
|
460
|
+
server.registerTool(
|
|
461
|
+
"create_wallet",
|
|
462
|
+
{
|
|
463
|
+
title: "Create wallet",
|
|
464
|
+
description: "Add a receiving wallet for a (cryptocurrency, network) pair. Pass `address` for a DIRECT_WALLET, or `xpub` (extended PUBLIC key) for an XPUB_WALLET. One wallet per pair.",
|
|
465
|
+
inputSchema: {
|
|
466
|
+
cryptocurrency: z2.enum(CRYPTOCURRENCIES),
|
|
467
|
+
network: z2.enum(NETWORKS),
|
|
468
|
+
walletType: z2.enum(WALLET_TYPES),
|
|
469
|
+
address: z2.string().optional().describe("Required for DIRECT_WALLET."),
|
|
470
|
+
xpub: z2.string().optional().describe("Extended PUBLIC key \u2014 required for XPUB_WALLET (BTC/LTC)."),
|
|
471
|
+
derivationPath: z2.string().optional(),
|
|
472
|
+
isEnabled: z2.boolean().optional(),
|
|
473
|
+
requiredConfirmations: z2.number().int().min(1).max(100).optional()
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
async (params) => {
|
|
477
|
+
try {
|
|
478
|
+
return ok(await billium.wallets.create(params));
|
|
479
|
+
} catch (err) {
|
|
480
|
+
return fail(err);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
server.registerTool(
|
|
485
|
+
"update_wallet",
|
|
486
|
+
{
|
|
487
|
+
title: "Update wallet",
|
|
488
|
+
description: "Update a wallet\u2019s mutable config (address, xpub, enabled state, confirmations, derivation path). Identity fields cannot change.",
|
|
489
|
+
inputSchema: {
|
|
490
|
+
walletId: z2.string().describe("Wallet ID (wal_...)."),
|
|
491
|
+
address: z2.string().optional(),
|
|
492
|
+
xpub: z2.string().optional(),
|
|
493
|
+
isEnabled: z2.boolean().optional(),
|
|
494
|
+
requiredConfirmations: z2.number().int().min(1).max(100).optional(),
|
|
495
|
+
derivationPath: z2.string().optional()
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
async ({ walletId, ...params }) => {
|
|
499
|
+
try {
|
|
500
|
+
return ok(await billium.wallets.update(walletId, params));
|
|
501
|
+
} catch (err) {
|
|
502
|
+
return fail(err);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
server.registerTool(
|
|
507
|
+
"delete_wallet",
|
|
508
|
+
{
|
|
509
|
+
title: "Delete wallet",
|
|
510
|
+
description: "Delete a wallet. Rejected if it still has active payments against it.",
|
|
511
|
+
inputSchema: { walletId: z2.string().describe("Wallet ID (wal_...).") }
|
|
512
|
+
},
|
|
513
|
+
async ({ walletId }) => {
|
|
514
|
+
try {
|
|
515
|
+
return ok(await billium.wallets.delete(walletId));
|
|
516
|
+
} catch (err) {
|
|
517
|
+
return fail(err);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/version.ts
|
|
524
|
+
var MCP_VERSION = "0.1.0";
|
|
525
|
+
|
|
526
|
+
// src/server.ts
|
|
527
|
+
function createServer(billium) {
|
|
528
|
+
const server = new McpServer({
|
|
529
|
+
name: "billium",
|
|
530
|
+
version: MCP_VERSION
|
|
531
|
+
});
|
|
532
|
+
registerTools(server, billium);
|
|
533
|
+
registerMerchantTools(server, billium);
|
|
534
|
+
return server;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// src/index.ts
|
|
538
|
+
async function main() {
|
|
539
|
+
const billium = billiumFromEnv();
|
|
540
|
+
const server = createServer(billium);
|
|
541
|
+
const transport = new StdioServerTransport();
|
|
542
|
+
await server.connect(transport);
|
|
543
|
+
console.error("Billium MCP server running on stdio.");
|
|
544
|
+
}
|
|
545
|
+
main().catch((err) => {
|
|
546
|
+
console.error(
|
|
547
|
+
"Failed to start Billium MCP server:",
|
|
548
|
+
err instanceof Error ? err.message : err
|
|
549
|
+
);
|
|
550
|
+
process.exit(1);
|
|
551
|
+
});
|
|
552
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/server.ts","../src/tools.ts","../src/tools-merchant.ts","../src/version.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport { billiumFromEnv } from './config';\nimport { createServer } from './server';\n\nasync function main(): Promise<void> {\n const billium = billiumFromEnv();\n const server = createServer(billium);\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // stdout is the MCP protocol channel — all human-readable logging must go to\n // stderr so it never corrupts the JSON-RPC stream.\n console.error('Billium MCP server running on stdio.');\n}\n\nmain().catch((err: unknown) => {\n console.error(\n 'Failed to start Billium MCP server:',\n err instanceof Error ? err.message : err,\n );\n process.exit(1);\n});\n","import { Billium } from '@billium/node';\n\n/**\n * Builds a Billium SDK client from environment variables.\n *\n * Required:\n * BILLIUM_API_KEY — secret API key (sk_...)\n * BILLIUM_MERCHANT_ID — merchant ID (mer_...)\n * Optional:\n * BILLIUM_BASE_URL — override the API base URL (self-hosted / testing)\n *\n * Throws a clear error (listing what's missing) so misconfiguration fails fast\n * at startup rather than as a confusing 401 on the first tool call.\n */\nexport function billiumFromEnv(env: NodeJS.ProcessEnv = process.env): Billium {\n const apiKey = env.BILLIUM_API_KEY?.trim();\n const merchantId = env.BILLIUM_MERCHANT_ID?.trim();\n\n const missing: string[] = [];\n if (!apiKey) missing.push('BILLIUM_API_KEY');\n if (!merchantId) missing.push('BILLIUM_MERCHANT_ID');\n if (missing.length > 0) {\n throw new Error(\n `Missing required environment variable(s): ${missing.join(', ')}. ` +\n 'Generate a secret API key in the Billium dashboard under ' +\n 'Settings → Developer → API keys.',\n );\n }\n\n return new Billium({\n apiKey,\n merchantId,\n baseUrl: env.BILLIUM_BASE_URL?.trim() || undefined,\n });\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Billium } from '@billium/node';\n\nimport { registerTools } from './tools';\nimport { registerMerchantTools } from './tools-merchant';\nimport { MCP_VERSION } from './version';\n\n/**\n * Builds the Billium MCP server and registers every tool against the given SDK\n * client. Transport-agnostic — `index.ts` connects it over stdio in production,\n * and tests connect it over an in-memory transport.\n */\nexport function createServer(billium: Billium): McpServer {\n const server = new McpServer({\n name: 'billium',\n version: MCP_VERSION,\n });\n\n registerTools(server, billium);\n registerMerchantTools(server, billium);\n\n return server;\n}\n","import { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Billium, WebhookEventType } from '@billium/node';\n\n/**\n * The 17 webhook event types Billium emits, plus the two category wildcards.\n * Kept in sync with `@billium/node`'s `WebhookEventType` union.\n */\nconst WEBHOOK_EVENTS: [WebhookEventType, ...WebhookEventType[]] = [\n 'invoice.*',\n 'invoice.created',\n 'invoice.updated',\n 'invoice.paid',\n 'invoice.underpaid',\n 'invoice.overpaid',\n 'invoice.expired',\n 'invoice.cancelled',\n 'payment.*',\n 'payment.created',\n 'payment.updated',\n 'payment.detected',\n 'payment.confirmed',\n 'payment.paid',\n 'payment.underpaid',\n 'payment.overpaid',\n 'payment.expired',\n];\n\nexport type ToolResult = {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n};\n\nexport function ok(data: unknown): ToolResult {\n const text =\n typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n return { content: [{ type: 'text', text }] };\n}\n\nexport function fail(err: unknown): ToolResult {\n // Duck-type the SDK's error shape (BilliumApiError carries `status`) so we\n // surface actionable messages without a runtime import of the SDK.\n const status = (err as { status?: number })?.status;\n const message = err instanceof Error ? err.message : String(err);\n const text = status\n ? `Billium API error (${status}): ${message}`\n : `Billium error: ${message}`;\n return { content: [{ type: 'text', text }], isError: true };\n}\n\n/**\n * Registers every Billium tool on the given MCP server, backed by the supplied\n * SDK client. Split out from the transport wiring so tests can drive it with an\n * in-memory client and a mock `Billium`.\n */\nexport function registerTools(server: McpServer, billium: Billium): void {\n // ─── Invoices ──────────────────────────────────────────────────────────\n\n server.registerTool(\n 'create_invoice',\n {\n title: 'Create invoice',\n description:\n 'Create a new crypto payment invoice for the merchant and return it, ' +\n 'including the hosted checkout URL. The customer pays in crypto; ' +\n 'settlement is non-custodial (funds go straight to the merchant wallet). ' +\n 'An idempotency key is generated automatically unless you pass one.',\n inputSchema: {\n name: z.string().describe('Invoice display name, e.g. \"Order #1234\".'),\n rawAmount: z\n .number()\n .positive()\n .describe('Amount in the given currency (e.g. 99.99).'),\n currency: z\n .string()\n .optional()\n .describe(\"Currency code, e.g. 'USD'. Defaults to USD.\"),\n customerEmail: z.string().email().optional(),\n customerName: z.string().optional(),\n customerAddress: z.string().optional(),\n customerPhoneNumber: z.string().optional(),\n description: z.string().optional(),\n redirectUrl: z\n .string()\n .url()\n .optional()\n .describe('URL to send the customer to after a successful payment.'),\n idempotencyKey: z\n .string()\n .optional()\n .describe(\n 'Optional dedup key. If omitted, a UUID is generated so retries ' +\n 'never create duplicate invoices.',\n ),\n },\n },\n async ({ idempotencyKey, ...params }) => {\n try {\n const invoice = await billium.invoices.create(params, {\n idempotencyKey: idempotencyKey ?? randomUUID(),\n });\n return ok(invoice);\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'get_invoice',\n {\n title: 'Get invoice',\n description:\n 'Fetch a single invoice by ID, including its current status, ' +\n 'customer, payments, and status timeline.',\n inputSchema: {\n invoiceId: z.string().describe('The invoice ID (inv_...).'),\n },\n },\n async ({ invoiceId }) => {\n try {\n return ok(await billium.invoices.get(invoiceId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'list_invoices',\n {\n title: 'List invoices',\n description:\n 'List the merchant’s invoices with pagination and optional search. ' +\n 'Returns a page of invoices plus total/page metadata.',\n inputSchema: {\n page: z.number().int().positive().optional(),\n limit: z\n .number()\n .int()\n .positive()\n .max(100)\n .optional()\n .describe('Results per page (max 100). Defaults to 10.'),\n search: z\n .string()\n .optional()\n .describe('Filter by invoice name, description, or ID.'),\n },\n },\n async (params) => {\n try {\n return ok(await billium.invoices.list(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'cancel_invoice',\n {\n title: 'Cancel invoice',\n description:\n 'Cancel an invoice that has not yet been paid. Returns the updated ' +\n 'invoice. Already-terminal invoices (paid/expired/cancelled) cannot ' +\n 'be cancelled.',\n inputSchema: {\n invoiceId: z.string().describe('The invoice ID (inv_...).'),\n },\n },\n async ({ invoiceId }) => {\n try {\n return ok(await billium.invoices.cancel(invoiceId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n // ─── Webhooks ──────────────────────────────────────────────────────────\n\n server.registerTool(\n 'create_webhook',\n {\n title: 'Create webhook',\n description:\n 'Register a webhook endpoint that Billium will POST events to. Use ' +\n \"'invoice.*' or 'payment.*' to subscribe to every event in a category.\",\n inputSchema: {\n url: z.string().url().describe('HTTPS URL Billium will POST events to.'),\n events: z\n .array(z.enum(WEBHOOK_EVENTS))\n .nonempty()\n .describe('Event types to subscribe to.'),\n description: z.string().optional(),\n isActive: z.boolean().optional(),\n retryCount: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(30000).optional(),\n },\n },\n async (params) => {\n try {\n return ok(await billium.webhooks.create(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'list_webhooks',\n {\n title: 'List webhooks',\n description: 'List all webhook endpoints configured for the merchant.',\n inputSchema: {},\n },\n async () => {\n try {\n return ok(await billium.webhooks.list());\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'update_webhook',\n {\n title: 'Update webhook',\n description:\n 'Update an existing webhook endpoint (URL, subscribed events, active ' +\n 'state, retries, or timeout). Only the fields you pass are changed.',\n inputSchema: {\n webhookId: z.string().describe('The webhook ID (wh_...).'),\n url: z.string().url().optional(),\n events: z.array(z.enum(WEBHOOK_EVENTS)).nonempty().optional(),\n description: z.string().optional(),\n isActive: z.boolean().optional(),\n retryCount: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(30000).optional(),\n },\n },\n async ({ webhookId, ...params }) => {\n try {\n return ok(await billium.webhooks.update(webhookId, params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'delete_webhook',\n {\n title: 'Delete webhook',\n description: 'Permanently delete a webhook endpoint.',\n inputSchema: {\n webhookId: z.string().describe('The webhook ID (wh_...).'),\n },\n },\n async ({ webhookId }) => {\n try {\n await billium.webhooks.delete(webhookId);\n return ok(`Webhook ${webhookId} deleted.`);\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'ping_webhook',\n {\n title: 'Ping webhook',\n description:\n 'Send a test event to a webhook endpoint to verify it is reachable ' +\n 'and that your signature verification works.',\n inputSchema: {\n webhookId: z.string().describe('The webhook ID (wh_...).'),\n },\n },\n async ({ webhookId }) => {\n try {\n await billium.webhooks.ping(webhookId);\n return ok(`Ping sent to webhook ${webhookId}.`);\n } catch (err) {\n return fail(err);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Billium } from '@billium/node';\n\nimport { ok, fail } from './tools';\n\n// Enums mirrored from @billium/node so tool inputs are validated up front.\nconst CRYPTOCURRENCIES = [\n 'BTC',\n 'ETH',\n 'USDT',\n 'USDC',\n 'BNB',\n 'SHIB',\n 'POL',\n 'LTC',\n 'DAI',\n 'CRO',\n 'TRX',\n 'UNI',\n] as const;\nconst NETWORKS = ['BTC', 'ETH', 'BNB', 'POL', 'LTC', 'CRO', 'TRX'] as const;\nconst WALLET_TYPES = ['DIRECT_WALLET', 'XPUB_WALLET'] as const;\nconst PRODUCT_CURRENCIES = ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'JPY'] as const;\n\nconst paginationShape = {\n page: z.number().int().positive().optional(),\n limit: z.number().int().positive().max(100).optional(),\n search: z.string().optional().describe('Free-text search filter.'),\n};\n\n/**\n * Registers the merchant data-resource tools (customers, products, wallets)\n * on top of the core invoice/webhook tools. Kept separate from `tools.ts` so\n * each domain stays readable; both are registered by `createServer`.\n */\nexport function registerMerchantTools(\n server: McpServer,\n billium: Billium,\n): void {\n // ─── Customers ─────────────────────────────────────────────────────────\n // Customers are auto-provisioned from invoices — there is no create/delete,\n // only list/get/stats/update.\n\n server.registerTool(\n 'list_customers',\n {\n title: 'List customers',\n description:\n 'List the merchant’s customers (auto-created from invoices) with ' +\n 'pagination and optional search by email/name/phone/address.',\n inputSchema: paginationShape,\n },\n async (params) => {\n try {\n return ok(await billium.customers.list(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'get_customer',\n {\n title: 'Get customer',\n description:\n 'Fetch a single customer by ID, including derived location when known.',\n inputSchema: { customerId: z.string().describe('Customer ID (cus_...).') },\n },\n async ({ customerId }) => {\n try {\n return ok(await billium.customers.get(customerId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'get_customer_stats',\n {\n title: 'Get customer stats',\n description:\n 'Get a customer’s aggregate spend and invoice stats: total revenue ' +\n 'from paid invoices, invoice counts, and paid rate.',\n inputSchema: { customerId: z.string().describe('Customer ID (cus_...).') },\n },\n async ({ customerId }) => {\n try {\n return ok(await billium.customers.stats(customerId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'update_customer',\n {\n title: 'Update customer',\n description:\n 'Update a customer’s name, address, or phone number. Email cannot be ' +\n 'changed (it is the key that ties a customer to their invoices).',\n inputSchema: {\n customerId: z.string().describe('Customer ID (cus_...).'),\n name: z.string().optional(),\n address: z.string().optional(),\n phoneNumber: z.string().optional(),\n },\n },\n async ({ customerId, ...params }) => {\n try {\n return ok(await billium.customers.update(customerId, params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n // ─── Products ──────────────────────────────────────────────────────────\n\n server.registerTool(\n 'create_product',\n {\n title: 'Create product',\n description:\n 'Create a product the merchant can sell through a hosted checkout ' +\n 'page. Price is a fiat amount; the customer pays the crypto equivalent.',\n inputSchema: {\n name: z.string().describe('Product display name.'),\n price: z\n .number()\n .positive()\n .describe('Fiat price (e.g. 19.99). Returned as a string.'),\n currency: z.enum(PRODUCT_CURRENCIES).optional(),\n description: z.string().optional(),\n image: z\n .string()\n .optional()\n .describe('Storage key of a previously uploaded image.'),\n isActive: z.boolean().optional(),\n askForName: z.boolean().optional(),\n askForAddress: z.boolean().optional(),\n askForPhoneNumber: z.boolean().optional(),\n },\n },\n async (params) => {\n try {\n return ok(await billium.products.create(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'get_product',\n {\n title: 'Get product',\n description: 'Fetch a single product by ID (with a presigned image URL).',\n inputSchema: { productId: z.string().describe('Product ID (prd_...).') },\n },\n async ({ productId }) => {\n try {\n return ok(await billium.products.get(productId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'list_products',\n {\n title: 'List products',\n description:\n 'List the merchant’s products with pagination and optional search.',\n inputSchema: paginationShape,\n },\n async (params) => {\n try {\n return ok(await billium.products.list(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'update_product',\n {\n title: 'Update product',\n description:\n 'Update a product. Only the fields you pass are changed.',\n inputSchema: {\n productId: z.string().describe('Product ID (prd_...).'),\n name: z.string().optional(),\n price: z.number().positive().optional(),\n currency: z.enum(PRODUCT_CURRENCIES).optional(),\n description: z.string().optional(),\n image: z.string().optional(),\n isActive: z.boolean().optional(),\n askForName: z.boolean().optional(),\n askForAddress: z.boolean().optional(),\n askForPhoneNumber: z.boolean().optional(),\n },\n },\n async ({ productId, ...params }) => {\n try {\n return ok(await billium.products.update(productId, params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'delete_product',\n {\n title: 'Delete product',\n description: 'Delete a product.',\n inputSchema: { productId: z.string().describe('Product ID (prd_...).') },\n },\n async ({ productId }) => {\n try {\n return ok(await billium.products.delete(productId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n // ─── Wallets ───────────────────────────────────────────────────────────\n\n server.registerTool(\n 'list_wallets',\n {\n title: 'List wallets',\n description:\n 'List the merchant’s crypto wallet configurations (DIRECT_WALLET / ' +\n 'XPUB_WALLET). Only public config is returned — never private keys.',\n inputSchema: {},\n },\n async () => {\n try {\n return ok(await billium.wallets.list());\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'get_wallet',\n {\n title: 'Get wallet',\n description: 'Fetch a single wallet configuration by ID.',\n inputSchema: { walletId: z.string().describe('Wallet ID (wal_...).') },\n },\n async ({ walletId }) => {\n try {\n return ok(await billium.wallets.get(walletId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'create_wallet',\n {\n title: 'Create wallet',\n description:\n 'Add a receiving wallet for a (cryptocurrency, network) pair. Pass ' +\n '`address` for a DIRECT_WALLET, or `xpub` (extended PUBLIC key) for an ' +\n 'XPUB_WALLET. One wallet per pair.',\n inputSchema: {\n cryptocurrency: z.enum(CRYPTOCURRENCIES),\n network: z.enum(NETWORKS),\n walletType: z.enum(WALLET_TYPES),\n address: z\n .string()\n .optional()\n .describe('Required for DIRECT_WALLET.'),\n xpub: z\n .string()\n .optional()\n .describe('Extended PUBLIC key — required for XPUB_WALLET (BTC/LTC).'),\n derivationPath: z.string().optional(),\n isEnabled: z.boolean().optional(),\n requiredConfirmations: z.number().int().min(1).max(100).optional(),\n },\n },\n async (params) => {\n try {\n return ok(await billium.wallets.create(params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'update_wallet',\n {\n title: 'Update wallet',\n description:\n 'Update a wallet’s mutable config (address, xpub, enabled state, ' +\n 'confirmations, derivation path). Identity fields cannot change.',\n inputSchema: {\n walletId: z.string().describe('Wallet ID (wal_...).'),\n address: z.string().optional(),\n xpub: z.string().optional(),\n isEnabled: z.boolean().optional(),\n requiredConfirmations: z.number().int().min(1).max(100).optional(),\n derivationPath: z.string().optional(),\n },\n },\n async ({ walletId, ...params }) => {\n try {\n return ok(await billium.wallets.update(walletId, params));\n } catch (err) {\n return fail(err);\n }\n },\n );\n\n server.registerTool(\n 'delete_wallet',\n {\n title: 'Delete wallet',\n description:\n 'Delete a wallet. Rejected if it still has active payments against it.',\n inputSchema: { walletId: z.string().describe('Wallet ID (wal_...).') },\n },\n async ({ walletId }) => {\n try {\n return ok(await billium.wallets.delete(walletId));\n } catch (err) {\n return fail(err);\n }\n },\n );\n}\n","// Kept in sync with package.json `version`.\nexport const MCP_VERSION = '0.1.0';\n"],"mappings":"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","names":["z","z"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@billium/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official Billium MCP server — manage crypto invoices and webhooks from Claude, Cursor, and any MCP host.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"billium",
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"claude",
|
|
10
|
+
"cursor",
|
|
11
|
+
"crypto",
|
|
12
|
+
"payments",
|
|
13
|
+
"invoice",
|
|
14
|
+
"webhook",
|
|
15
|
+
"ai",
|
|
16
|
+
"agent"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Billium <hello@billium.to>",
|
|
20
|
+
"homepage": "https://billium.to",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/BilliumHQ/billium-node.git",
|
|
24
|
+
"directory": "packages/mcp"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/BilliumHQ/billium-node/issues"
|
|
28
|
+
},
|
|
29
|
+
"type": "module",
|
|
30
|
+
"bin": {
|
|
31
|
+
"billium-mcp": "dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"CHANGELOG.md"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"build:watch": "tsup --watch",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest",
|
|
48
|
+
"lint": "tsc --noEmit",
|
|
49
|
+
"prepublishOnly": "npm run build"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@billium/node": "^1.0.1",
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
|
+
"zod": "^3.23.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^20.0.0",
|
|
61
|
+
"tsup": "^8.0.0",
|
|
62
|
+
"typescript": "^5.4.0",
|
|
63
|
+
"vitest": "^1.5.0"
|
|
64
|
+
}
|
|
65
|
+
}
|