paygate-mcp 7.8.0 → 8.0.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 CHANGED
@@ -105,6 +105,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
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
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
+ - **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
+ - **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
108
110
  - **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
109
111
  - **Webhook Events** — POST batched usage events to any URL for external billing/alerting
110
112
  - **Config File Mode** — Load all settings from a JSON file (`--config`)
@@ -2301,6 +2303,63 @@ curl -X POST http://localhost:3402/requests/dry-run/batch \
2301
2303
 
2302
2304
  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
2305
 
2306
+ ### Tool Availability
2307
+
2308
+ Check per-key tool availability including pricing, affordability, and rate limit status:
2309
+
2310
+ ```bash
2311
+ curl "http://localhost:3402/tools/available?key=pg_..." \
2312
+ -H "X-Admin-Key: YOUR_ADMIN_KEY"
2313
+ ```
2314
+
2315
+ **Response:**
2316
+
2317
+ ```json
2318
+ {
2319
+ "key": "pg_c815...09a6",
2320
+ "creditsAvailable": 100,
2321
+ "totalTools": 3,
2322
+ "accessibleTools": 2,
2323
+ "globalRateLimit": { "limit": 60, "used": 5, "remaining": 55, "resetInMs": 45000 },
2324
+ "tools": [
2325
+ { "tool": "tool_a", "accessible": true, "creditsPerCall": 10, "canAfford": true },
2326
+ { "tool": "tool_b", "accessible": false, "denyReason": "denied_by_acl", "creditsPerCall": 5, "canAfford": true },
2327
+ { "tool": "tool_c", "accessible": true, "creditsPerCall": 1, "canAfford": true, "rateLimit": { "limit": 10, "used": 3, "remaining": 7 } }
2328
+ ]
2329
+ }
2330
+ ```
2331
+
2332
+ Returns every discovered tool with: `accessible` (ACL check), `denyReason` (if blocked), `creditsPerCall`, `canAfford` (credits vs price), and per-tool `rateLimit` when configured. Includes global rate limit info. Supports alias keys. Works on suspended keys (informational). Read-only — does not deduct credits or increment rate counters.
2333
+
2334
+ ### Key Dashboard
2335
+
2336
+ Get a consolidated overview of any API key in a single request:
2337
+
2338
+ ```bash
2339
+ curl "http://localhost:3402/keys/dashboard?key=pg_..." \
2340
+ -H "X-Admin-Key: YOUR_ADMIN_KEY"
2341
+ ```
2342
+
2343
+ **Response:**
2344
+
2345
+ ```json
2346
+ {
2347
+ "key": "pg_c815...09a6",
2348
+ "name": "production-agent",
2349
+ "status": "active",
2350
+ "namespace": "prod",
2351
+ "balance": { "credits": 850, "totalSpent": 150, "totalAllocated": 1000, "spendingLimit": 500 },
2352
+ "health": { "score": 92, "status": "good" },
2353
+ "velocity": { "creditsPerHour": 6.2, "creditsPerDay": 149, "estimatedDepletionDate": "2025-02-03T..." },
2354
+ "rateLimits": { "global": { "limit": 60, "used": 12, "remaining": 48, "resetInMs": 35000 } },
2355
+ "quotas": { "source": "global", "daily": { "callsUsed": 24, "callsLimit": 100 }, "monthly": { "callsUsed": 340, "callsLimit": 5000 } },
2356
+ "usage": { "totalCalls": 340, "totalAllowed": 330, "totalDenied": 10, "totalCredits": 150 },
2357
+ "recentActivity": [{ "timestamp": "...", "event": "gate.allowed", "tool": "search", "credits": 5 }]
2358
+ }
2359
+ ```
2360
+
2361
+ 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
+
2304
2363
  ### IP Allowlisting
2305
2364
 
2306
2365
  Restrict API keys to specific IP addresses or CIDR ranges:
