paygate-mcp 8.0.0 → 8.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/README.md +69 -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
|
@@ -107,6 +107,7 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
107
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
|
|
108
108
|
- **Tool Availability** — `GET /tools/available?key=...` returns per-key tool availability with pricing, affordability (canAfford), ACL enforcement (accessible/denyReason), and per-tool + global rate limit status
|
|
109
109
|
- **Key Dashboard** — `GET /keys/dashboard?key=...` consolidated single-endpoint view with metadata, balance, health score, spending velocity, rate limits, quotas, usage summary, and recent activity timeline
|
|
110
|
+
- **Admin Notifications** — `GET /admin/notifications` scans all keys for actionable issues: expired/expiring keys, zero credits, credit depletion velocity, suspended keys, high error rates, and rate limit pressure — with severity filtering and priority sorting
|
|
110
111
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
111
112
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
112
113
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -2360,6 +2361,74 @@ curl "http://localhost:3402/keys/dashboard?key=pg_..." \
|
|
|
2360
2361
|
|
|
2361
2362
|
Combines metadata (status/namespace/group/tags), balance (credits/spent/allocated/spendingLimit), health score (0-100 composite), spending velocity with depletion forecast, rate limit and quota status, usage summary, and last 10 audit events. Supports alias keys. Works on suspended/revoked/expired keys. Read-only.
|
|
2362
2363
|
|
|
2364
|
+
### Admin Notifications
|
|
2365
|
+
|
|
2366
|
+
Get actionable notifications about keys that need attention:
|
|
2367
|
+
|
|
2368
|
+
```bash
|
|
2369
|
+
# Get all notifications
|
|
2370
|
+
curl http://localhost:3402/admin/notifications \
|
|
2371
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
2372
|
+
|
|
2373
|
+
# Filter by severity
|
|
2374
|
+
curl "http://localhost:3402/admin/notifications?severity=critical" \
|
|
2375
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
2376
|
+
```
|
|
2377
|
+
|
|
2378
|
+
**Response:**
|
|
2379
|
+
|
|
2380
|
+
```json
|
|
2381
|
+
{
|
|
2382
|
+
"total": 4,
|
|
2383
|
+
"critical": 2,
|
|
2384
|
+
"warning": 1,
|
|
2385
|
+
"info": 1,
|
|
2386
|
+
"notifications": [
|
|
2387
|
+
{
|
|
2388
|
+
"severity": "critical",
|
|
2389
|
+
"category": "zero_credits",
|
|
2390
|
+
"message": "Key has zero credits remaining",
|
|
2391
|
+
"key": "pg_c815...09a6",
|
|
2392
|
+
"keyName": "production-agent"
|
|
2393
|
+
},
|
|
2394
|
+
{
|
|
2395
|
+
"severity": "critical",
|
|
2396
|
+
"category": "key_expiring_soon",
|
|
2397
|
+
"message": "Key expires within 8 hours",
|
|
2398
|
+
"key": "pg_a3f1...b2e4",
|
|
2399
|
+
"keyName": "staging-agent",
|
|
2400
|
+
"details": { "expiresAt": "2026-02-27T08:00:00.000Z", "hoursRemaining": 7.5 }
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
"severity": "warning",
|
|
2404
|
+
"category": "credits_depleting",
|
|
2405
|
+
"message": "Credits will deplete in ~18 hours at current rate",
|
|
2406
|
+
"key": "pg_d7e2...f1a3",
|
|
2407
|
+
"keyName": "batch-worker",
|
|
2408
|
+
"details": { "credits": 90, "creditsPerHour": 5.1, "estimatedHoursRemaining": 17.6 }
|
|
2409
|
+
},
|
|
2410
|
+
{
|
|
2411
|
+
"severity": "info",
|
|
2412
|
+
"category": "key_suspended",
|
|
2413
|
+
"message": "Key is suspended",
|
|
2414
|
+
"key": "pg_b4c9...e8d5",
|
|
2415
|
+
"keyName": "deprecated-agent"
|
|
2416
|
+
}
|
|
2417
|
+
]
|
|
2418
|
+
}
|
|
2419
|
+
```
|
|
2420
|
+
|
|
2421
|
+
**Notification categories:**
|
|
2422
|
+
- `key_expired` (critical) — Key has passed its expiry date
|
|
2423
|
+
- `key_expiring_soon` (critical <24h, warning <7d) — Key approaching expiry
|
|
2424
|
+
- `zero_credits` (critical) — Key has no credits remaining
|
|
2425
|
+
- `credits_depleting` (critical <6h, warning <24h) — Spending velocity predicts depletion
|
|
2426
|
+
- `key_suspended` (info) — Key is suspended
|
|
2427
|
+
- `high_error_rate` (critical ≥50%, warning ≥25%) — High denial rate (min 10 calls)
|
|
2428
|
+
- `rate_limit_pressure` (warning ≥90%) — Rate limit nearly exhausted
|
|
2429
|
+
|
|
2430
|
+
Notifications are sorted by severity (critical first). Revoked keys are excluded. A single key can appear in multiple notifications (e.g., zero credits AND expiring soon). Filter with `?severity=critical|warning|info`. Read-only.
|
|
2431
|
+
|
|
2363
2432
|
### IP Allowlisting
|
|
2364
2433
|
|
|
2365
2434
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/server.d.ts
CHANGED
|
@@ -242,6 +242,7 @@ export declare class PayGateServer {
|
|
|
242
242
|
private handleGetMaintenance;
|
|
243
243
|
private handleSetMaintenance;
|
|
244
244
|
private handleAdminEventStream;
|
|
245
|
+
private handleAdminNotifications;
|
|
245
246
|
private handleGetNotes;
|
|
246
247
|
private handleAddNote;
|
|
247
248
|
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
|
@@ -798,6 +798,12 @@ class PayGateServer {
|
|
|
798
798
|
return this.handleRevokeAdminKey(req, res);
|
|
799
799
|
case '/admin/events':
|
|
800
800
|
return this.handleAdminEventStream(req, res);
|
|
801
|
+
case '/admin/notifications':
|
|
802
|
+
if (req.method === 'GET')
|
|
803
|
+
return this.handleAdminNotifications(req, res);
|
|
804
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
805
|
+
res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
|
|
806
|
+
return;
|
|
801
807
|
// ─── Plugin endpoints ──────────────────────────────────────────────
|
|
802
808
|
case '/plugins':
|
|
803
809
|
return this.handleListPlugins(req, res);
|
|
@@ -1338,6 +1344,7 @@ class PayGateServer {
|
|
|
1338
1344
|
toolStats: 'GET /tools/stats — Per-tool call counts, success rates, latency, credits, and top consumers (requires X-Admin-Key)',
|
|
1339
1345
|
toolAvailability: 'GET /tools/available?key=... — Per-key tool availability with pricing, affordability, and rate limit status (requires X-Admin-Key)',
|
|
1340
1346
|
keyDashboard: 'GET /keys/dashboard?key=... — Consolidated key overview with metadata, balance, health, velocity, rate limits, quotas, and recent activity (requires X-Admin-Key)',
|
|
1347
|
+
adminNotifications: 'GET /admin/notifications — Actionable notifications for expiring keys, low credits, high error rates, and rate limit pressure (requires X-Admin-Key)',
|
|
1341
1348
|
...(this.oauth ? {
|
|
1342
1349
|
oauthMetadata: 'GET /.well-known/oauth-authorization-server — OAuth 2.1 server metadata',
|
|
1343
1350
|
oauthRegister: 'POST /oauth/register — Register OAuth client',
|
|
@@ -4296,6 +4303,142 @@ class PayGateServer {
|
|
|
4296
4303
|
}
|
|
4297
4304
|
});
|
|
4298
4305
|
}
|
|
4306
|
+
// ─── /admin/notifications — Actionable notifications ──────────────────────
|
|
4307
|
+
handleAdminNotifications(req, res) {
|
|
4308
|
+
if (!this.checkAdmin(req, res))
|
|
4309
|
+
return;
|
|
4310
|
+
const urlParts = req.url?.split('?') || [];
|
|
4311
|
+
const params = new URLSearchParams(urlParts[1] || '');
|
|
4312
|
+
const severityFilter = params.get('severity'); // critical, warning, info, or null for all
|
|
4313
|
+
const notifications = [];
|
|
4314
|
+
// Scan all keys for issues
|
|
4315
|
+
const allRecords = this.gate.store.getAllRecords();
|
|
4316
|
+
for (const record of allRecords) {
|
|
4317
|
+
const maskedKey = record.key.slice(0, 7) + '...' + record.key.slice(-4);
|
|
4318
|
+
const keyName = record.name || undefined;
|
|
4319
|
+
// Skip revoked keys
|
|
4320
|
+
if (!record.active)
|
|
4321
|
+
continue;
|
|
4322
|
+
// ── Expiry checks ──
|
|
4323
|
+
if (record.expiresAt) {
|
|
4324
|
+
const msToExpiry = new Date(record.expiresAt).getTime() - Date.now();
|
|
4325
|
+
const hoursToExpiry = msToExpiry / 3_600_000;
|
|
4326
|
+
if (msToExpiry <= 0) {
|
|
4327
|
+
notifications.push({
|
|
4328
|
+
severity: 'critical', category: 'key_expired',
|
|
4329
|
+
message: `Key has expired`,
|
|
4330
|
+
key: maskedKey, keyName,
|
|
4331
|
+
details: { expiresAt: record.expiresAt },
|
|
4332
|
+
});
|
|
4333
|
+
}
|
|
4334
|
+
else if (hoursToExpiry <= 24) {
|
|
4335
|
+
notifications.push({
|
|
4336
|
+
severity: 'critical', category: 'key_expiring_soon',
|
|
4337
|
+
message: `Key expires within ${Math.ceil(hoursToExpiry)} hours`,
|
|
4338
|
+
key: maskedKey, keyName,
|
|
4339
|
+
details: { expiresAt: record.expiresAt, hoursRemaining: Math.round(hoursToExpiry * 10) / 10 },
|
|
4340
|
+
});
|
|
4341
|
+
}
|
|
4342
|
+
else if (hoursToExpiry <= 168) {
|
|
4343
|
+
notifications.push({
|
|
4344
|
+
severity: 'warning', category: 'key_expiring_soon',
|
|
4345
|
+
message: `Key expires within ${Math.ceil(hoursToExpiry / 24)} days`,
|
|
4346
|
+
key: maskedKey, keyName,
|
|
4347
|
+
details: { expiresAt: record.expiresAt, daysRemaining: Math.round(hoursToExpiry / 24 * 10) / 10 },
|
|
4348
|
+
});
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
// ── Credit checks ──
|
|
4352
|
+
if (record.credits <= 0) {
|
|
4353
|
+
notifications.push({
|
|
4354
|
+
severity: 'critical', category: 'zero_credits',
|
|
4355
|
+
message: `Key has zero credits remaining`,
|
|
4356
|
+
key: maskedKey, keyName,
|
|
4357
|
+
});
|
|
4358
|
+
}
|
|
4359
|
+
else {
|
|
4360
|
+
// Check spending velocity for depletion
|
|
4361
|
+
const velocity = this.creditLedger.getSpendingVelocity(record.key, record.credits, 24);
|
|
4362
|
+
if (velocity.creditsPerHour > 0) {
|
|
4363
|
+
const hoursLeft = velocity.estimatedHoursRemaining ?? Infinity;
|
|
4364
|
+
if (hoursLeft <= 6) {
|
|
4365
|
+
notifications.push({
|
|
4366
|
+
severity: 'critical', category: 'credits_depleting',
|
|
4367
|
+
message: `Credits will deplete in ~${Math.ceil(hoursLeft)} hours at current rate`,
|
|
4368
|
+
key: maskedKey, keyName,
|
|
4369
|
+
details: { credits: record.credits, creditsPerHour: velocity.creditsPerHour, estimatedHoursRemaining: Math.round(hoursLeft * 10) / 10 },
|
|
4370
|
+
});
|
|
4371
|
+
}
|
|
4372
|
+
else if (hoursLeft <= 24) {
|
|
4373
|
+
notifications.push({
|
|
4374
|
+
severity: 'warning', category: 'credits_depleting',
|
|
4375
|
+
message: `Credits will deplete in ~${Math.ceil(hoursLeft)} hours at current rate`,
|
|
4376
|
+
key: maskedKey, keyName,
|
|
4377
|
+
details: { credits: record.credits, creditsPerHour: velocity.creditsPerHour, estimatedHoursRemaining: Math.round(hoursLeft * 10) / 10 },
|
|
4378
|
+
});
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
// ── Suspended key ──
|
|
4383
|
+
if (record.suspended) {
|
|
4384
|
+
notifications.push({
|
|
4385
|
+
severity: 'info', category: 'key_suspended',
|
|
4386
|
+
message: `Key is suspended`,
|
|
4387
|
+
key: maskedKey, keyName,
|
|
4388
|
+
});
|
|
4389
|
+
}
|
|
4390
|
+
// ── Error rate check ──
|
|
4391
|
+
const keyUsage = this.gate.meter.getKeyUsage(record.key);
|
|
4392
|
+
if (keyUsage.totalCalls >= 10) {
|
|
4393
|
+
const errorRate = keyUsage.totalDenied / keyUsage.totalCalls;
|
|
4394
|
+
if (errorRate >= 0.5) {
|
|
4395
|
+
notifications.push({
|
|
4396
|
+
severity: 'critical', category: 'high_error_rate',
|
|
4397
|
+
message: `${Math.round(errorRate * 100)}% error rate (${keyUsage.totalDenied}/${keyUsage.totalCalls} denied)`,
|
|
4398
|
+
key: maskedKey, keyName,
|
|
4399
|
+
details: { errorRate: Math.round(errorRate * 1000) / 1000, totalCalls: keyUsage.totalCalls, totalDenied: keyUsage.totalDenied },
|
|
4400
|
+
});
|
|
4401
|
+
}
|
|
4402
|
+
else if (errorRate >= 0.25) {
|
|
4403
|
+
notifications.push({
|
|
4404
|
+
severity: 'warning', category: 'high_error_rate',
|
|
4405
|
+
message: `${Math.round(errorRate * 100)}% error rate (${keyUsage.totalDenied}/${keyUsage.totalCalls} denied)`,
|
|
4406
|
+
key: maskedKey, keyName,
|
|
4407
|
+
details: { errorRate: Math.round(errorRate * 1000) / 1000, totalCalls: keyUsage.totalCalls, totalDenied: keyUsage.totalDenied },
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
// ── Rate limit pressure ──
|
|
4412
|
+
const rateStatus = this.gate.rateLimiter.getStatus(record.key);
|
|
4413
|
+
if (rateStatus.limit > 0) {
|
|
4414
|
+
const utilization = rateStatus.used / rateStatus.limit;
|
|
4415
|
+
if (utilization >= 0.9) {
|
|
4416
|
+
notifications.push({
|
|
4417
|
+
severity: 'warning', category: 'rate_limit_pressure',
|
|
4418
|
+
message: `${Math.round(utilization * 100)}% rate limit utilization (${rateStatus.used}/${rateStatus.limit})`,
|
|
4419
|
+
key: maskedKey, keyName,
|
|
4420
|
+
details: { used: rateStatus.used, limit: rateStatus.limit, remaining: rateStatus.remaining },
|
|
4421
|
+
});
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
// Apply severity filter
|
|
4426
|
+
let filtered = notifications;
|
|
4427
|
+
if (severityFilter) {
|
|
4428
|
+
filtered = notifications.filter(n => n.severity === severityFilter);
|
|
4429
|
+
}
|
|
4430
|
+
// Sort: critical first, then warning, then info
|
|
4431
|
+
const severityOrder = { critical: 0, warning: 1, info: 2 };
|
|
4432
|
+
filtered.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
|
|
4433
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4434
|
+
res.end(JSON.stringify({
|
|
4435
|
+
total: filtered.length,
|
|
4436
|
+
critical: filtered.filter(n => n.severity === 'critical').length,
|
|
4437
|
+
warning: filtered.filter(n => n.severity === 'warning').length,
|
|
4438
|
+
info: filtered.filter(n => n.severity === 'info').length,
|
|
4439
|
+
notifications: filtered,
|
|
4440
|
+
}));
|
|
4441
|
+
}
|
|
4299
4442
|
// ─── /keys/notes — Timestamped notes on API keys ─────────────────────────
|
|
4300
4443
|
handleGetNotes(req, res) {
|
|
4301
4444
|
if (!this.checkAdmin(req, res))
|