paygate-mcp 8.8.0 → 8.10.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 +40 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +196 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
115
115
|
- **Quota Analysis** — `GET /admin/quotas` quota utilization analysis with per-key daily/monthly usage vs limits, per-tool denial breakdown, most constrained keys, and global/per-key quota source tracking
|
|
116
116
|
- **Denial Analysis** — `GET /admin/denials` comprehensive denial breakdown by reason type (insufficient_credits, rate_limited, quota_exceeded, key_suspended, etc.) with per-key and per-tool stats, hourly trends, and most denied keys
|
|
117
117
|
- **Traffic Analysis** — `GET /admin/traffic` request volume analysis with tool popularity, hourly volume, top consumers by call count, namespace breakdown, peak hour identification, and success rates
|
|
118
|
+
- **Security Audit** — `GET /admin/security` security posture analysis identifying keys without IP allowlists, quotas, ACL restrictions, spending limits, or expiry dates, flagging high-credit keys, and computing a composite security score
|
|
119
|
+
- **Revenue Analysis** — `GET /admin/revenue` revenue metrics with per-tool revenue breakdown, per-key spending, hourly revenue trends, credit flow summary (allocated/spent/remaining), and average revenue per call
|
|
118
120
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
119
121
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
120
122
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -2655,6 +2657,44 @@ curl http://localhost:3000/admin/traffic -H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
|
2655
2657
|
|
|
2656
2658
|
Returns traffic summary with success rate and peak hour, tool popularity ranked by call count with success rates and credit totals, hourly volume (last 24 hours) with allowed/denied/credit breakdowns, top 10 consumers by call count, and namespace breakdown with per-namespace stats. Read-only.
|
|
2657
2659
|
|
|
2660
|
+
### Security Audit
|
|
2661
|
+
|
|
2662
|
+
```bash
|
|
2663
|
+
curl http://localhost:3000/admin/security -H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
2664
|
+
```
|
|
2665
|
+
|
|
2666
|
+
```json
|
|
2667
|
+
{
|
|
2668
|
+
"score": 72,
|
|
2669
|
+
"summary": { "totalKeys": 5, "totalFindings": 12 },
|
|
2670
|
+
"findings": [
|
|
2671
|
+
{ "type": "no_ip_allowlist", "severity": "warning", "keys": ["prod-key", "dev-key"], "description": "Keys without IP allowlists can be used from any IP address" },
|
|
2672
|
+
{ "type": "no_acl_restriction", "severity": "info", "keys": ["dev-key"], "description": "Keys without ACL restrictions can access all tools" },
|
|
2673
|
+
{ "type": "high_credit_balance", "severity": "warning", "keys": ["whale-key"], "description": "Keys with 10000+ credits are high-value targets if compromised" }
|
|
2674
|
+
]
|
|
2675
|
+
}
|
|
2676
|
+
```
|
|
2677
|
+
|
|
2678
|
+
Returns a composite security score (0-100) with per-finding breakdown. Scans all active keys for: missing IP allowlists (warning), missing quotas (info), unrestricted ACLs (info), no spending limits (info), no expiry dates (info), and high credit balances (warning). Well-configured keys with IP restrictions, tool ACLs, quotas, spending limits, and expiry dates will not appear in any findings. Read-only — does not modify system state.
|
|
2679
|
+
|
|
2680
|
+
### Revenue Analysis
|
|
2681
|
+
|
|
2682
|
+
```bash
|
|
2683
|
+
curl http://localhost:3000/admin/revenue -H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
2684
|
+
```
|
|
2685
|
+
|
|
2686
|
+
```json
|
|
2687
|
+
{
|
|
2688
|
+
"summary": { "totalRevenue": 5000, "totalCalls": 250, "averageRevenuePerCall": 20 },
|
|
2689
|
+
"byTool": [{ "tool": "summarize", "revenue": 3000, "calls": 150, "averagePerCall": 20 }],
|
|
2690
|
+
"byKey": [{ "name": "heavy-user", "revenue": 2000, "calls": 80 }],
|
|
2691
|
+
"hourlyRevenue": [{ "hour": "2025-01-15T14", "revenue": 500, "calls": 25 }],
|
|
2692
|
+
"creditFlow": { "totalAllocated": 50000, "totalSpent": 5000, "totalRemaining": 45000 }
|
|
2693
|
+
}
|
|
2694
|
+
```
|
|
2695
|
+
|
|
2696
|
+
Returns revenue summary with total credits earned, per-tool revenue ranked by earnings with average per-call, top 10 per-key spending, hourly revenue trends (last 24 hours), and credit flow showing total allocated vs spent vs remaining across all active keys. Only counts successful (allowed) calls. Read-only.
|
|
2697
|
+
|
|
2658
2698
|
### IP Allowlisting
|
|
2659
2699
|
|
|
2660
2700
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/server.d.ts
CHANGED
|
@@ -250,6 +250,8 @@ export declare class PayGateServer {
|
|
|
250
250
|
private handleQuotaAnalysis;
|
|
251
251
|
private handleDenialAnalysis;
|
|
252
252
|
private handleTrafficAnalysis;
|
|
253
|
+
private handleSecurityAudit;
|
|
254
|
+
private handleRevenueAnalysis;
|
|
253
255
|
private handleGetNotes;
|
|
254
256
|
private handleAddNote;
|
|
255
257
|
private handleDeleteNote;
|
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
|
@@ -846,6 +846,18 @@ class PayGateServer {
|
|
|
846
846
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
847
847
|
res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
|
|
848
848
|
return;
|
|
849
|
+
case '/admin/security':
|
|
850
|
+
if (req.method === 'GET')
|
|
851
|
+
return this.handleSecurityAudit(req, res);
|
|
852
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
853
|
+
res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
|
|
854
|
+
return;
|
|
855
|
+
case '/admin/revenue':
|
|
856
|
+
if (req.method === 'GET')
|
|
857
|
+
return this.handleRevenueAnalysis(req, res);
|
|
858
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
859
|
+
res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
|
|
860
|
+
return;
|
|
849
861
|
// ─── Plugin endpoints ──────────────────────────────────────────────
|
|
850
862
|
case '/plugins':
|
|
851
863
|
return this.handleListPlugins(req, res);
|
|
@@ -1394,6 +1406,8 @@ class PayGateServer {
|
|
|
1394
1406
|
quotaAnalysis: 'GET /admin/quotas — Quota utilization analysis with per-key and per-tool breakdown, denial trends, most constrained keys, and configuration display (requires X-Admin-Key)',
|
|
1395
1407
|
denialAnalysis: 'GET /admin/denials — Comprehensive denial breakdown by reason type with per-key and per-tool stats, hourly trends, and most denied keys (requires X-Admin-Key)',
|
|
1396
1408
|
trafficAnalysis: 'GET /admin/traffic — Traffic volume analysis with tool popularity, hourly volume, top consumers, namespace breakdown, and peak hour identification (requires X-Admin-Key)',
|
|
1409
|
+
securityAudit: 'GET /admin/security — Security posture analysis with findings for missing IP allowlists, quotas, ACLs, spending limits, expiry, high-credit keys, and composite score (requires X-Admin-Key)',
|
|
1410
|
+
revenueAnalysis: 'GET /admin/revenue — Revenue metrics with per-tool revenue, per-key spending, hourly revenue trends, credit flow summary, and average revenue per call (requires X-Admin-Key)',
|
|
1397
1411
|
...(this.oauth ? {
|
|
1398
1412
|
oauthMetadata: 'GET /.well-known/oauth-authorization-server — OAuth 2.1 server metadata',
|
|
1399
1413
|
oauthRegister: 'POST /oauth/register — Register OAuth client',
|
|
@@ -5285,6 +5299,188 @@ class PayGateServer {
|
|
|
5285
5299
|
byNamespace,
|
|
5286
5300
|
}));
|
|
5287
5301
|
}
|
|
5302
|
+
// ─── /admin/security — Security posture audit ───────────────────────────
|
|
5303
|
+
handleSecurityAudit(req, res) {
|
|
5304
|
+
if (!this.checkAdmin(req, res))
|
|
5305
|
+
return;
|
|
5306
|
+
const allRecords = this.gate.store.getAllRecords();
|
|
5307
|
+
const HIGH_CREDIT_THRESHOLD = 10000;
|
|
5308
|
+
const findings = [];
|
|
5309
|
+
// ── no_ip_allowlist (warning) ──
|
|
5310
|
+
const noIp = allRecords.filter(r => r.active && (!r.ipAllowlist || r.ipAllowlist.length === 0));
|
|
5311
|
+
if (noIp.length > 0) {
|
|
5312
|
+
findings.push({
|
|
5313
|
+
type: 'no_ip_allowlist',
|
|
5314
|
+
severity: 'warning',
|
|
5315
|
+
keys: noIp.map(r => r.name),
|
|
5316
|
+
description: 'Keys without IP allowlists can be used from any IP address',
|
|
5317
|
+
});
|
|
5318
|
+
}
|
|
5319
|
+
// ── no_quota (info) ──
|
|
5320
|
+
const noQuota = allRecords.filter(r => {
|
|
5321
|
+
if (!r.active)
|
|
5322
|
+
return false;
|
|
5323
|
+
// Has per-key quota?
|
|
5324
|
+
if (r.quota) {
|
|
5325
|
+
const q = r.quota;
|
|
5326
|
+
if (q.dailyCallLimit > 0 || q.monthlyCallLimit > 0 || q.dailyCreditLimit > 0 || q.monthlyCreditLimit > 0)
|
|
5327
|
+
return false;
|
|
5328
|
+
}
|
|
5329
|
+
// Has global quota?
|
|
5330
|
+
if (this.config.globalQuota) {
|
|
5331
|
+
const gq = this.config.globalQuota;
|
|
5332
|
+
if (gq.dailyCallLimit > 0 || gq.monthlyCallLimit > 0 || gq.dailyCreditLimit > 0 || gq.monthlyCreditLimit > 0)
|
|
5333
|
+
return false;
|
|
5334
|
+
}
|
|
5335
|
+
return true;
|
|
5336
|
+
});
|
|
5337
|
+
if (noQuota.length > 0) {
|
|
5338
|
+
findings.push({
|
|
5339
|
+
type: 'no_quota',
|
|
5340
|
+
severity: 'info',
|
|
5341
|
+
keys: noQuota.map(r => r.name),
|
|
5342
|
+
description: 'Keys without quotas have no daily/monthly usage limits',
|
|
5343
|
+
});
|
|
5344
|
+
}
|
|
5345
|
+
// ── no_acl_restriction (info) ──
|
|
5346
|
+
const noAcl = allRecords.filter(r => r.active && (!r.allowedTools || r.allowedTools.length === 0));
|
|
5347
|
+
if (noAcl.length > 0) {
|
|
5348
|
+
findings.push({
|
|
5349
|
+
type: 'no_acl_restriction',
|
|
5350
|
+
severity: 'info',
|
|
5351
|
+
keys: noAcl.map(r => r.name),
|
|
5352
|
+
description: 'Keys without ACL restrictions can access all tools',
|
|
5353
|
+
});
|
|
5354
|
+
}
|
|
5355
|
+
// ── no_spending_limit (info) ──
|
|
5356
|
+
const noSpend = allRecords.filter(r => r.active && (!r.spendingLimit || r.spendingLimit === 0));
|
|
5357
|
+
if (noSpend.length > 0) {
|
|
5358
|
+
findings.push({
|
|
5359
|
+
type: 'no_spending_limit',
|
|
5360
|
+
severity: 'info',
|
|
5361
|
+
keys: noSpend.map(r => r.name),
|
|
5362
|
+
description: 'Keys without spending limits have no cap on total credit consumption',
|
|
5363
|
+
});
|
|
5364
|
+
}
|
|
5365
|
+
// ── no_expiry (info) ──
|
|
5366
|
+
const noExpiry = allRecords.filter(r => r.active && !r.expiresAt);
|
|
5367
|
+
if (noExpiry.length > 0) {
|
|
5368
|
+
findings.push({
|
|
5369
|
+
type: 'no_expiry',
|
|
5370
|
+
severity: 'info',
|
|
5371
|
+
keys: noExpiry.map(r => r.name),
|
|
5372
|
+
description: 'Keys without expiry dates remain valid indefinitely',
|
|
5373
|
+
});
|
|
5374
|
+
}
|
|
5375
|
+
// ── high_credit_balance (warning) ──
|
|
5376
|
+
const highCredit = allRecords.filter(r => r.active && r.credits >= HIGH_CREDIT_THRESHOLD);
|
|
5377
|
+
if (highCredit.length > 0) {
|
|
5378
|
+
findings.push({
|
|
5379
|
+
type: 'high_credit_balance',
|
|
5380
|
+
severity: 'warning',
|
|
5381
|
+
keys: highCredit.map(r => r.name),
|
|
5382
|
+
description: `Keys with ${HIGH_CREDIT_THRESHOLD}+ credits are high-value targets if compromised`,
|
|
5383
|
+
});
|
|
5384
|
+
}
|
|
5385
|
+
// ── Compute score ──
|
|
5386
|
+
const totalKeys = allRecords.filter(r => r.active).length;
|
|
5387
|
+
const totalFindings = findings.reduce((sum, f) => sum + f.keys.length, 0);
|
|
5388
|
+
let score = 100;
|
|
5389
|
+
if (totalKeys > 0) {
|
|
5390
|
+
// Each warning finding per key deducts more than info
|
|
5391
|
+
for (const f of findings) {
|
|
5392
|
+
const weight = f.severity === 'warning' ? 5 : f.severity === 'critical' ? 10 : 2;
|
|
5393
|
+
score -= f.keys.length * weight;
|
|
5394
|
+
}
|
|
5395
|
+
score = Math.max(0, Math.min(100, score));
|
|
5396
|
+
}
|
|
5397
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
5398
|
+
res.end(JSON.stringify({
|
|
5399
|
+
score,
|
|
5400
|
+
summary: {
|
|
5401
|
+
totalKeys,
|
|
5402
|
+
totalFindings,
|
|
5403
|
+
},
|
|
5404
|
+
findings,
|
|
5405
|
+
}));
|
|
5406
|
+
}
|
|
5407
|
+
// ─── /admin/revenue — Revenue analysis ──────────────────────────────────
|
|
5408
|
+
handleRevenueAnalysis(req, res) {
|
|
5409
|
+
if (!this.checkAdmin(req, res))
|
|
5410
|
+
return;
|
|
5411
|
+
const events = this.gate.meter.getEvents();
|
|
5412
|
+
const allRecords = this.gate.store.getAllRecords();
|
|
5413
|
+
// ── Summary ──
|
|
5414
|
+
const allowedEvents = events.filter(e => e.allowed);
|
|
5415
|
+
const totalRevenue = allowedEvents.reduce((sum, e) => sum + e.creditsCharged, 0);
|
|
5416
|
+
const totalCalls = allowedEvents.length;
|
|
5417
|
+
const averageRevenuePerCall = totalCalls > 0 ? Math.round(totalRevenue / totalCalls * 100) / 100 : 0;
|
|
5418
|
+
// ── By tool ──
|
|
5419
|
+
const toolMap = new Map();
|
|
5420
|
+
for (const e of allowedEvents) {
|
|
5421
|
+
if (!toolMap.has(e.tool))
|
|
5422
|
+
toolMap.set(e.tool, { revenue: 0, calls: 0 });
|
|
5423
|
+
const t = toolMap.get(e.tool);
|
|
5424
|
+
t.revenue += e.creditsCharged;
|
|
5425
|
+
t.calls++;
|
|
5426
|
+
}
|
|
5427
|
+
const byTool = Array.from(toolMap.entries())
|
|
5428
|
+
.map(([tool, stats]) => ({ tool, ...stats, averagePerCall: stats.calls > 0 ? Math.round(stats.revenue / stats.calls * 100) / 100 : 0 }))
|
|
5429
|
+
.sort((a, b) => b.revenue - a.revenue);
|
|
5430
|
+
// ── By key ──
|
|
5431
|
+
const keyMap = new Map();
|
|
5432
|
+
for (const e of allowedEvents) {
|
|
5433
|
+
const name = e.keyName || e.apiKey;
|
|
5434
|
+
if (!keyMap.has(name))
|
|
5435
|
+
keyMap.set(name, { name, revenue: 0, calls: 0 });
|
|
5436
|
+
const k = keyMap.get(name);
|
|
5437
|
+
k.revenue += e.creditsCharged;
|
|
5438
|
+
k.calls++;
|
|
5439
|
+
}
|
|
5440
|
+
const byKey = Array.from(keyMap.values())
|
|
5441
|
+
.sort((a, b) => b.revenue - a.revenue)
|
|
5442
|
+
.slice(0, 10);
|
|
5443
|
+
// ── Hourly revenue ──
|
|
5444
|
+
const hourMap = new Map();
|
|
5445
|
+
for (const e of allowedEvents) {
|
|
5446
|
+
const hour = new Date(e.timestamp).toISOString().slice(0, 13);
|
|
5447
|
+
if (!hourMap.has(hour))
|
|
5448
|
+
hourMap.set(hour, { revenue: 0, calls: 0 });
|
|
5449
|
+
const h = hourMap.get(hour);
|
|
5450
|
+
h.revenue += e.creditsCharged;
|
|
5451
|
+
h.calls++;
|
|
5452
|
+
}
|
|
5453
|
+
const hourlyRevenue = Array.from(hourMap.entries())
|
|
5454
|
+
.map(([hour, stats]) => ({ hour, ...stats }))
|
|
5455
|
+
.sort((a, b) => a.hour.localeCompare(b.hour));
|
|
5456
|
+
// ── Credit flow ──
|
|
5457
|
+
let totalAllocated = 0;
|
|
5458
|
+
let totalSpent = 0;
|
|
5459
|
+
let totalRemaining = 0;
|
|
5460
|
+
for (const record of allRecords) {
|
|
5461
|
+
if (!record.active)
|
|
5462
|
+
continue;
|
|
5463
|
+
totalAllocated += record.credits + (record.totalSpent || 0);
|
|
5464
|
+
totalSpent += record.totalSpent || 0;
|
|
5465
|
+
totalRemaining += record.credits;
|
|
5466
|
+
}
|
|
5467
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
5468
|
+
res.end(JSON.stringify({
|
|
5469
|
+
summary: {
|
|
5470
|
+
totalRevenue,
|
|
5471
|
+
totalCalls,
|
|
5472
|
+
averageRevenuePerCall,
|
|
5473
|
+
},
|
|
5474
|
+
byTool,
|
|
5475
|
+
byKey,
|
|
5476
|
+
hourlyRevenue,
|
|
5477
|
+
creditFlow: {
|
|
5478
|
+
totalAllocated,
|
|
5479
|
+
totalSpent,
|
|
5480
|
+
totalRemaining,
|
|
5481
|
+
},
|
|
5482
|
+
}));
|
|
5483
|
+
}
|
|
5288
5484
|
// ─── /keys/notes — Timestamped notes on API keys ─────────────────────────
|
|
5289
5485
|
handleGetNotes(req, res) {
|
|
5290
5486
|
if (!this.checkAdmin(req, res))
|