package/dist/server.d.ts CHANGED
@@ -211,6 +211,7 @@ export declare class PayGateServer {
211
211
  private handleSpendingVelocity;
212
212
  private handleKeyComparison;
213
213
  private handleKeyHealth;
214
+ private handleKeyDashboard;
214
215
  private handleSetAutoTopup;
215
216
  private handleBalance;
216
217
  private handleLimits;
@@ -319,6 +320,7 @@ export declare class PayGateServer {
319
320
  private handleRequestDryRun;
320
321
  private handleRequestDryRunBatch;
321
322
  private handleRequestLogExport;
323
+ private handleToolAvailability;
322
324
  /** Calculate percentile from an array of numbers. */
323
325
  private percentile;
324
326
  }
@@ -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
@@ -638,6 +638,12 @@ class PayGateServer {
638
638
  return this.handleKeyComparison(req, res);
639
639
  case '/keys/health':
640
640
  return this.handleKeyHealth(req, res);
641
+ case '/keys/dashboard':
642
+ if (req.method === 'GET')
643
+ return this.handleKeyDashboard(req, res);
644
+ res.writeHead(405, { 'Content-Type': 'application/json' });
645
+ res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
646
+ return;
641
647
  case '/keys/templates':
642
648
  if (req.method === 'GET')
643
649
  return this.handleListTemplates(req, res);
@@ -711,6 +717,12 @@ class PayGateServer {
711
717
  res.writeHead(405, { 'Content-Type': 'application/json' });
712
718
  res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
713
719
  return;
720
+ case '/tools/available':
721
+ if (req.method === 'GET')
722
+ return this.handleToolAvailability(req, res);
723
+ res.writeHead(405, { 'Content-Type': 'application/json' });
724
+ res.end(JSON.stringify({ error: 'Method not allowed. Use GET.' }));
725
+ return;
714
726
  case '/alerts':
715
727
  if (req.method === 'GET')
716
728
  return this.handleGetAlerts(req, res);
@@ -1324,6 +1336,8 @@ class PayGateServer {
1324
1336
  requestDryRun: 'POST /requests/dry-run — Simulate a tool call without executing (requires X-Admin-Key)',
1325
1337
  requestDryRunBatch: 'POST /requests/dry-run/batch — Simulate multiple tool calls without executing (requires X-Admin-Key)',
1326
1338
  toolStats: 'GET /tools/stats — Per-tool call counts, success rates, latency, credits, and top consumers (requires X-Admin-Key)',
1339
+ toolAvailability: 'GET /tools/available?key=... — Per-key tool availability with pricing, affordability, and rate limit status (requires X-Admin-Key)',
1340
+ keyDashboard: 'GET /keys/dashboard?key=... — Consolidated key overview with metadata, balance, health, velocity, rate limits, quotas, and recent activity (requires X-Admin-Key)',
1327
1341
  ...(this.oauth ? {
1328
1342
  oauthMetadata: 'GET /.well-known/oauth-authorization-server — OAuth 2.1 server metadata',
1329
1343
  oauthRegister: 'POST /oauth/register — Register OAuth client',
@@ -3282,6 +3296,188 @@ class PayGateServer {
3282
3296
  },
3283
3297
  }));
3284
3298
  }
3299
+ // ─── /keys/dashboard — Consolidated key overview ──────────────────────────────
3300
+ handleKeyDashboard(req, res) {
3301
+ if (!this.checkAdmin(req, res))
3302
+ return;
3303
+ const urlParts = req.url?.split('?') || [];
3304
+ const params = new URLSearchParams(urlParts[1] || '');
3305
+ const keyParam = params.get('key');
3306
+ if (!keyParam) {
3307
+ res.writeHead(400, { 'Content-Type': 'application/json' });
3308
+ res.end(JSON.stringify({ error: 'Missing required parameter: key' }));
3309
+ return;
3310
+ }
3311
+ const record = this.gate.store.resolveKeyRaw(keyParam);
3312
+ if (!record) {
3313
+ res.writeHead(404, { 'Content-Type': 'application/json' });
3314
+ res.end(JSON.stringify({ error: 'Key not found' }));
3315
+ return;
3316
+ }
3317
+ const actualKey = record.key;
3318
+ const maskedKey = actualKey.slice(0, 7) + '...' + actualKey.slice(-4);
3319
+ // ── Metadata ──
3320
+ const isExpired = record.expiresAt ? new Date(record.expiresAt).getTime() < Date.now() : false;
3321
+ let status = 'active';
3322
+ if (!record.active)
3323
+ status = 'revoked';
3324
+ else if (record.suspended)
3325
+ status = 'suspended';
3326
+ else if (isExpired)
3327
+ status = 'expired';
3328
+ const metadata = {
3329
+ key: maskedKey,
3330
+ name: record.name || null,
3331
+ status,
3332
+ namespace: record.namespace || null,
3333
+ group: record.group || null,
3334
+ createdAt: record.createdAt || null,
3335
+ ...(record.expiresAt ? { expiresAt: record.expiresAt } : {}),
3336
+ tags: record.tags && Object.keys(record.tags).length > 0 ? record.tags : undefined,
3337
+ };
3338
+ // ── Balance ──
3339
+ const balance = {
3340
+ credits: record.credits,
3341
+ totalSpent: record.totalSpent || 0,
3342
+ totalAllocated: record.credits + (record.totalSpent || 0),
3343
+ ...(record.spendingLimit ? { spendingLimit: record.spendingLimit } : {}),
3344
+ };
3345
+ // ── Health score (simplified from handleKeyHealth) ──
3346
+ const velocity = this.creditLedger.getSpendingVelocity(actualKey, record.credits, 24);
3347
+ let balanceScore = 100;
3348
+ if (velocity.creditsPerHour > 0) {
3349
+ const hoursLeft = velocity.estimatedHoursRemaining ?? Infinity;
3350
+ if (hoursLeft <= 1)
3351
+ balanceScore = 0;
3352
+ else if (hoursLeft <= 6)
3353
+ balanceScore = 20;
3354
+ else if (hoursLeft <= 24)
3355
+ balanceScore = 40;
3356
+ else if (hoursLeft <= 72)
3357
+ balanceScore = 60;
3358
+ else if (hoursLeft <= 168)
3359
+ balanceScore = 80;
3360
+ }
3361
+ else if (record.credits <= 0) {
3362
+ balanceScore = 0;
3363
+ }
3364
+ // Quota component
3365
+ let quotaScore = 100;
3366
+ const quotaConfig = record.quota || this.config.globalQuota;
3367
+ if (quotaConfig) {
3368
+ this.gate.quotaTracker.resetIfNeeded(record);
3369
+ let maxUtil = 0;
3370
+ if (quotaConfig.dailyCallLimit && quotaConfig.dailyCallLimit > 0)
3371
+ maxUtil = Math.max(maxUtil, record.quotaDailyCalls / quotaConfig.dailyCallLimit);
3372
+ if (quotaConfig.monthlyCallLimit && quotaConfig.monthlyCallLimit > 0)
3373
+ maxUtil = Math.max(maxUtil, record.quotaMonthlyCalls / quotaConfig.monthlyCallLimit);
3374
+ if (quotaConfig.dailyCreditLimit && quotaConfig.dailyCreditLimit > 0)
3375
+ maxUtil = Math.max(maxUtil, record.quotaDailyCredits / quotaConfig.dailyCreditLimit);
3376
+ if (quotaConfig.monthlyCreditLimit && quotaConfig.monthlyCreditLimit > 0)
3377
+ maxUtil = Math.max(maxUtil, record.quotaMonthlyCredits / quotaConfig.monthlyCreditLimit);
3378
+ quotaScore = Math.max(0, Math.round((1 - maxUtil) * 100));
3379
+ }
3380
+ // Rate limit component
3381
+ const rateStatus = this.gate.rateLimiter.getStatus(actualKey);
3382
+ let rateLimitScore = 100;
3383
+ if (rateStatus.limit > 0) {
3384
+ const utilization = rateStatus.used / rateStatus.limit;
3385
+ rateLimitScore = Math.max(0, Math.round((1 - utilization) * 100));
3386
+ }
3387
+ // Error rate component
3388
+ const keyUsage = this.gate.meter.getKeyUsage(actualKey);
3389
+ let errorScore = 100;
3390
+ if (keyUsage.totalCalls > 0) {
3391
+ const errorRate = keyUsage.totalDenied / keyUsage.totalCalls;
3392
+ errorScore = Math.max(0, Math.round((1 - errorRate) * 100));
3393
+ }
3394
+ const healthScore = Math.round(balanceScore * 0.30 + quotaScore * 0.25 + rateLimitScore * 0.20 + errorScore * 0.25);
3395
+ let healthStatus = 'healthy';
3396
+ if (healthScore < 25)
3397
+ healthStatus = 'critical';
3398
+ else if (healthScore < 50)
3399
+ healthStatus = 'warning';
3400
+ else if (healthScore < 75)
3401
+ healthStatus = 'caution';
3402
+ else if (healthScore < 90)
3403
+ healthStatus = 'good';
3404
+ // ── Velocity ──
3405
+ const velocitySummary = {
3406
+ creditsPerHour: velocity.creditsPerHour,
3407
+ creditsPerDay: velocity.creditsPerDay,
3408
+ callsPerHour: velocity.callsPerHour,
3409
+ callsPerDay: velocity.callsPerDay,
3410
+ estimatedDepletionDate: velocity.estimatedDepletionDate || null,
3411
+ };
3412
+ // ── Rate limits ──
3413
+ const rateLimits = {
3414
+ global: {
3415
+ limit: rateStatus.limit,
3416
+ used: rateStatus.used,
3417
+ remaining: rateStatus.remaining,
3418
+ resetInMs: rateStatus.resetInMs,
3419
+ },
3420
+ };
3421
+ // ── Quotas ──
3422
+ let quotas;
3423
+ if (quotaConfig) {
3424
+ this.gate.quotaTracker.resetIfNeeded(record);
3425
+ quotas = {
3426
+ source: record.quota ? 'per-key' : 'global',
3427
+ daily: {
3428
+ callsUsed: record.quotaDailyCalls,
3429
+ callsLimit: quotaConfig.dailyCallLimit || 0,
3430
+ creditsUsed: record.quotaDailyCredits,
3431
+ creditsLimit: quotaConfig.dailyCreditLimit || 0,
3432
+ },
3433
+ monthly: {
3434
+ callsUsed: record.quotaMonthlyCalls,
3435
+ callsLimit: quotaConfig.monthlyCallLimit || 0,
3436
+ creditsUsed: record.quotaMonthlyCredits,
3437
+ creditsLimit: quotaConfig.monthlyCreditLimit || 0,
3438
+ },
3439
+ };
3440
+ }
3441
+ // ── Usage summary ──
3442
+ const usage = {
3443
+ totalCalls: keyUsage.totalCalls || 0,
3444
+ totalAllowed: keyUsage.totalAllowed || 0,
3445
+ totalDenied: keyUsage.totalDenied || 0,
3446
+ totalCredits: keyUsage.totalCreditsSpent || 0,
3447
+ };
3448
+ // ── Recent activity (last 10 events) ──
3449
+ const maskedForAudit = (0, audit_1.maskKeyForAudit)(actualKey);
3450
+ const auditResult = this.audit.query({ limit: 100 });
3451
+ const recentActivity = auditResult.events
3452
+ .filter(e => {
3453
+ for (const field of ['key', 'keyMasked', 'sourceKey', 'destKey']) {
3454
+ const val = e.metadata?.[field];
3455
+ if (val && typeof val === 'string' && val === maskedForAudit)
3456
+ return true;
3457
+ }
3458
+ if (e.actor === maskedForAudit)
3459
+ return true;
3460
+ return false;
3461
+ })
3462
+ .slice(0, 10)
3463
+ .map(e => ({
3464
+ timestamp: e.timestamp,
3465
+ event: e.type,
3466
+ ...(e.metadata?.tool ? { tool: e.metadata.tool } : {}),
3467
+ ...(e.metadata?.credits ? { credits: e.metadata.credits } : {}),
3468
+ }));
3469
+ res.writeHead(200, { 'Content-Type': 'application/json' });
3470
+ res.end(JSON.stringify({
3471
+ ...metadata,
3472
+ balance,
3473
+ health: { score: healthScore, status: healthStatus },
3474
+ velocity: velocitySummary,
3475
+ rateLimits,
3476
+ ...(quotas ? { quotas } : {}),
3477
+ usage,
3478
+ recentActivity: recentActivity.length > 0 ? recentActivity : [],
3479
+ }));
3480
+ }
3285
3481
  // ─── /keys/auto-topup — Configure auto-topup ────────────────────────────────
3286
3482
  async handleSetAutoTopup(req, res) {
3287
3483
  if (req.method !== 'POST') {
@@ -6815,6 +7011,73 @@ class PayGateServer {
6815
7011
  res.end(JSON.stringify({ count: sorted.length, requests: sorted }, null, 2));
6816
7012
  }
6817
7013
  }
7014
+ // ─── /tools/available — Per-key tool availability with pricing ──────────────
7015
+ handleToolAvailability(req, res) {
7016
+ if (!this.checkAdmin(req, res))
7017
+ return;
7018
+ const urlParts = req.url?.split('?') || [];
7019
+ const params = new URLSearchParams(urlParts[1] || '');
7020
+ const keyParam = params.get('key');
7021
+ if (!keyParam) {
7022
+ res.writeHead(400, { 'Content-Type': 'application/json' });
7023
+ res.end(JSON.stringify({ error: 'Missing required parameter: key' }));
7024
+ return;
7025
+ }
7026
+ // Resolve alias
7027
+ const keyRecord = this.gate.store.resolveKeyRaw(keyParam);
7028
+ if (!keyRecord) {
7029
+ const isExpired = this.gate.store.isExpired(keyParam);
7030
+ const reason = isExpired ? 'api_key_expired' : 'invalid_api_key';
7031
+ res.writeHead(200, { 'Content-Type': 'application/json' });
7032
+ res.end(JSON.stringify({ error: reason, tools: [] }));
7033
+ return;
7034
+ }
7035
+ // Get all discovered tools with pricing
7036
+ const allToolPricing = this.registry.getFullPricing().tools;
7037
+ // Build per-tool availability
7038
+ const effectiveAllowed = keyRecord.allowedTools || [];
7039
+ const effectiveDenied = keyRecord.deniedTools || [];
7040
+ const tools = allToolPricing.map(toolInfo => {
7041
+ const toolName = toolInfo.name;
7042
+ // ACL check
7043
+ let accessible = true;
7044
+ let denyReason;
7045
+ if (effectiveDenied.includes(toolName)) {
7046
+ accessible = false;
7047
+ denyReason = 'denied_by_acl';
7048
+ }
7049
+ else if (effectiveAllowed.length > 0 && !effectiveAllowed.includes(toolName)) {
7050
+ accessible = false;
7051
+ denyReason = 'not_in_allowed_list';
7052
+ }
7053
+ // Affordability
7054
+ const creditsRequired = toolInfo.creditsPerCall;
7055
+ const canAfford = keyRecord.credits >= creditsRequired;
7056
+ // Per-tool rate limit status
7057
+ const perToolRateLimit = toolInfo.rateLimitPerMin > 0
7058
+ ? this.gate.rateLimiter.getStatus(`${keyRecord.key}:tool:${toolName}`, toolInfo.rateLimitPerMin)
7059
+ : null;
7060
+ return {
7061
+ tool: toolName,
7062
+ accessible,
7063
+ ...(denyReason ? { denyReason } : {}),
7064
+ creditsPerCall: creditsRequired,
7065
+ canAfford,
7066
+ ...(perToolRateLimit ? { rateLimit: perToolRateLimit } : {}),
7067
+ };
7068
+ });
7069
+ // Global rate limit
7070
+ const globalRateLimit = this.gate.rateLimiter.getStatus(keyRecord.key);
7071
+ res.writeHead(200, { 'Content-Type': 'application/json' });
7072
+ res.end(JSON.stringify({
7073
+ key: keyRecord.key.slice(0, 7) + '...' + keyRecord.key.slice(-4),
7074
+ creditsAvailable: keyRecord.credits,
7075
+ totalTools: tools.length,
7076
+ accessibleTools: tools.filter(t => t.accessible).length,
7077
+ ...(globalRateLimit.limit > 0 ? { globalRateLimit } : {}),
7078
+ tools,
7079
+ }));
7080
+ }
6818
7081
  /** Calculate percentile from an array of numbers. */
6819
7082
  percentile(values, p) {
6820
7083
  if (values.length === 0)