paygate-mcp 7.7.0 → 7.8.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/README.md +28 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +143 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,6 +104,7 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
104
104
|
- **Tool Stats** — `GET /tools/stats` per-tool analytics: call counts, success rate, avg/p95 latency, credits consumed, deny reason breakdown, top 10 consumers — optional `?tool=` for detailed single-tool view, `?since=` filter
|
|
105
105
|
- **Request Log Export** — `GET /requests/export` exports the full request log as JSON or CSV with Content-Disposition headers — filter by key/tool/status/since/until, combined time-window queries, no pagination limit
|
|
106
106
|
- **Tool Call Dry Run** — `POST /requests/dry-run` simulates a tool call without executing — checks key validity, ACL, rate limits, credits, and spending limits, returns predicted outcome with credits-after calculation and rate limit status
|
|
107
|
+
- **Batch Dry Run** — `POST /requests/dry-run/batch` simulates multiple tool calls at once — aggregate credit check, per-tool ACL validation, spending limit, returns per-tool results with total credits required and credits-after
|
|
107
108
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
108
109
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
109
110
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -2273,6 +2274,33 @@ curl -X POST http://localhost:3402/requests/dry-run \
|
|
|
2273
2274
|
|
|
2274
2275
|
Checks key validity, suspension, tool ACL, rate limits, credit balance, and spending limits. Supports alias keys. Useful for agents that want to pre-flight check a call before committing.
|
|
2275
2276
|
|
|
2277
|
+
### Batch Dry Run
|
|
2278
|
+
|
|
2279
|
+
Simulate multiple tool calls at once to check if an entire batch would succeed:
|
|
2280
|
+
|
|
2281
|
+
```bash
|
|
2282
|
+
curl -X POST http://localhost:3402/requests/dry-run/batch \
|
|
2283
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
2284
|
+
-d '{"key": "pg_...", "tools": [{"name": "tool_a"}, {"name": "tool_b"}]}'
|
|
2285
|
+
```
|
|
2286
|
+
|
|
2287
|
+
**Response:**
|
|
2288
|
+
|
|
2289
|
+
```json
|
|
2290
|
+
{
|
|
2291
|
+
"allAllowed": true,
|
|
2292
|
+
"totalCreditsRequired": 10,
|
|
2293
|
+
"creditsAvailable": 100,
|
|
2294
|
+
"creditsAfter": 90,
|
|
2295
|
+
"results": [
|
|
2296
|
+
{ "tool": "tool_a", "allowed": true, "creditsRequired": 5 },
|
|
2297
|
+
{ "tool": "tool_b", "allowed": true, "creditsRequired": 5 }
|
|
2298
|
+
]
|
|
2299
|
+
}
|
|
2300
|
+
```
|
|
2301
|
+
|
|
2302
|
+
Performs aggregate credit check (sum of all tool prices vs balance), per-tool ACL validation, spending limit, and rate limit checks. Returns per-tool results so you can see which specific tools would fail. Max 100 tools per batch. Supports alias keys.
|
|
2303
|
+
|
|
2276
2304
|
### IP Allowlisting
|
|
2277
2305
|
|
|
2278
2306
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/server.d.ts
CHANGED
|
@@ -317,6 +317,7 @@ export declare class PayGateServer {
|
|
|
317
317
|
private handleRequestLog;
|
|
318
318
|
private handleToolStats;
|
|
319
319
|
private handleRequestDryRun;
|
|
320
|
+
private handleRequestDryRunBatch;
|
|
320
321
|
private handleRequestLogExport;
|
|
321
322
|
/** Calculate percentile from an array of numbers. */
|
|
322
323
|
private percentile;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -690,6 +690,12 @@ class PayGateServer {
|
|
|
690
690
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
691
691
|
res.end(JSON.stringify({ error: 'Method not allowed. Use POST.' }));
|
|
692
692
|
return;
|
|
693
|
+
case '/requests/dry-run/batch':
|
|
694
|
+
if (req.method === 'POST')
|
|
695
|
+
return this.handleRequestDryRunBatch(req, res);
|
|
696
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
697
|
+
res.end(JSON.stringify({ error: 'Method not allowed. Use POST.' }));
|
|
698
|
+
return;
|
|
693
699
|
// ─── Registry / Discovery endpoints ──────────────────────────────
|
|
694
700
|
case '/.well-known/mcp-payment':
|
|
695
701
|
return this.handlePaymentMetadata(req, res);
|
|
@@ -1316,6 +1322,7 @@ class PayGateServer {
|
|
|
1316
1322
|
requestLog: 'GET /requests — Queryable log of tool call requests with timing, credits, status (requires X-Admin-Key)',
|
|
1317
1323
|
requestLogExport: 'GET /requests/export — Export request log as JSON or CSV with filters (requires X-Admin-Key)',
|
|
1318
1324
|
requestDryRun: 'POST /requests/dry-run — Simulate a tool call without executing (requires X-Admin-Key)',
|
|
1325
|
+
requestDryRunBatch: 'POST /requests/dry-run/batch — Simulate multiple tool calls without executing (requires X-Admin-Key)',
|
|
1319
1326
|
toolStats: 'GET /tools/stats — Per-tool call counts, success rates, latency, credits, and top consumers (requires X-Admin-Key)',
|
|
1320
1327
|
...(this.oauth ? {
|
|
1321
1328
|
oauthMetadata: 'GET /.well-known/oauth-authorization-server — OAuth 2.1 server metadata',
|
|
@@ -6591,6 +6598,142 @@ class PayGateServer {
|
|
|
6591
6598
|
res.end(JSON.stringify({ error: 'Failed to read request body' }));
|
|
6592
6599
|
}
|
|
6593
6600
|
}
|
|
6601
|
+
// ─── /requests/dry-run/batch — Simulate multiple tool calls without executing ──
|
|
6602
|
+
async handleRequestDryRunBatch(req, res) {
|
|
6603
|
+
if (!this.checkAdmin(req, res))
|
|
6604
|
+
return;
|
|
6605
|
+
try {
|
|
6606
|
+
const raw = await this.readBody(req);
|
|
6607
|
+
try {
|
|
6608
|
+
const params = JSON.parse(raw);
|
|
6609
|
+
const apiKey = params.key;
|
|
6610
|
+
const tools = params.tools;
|
|
6611
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
6612
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6613
|
+
res.end(JSON.stringify({ error: 'Missing required field: key' }));
|
|
6614
|
+
return;
|
|
6615
|
+
}
|
|
6616
|
+
if (!Array.isArray(tools) || tools.length === 0) {
|
|
6617
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6618
|
+
res.end(JSON.stringify({ error: 'Missing required field: tools (non-empty array of {name} objects)' }));
|
|
6619
|
+
return;
|
|
6620
|
+
}
|
|
6621
|
+
if (tools.length > 100) {
|
|
6622
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6623
|
+
res.end(JSON.stringify({ error: 'Maximum 100 tools per batch dry run' }));
|
|
6624
|
+
return;
|
|
6625
|
+
}
|
|
6626
|
+
// Validate tool entries
|
|
6627
|
+
for (let i = 0; i < tools.length; i++) {
|
|
6628
|
+
if (!tools[i]?.name || typeof tools[i].name !== 'string') {
|
|
6629
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6630
|
+
res.end(JSON.stringify({ error: `tools[${i}] missing required "name" field` }));
|
|
6631
|
+
return;
|
|
6632
|
+
}
|
|
6633
|
+
}
|
|
6634
|
+
// Step 1: Key lookup (resolveKeyRaw handles aliases)
|
|
6635
|
+
const keyRecord = this.gate.store.resolveKeyRaw(apiKey);
|
|
6636
|
+
if (!keyRecord) {
|
|
6637
|
+
const isExpired = this.gate.store.isExpired(apiKey);
|
|
6638
|
+
const reason = isExpired ? 'api_key_expired' : 'invalid_api_key';
|
|
6639
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
6640
|
+
res.end(JSON.stringify({
|
|
6641
|
+
allAllowed: false,
|
|
6642
|
+
reason,
|
|
6643
|
+
totalCreditsRequired: 0,
|
|
6644
|
+
results: tools.map((t) => ({ tool: t.name, allowed: false, reason, creditsRequired: 0 })),
|
|
6645
|
+
}));
|
|
6646
|
+
return;
|
|
6647
|
+
}
|
|
6648
|
+
// Step 2: Suspended?
|
|
6649
|
+
if (keyRecord.suspended) {
|
|
6650
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
6651
|
+
res.end(JSON.stringify({
|
|
6652
|
+
allAllowed: false,
|
|
6653
|
+
reason: 'key_suspended',
|
|
6654
|
+
totalCreditsRequired: 0,
|
|
6655
|
+
creditsAvailable: keyRecord.credits,
|
|
6656
|
+
results: tools.map((t) => ({ tool: t.name, allowed: false, reason: 'key_suspended', creditsRequired: 0 })),
|
|
6657
|
+
}));
|
|
6658
|
+
return;
|
|
6659
|
+
}
|
|
6660
|
+
// Step 3: Rate limit check (read-only)
|
|
6661
|
+
const rateStatus = this.gate.rateLimiter.getStatus(keyRecord.key);
|
|
6662
|
+
if (rateStatus.limit > 0 && rateStatus.remaining <= 0) {
|
|
6663
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
6664
|
+
res.end(JSON.stringify({
|
|
6665
|
+
allAllowed: false,
|
|
6666
|
+
reason: 'rate_limited',
|
|
6667
|
+
totalCreditsRequired: 0,
|
|
6668
|
+
creditsAvailable: keyRecord.credits,
|
|
6669
|
+
rateLimit: rateStatus,
|
|
6670
|
+
results: tools.map((t) => ({ tool: t.name, allowed: false, reason: 'rate_limited', creditsRequired: 0 })),
|
|
6671
|
+
}));
|
|
6672
|
+
return;
|
|
6673
|
+
}
|
|
6674
|
+
// Step 4: Per-tool checks
|
|
6675
|
+
const results = [];
|
|
6676
|
+
let totalCreditsRequired = 0;
|
|
6677
|
+
let allAllowed = true;
|
|
6678
|
+
let firstDenyReason;
|
|
6679
|
+
for (const toolEntry of tools) {
|
|
6680
|
+
const toolName = toolEntry.name;
|
|
6681
|
+
const toolArgs = toolEntry.arguments;
|
|
6682
|
+
// ACL check
|
|
6683
|
+
const effectiveAllowed = keyRecord.allowedTools || [];
|
|
6684
|
+
const effectiveDenied = keyRecord.deniedTools || [];
|
|
6685
|
+
if (effectiveDenied.includes(toolName)) {
|
|
6686
|
+
results.push({ tool: toolName, allowed: false, reason: `tool_not_allowed: ${toolName} is in deniedTools`, creditsRequired: 0 });
|
|
6687
|
+
allAllowed = false;
|
|
6688
|
+
if (!firstDenyReason)
|
|
6689
|
+
firstDenyReason = `tool_not_allowed: ${toolName}`;
|
|
6690
|
+
continue;
|
|
6691
|
+
}
|
|
6692
|
+
if (effectiveAllowed.length > 0 && !effectiveAllowed.includes(toolName)) {
|
|
6693
|
+
results.push({ tool: toolName, allowed: false, reason: `tool_not_allowed: ${toolName} not in allowedTools`, creditsRequired: 0 });
|
|
6694
|
+
allAllowed = false;
|
|
6695
|
+
if (!firstDenyReason)
|
|
6696
|
+
firstDenyReason = `tool_not_allowed: ${toolName}`;
|
|
6697
|
+
continue;
|
|
6698
|
+
}
|
|
6699
|
+
const creditsRequired = this.gate.getToolPrice(toolName, toolArgs);
|
|
6700
|
+
totalCreditsRequired += creditsRequired;
|
|
6701
|
+
results.push({ tool: toolName, allowed: true, creditsRequired });
|
|
6702
|
+
}
|
|
6703
|
+
// Step 5: Aggregate credits check
|
|
6704
|
+
if (allAllowed && keyRecord.credits < totalCreditsRequired) {
|
|
6705
|
+
allAllowed = false;
|
|
6706
|
+
firstDenyReason = `insufficient_credits: need ${totalCreditsRequired}, have ${keyRecord.credits}`;
|
|
6707
|
+
}
|
|
6708
|
+
// Step 6: Spending limit
|
|
6709
|
+
if (allAllowed && keyRecord.spendingLimit > 0) {
|
|
6710
|
+
const wouldSpend = keyRecord.totalSpent + totalCreditsRequired;
|
|
6711
|
+
if (wouldSpend > keyRecord.spendingLimit) {
|
|
6712
|
+
allAllowed = false;
|
|
6713
|
+
firstDenyReason = `spending_limit_exceeded: limit ${keyRecord.spendingLimit}, spent ${keyRecord.totalSpent}, need ${totalCreditsRequired}`;
|
|
6714
|
+
}
|
|
6715
|
+
}
|
|
6716
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
6717
|
+
res.end(JSON.stringify({
|
|
6718
|
+
allAllowed,
|
|
6719
|
+
...(firstDenyReason ? { reason: firstDenyReason } : {}),
|
|
6720
|
+
totalCreditsRequired,
|
|
6721
|
+
creditsAvailable: keyRecord.credits,
|
|
6722
|
+
...(allAllowed ? { creditsAfter: keyRecord.credits - totalCreditsRequired } : {}),
|
|
6723
|
+
...(rateStatus.limit > 0 ? { rateLimit: rateStatus } : {}),
|
|
6724
|
+
results,
|
|
6725
|
+
}));
|
|
6726
|
+
}
|
|
6727
|
+
catch {
|
|
6728
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6729
|
+
res.end(JSON.stringify({ error: 'Invalid JSON body' }));
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
catch {
|
|
6733
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
6734
|
+
res.end(JSON.stringify({ error: 'Failed to read request body' }));
|
|
6735
|
+
}
|
|
6736
|
+
}
|
|
6594
6737
|
// ─── /requests/export — Export request log as JSON or CSV ───────────────────
|
|
6595
6738
|
handleRequestLogExport(req, res) {
|
|
6596
6739
|
if (!this.checkAdmin(req, res))
|