paygate-mcp 5.3.0 → 5.5.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 +70 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +87 -2
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
80
80
|
- **Key Expiry Scanner** — Proactive background scanner that detects expiring API keys before they expire — configurable scan interval and notification thresholds (default: 7d, 24h, 1h), de-duplicated `key.expiry_warning` webhook events, audit trail, `GET /keys/expiring?within=86400` query endpoint, and graceful shutdown
|
|
81
81
|
- **Key Templates** — Named templates for API key creation — define reusable presets (credits, ACL, quotas, IP, tags, namespace, expiry TTL, spending limit, auto-topup) and create keys with `template: "free-tier"` — explicit params override template defaults, CRUD admin API, Prometheus gauge, file persistence, max 100 templates
|
|
82
82
|
- **Environment Variables Config** — Configure everything via `PAYGATE_*` env vars for Docker/K8s deployments — 18 env vars covering all CLI flags, with priority: CLI flags > env vars > config file > defaults, `PAYGATE_CONFIG` loads config file path, help text with Docker examples
|
|
83
|
+
- **Request ID Tracking** — Every HTTP response includes `X-Request-Id` header (auto-generated `req_` prefix + 16 hex chars) for distributed tracing — propagates incoming `X-Request-Id` from load balancers/proxies, included in gate audit log metadata, CORS-exposed, available via `getRequestId(req)` helper
|
|
84
|
+
- **Server Info Endpoint** — `GET /info` returns server capabilities, enabled features, auth methods, pricing summary, rate limits, and available endpoints — public, no admin key required, ideal for agent auto-discovery and debugging
|
|
83
85
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
84
86
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
85
87
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -1377,6 +1379,74 @@ All 18 supported environment variables:
|
|
|
1377
1379
|
|
|
1378
1380
|
**Priority:** CLI flags > env vars > config file > defaults. This means you can set defaults via env vars in Docker and override specific values on the command line.
|
|
1379
1381
|
|
|
1382
|
+
### Request ID Tracking
|
|
1383
|
+
|
|
1384
|
+
Every HTTP response includes an `X-Request-Id` header for distributed tracing. If the incoming request has an `X-Request-Id` header (e.g., from a load balancer or API gateway), it is propagated through. Otherwise, a new ID is auto-generated with the format `req_<16 hex chars>`.
|
|
1385
|
+
|
|
1386
|
+
```bash
|
|
1387
|
+
# Auto-generated request ID
|
|
1388
|
+
curl -v http://localhost:3402/health
|
|
1389
|
+
# < X-Request-Id: req_a1b2c3d4e5f67890
|
|
1390
|
+
|
|
1391
|
+
# Propagate your own trace ID
|
|
1392
|
+
curl -v -H "X-Request-Id: my-trace-123" http://localhost:3402/health
|
|
1393
|
+
# < X-Request-Id: my-trace-123
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
| Feature | Details |
|
|
1397
|
+
|---------|---------|
|
|
1398
|
+
| Format | `req_` + 16 hex chars (8 bytes of randomness) |
|
|
1399
|
+
| Propagation | Incoming `X-Request-Id` header is preserved and returned |
|
|
1400
|
+
| CORS | Included in `Access-Control-Allow-Headers` and `Access-Control-Expose-Headers` |
|
|
1401
|
+
| Audit | Request ID appears in `gate.allow`, `gate.deny`, and `session.created` audit metadata |
|
|
1402
|
+
| Exports | `generateRequestId()` and `getRequestId(req)` available in SDK |
|
|
1403
|
+
|
|
1404
|
+
### Server Info Endpoint
|
|
1405
|
+
|
|
1406
|
+
`GET /info` returns a comprehensive JSON object describing the server's capabilities. Public endpoint — no admin key required.
|
|
1407
|
+
|
|
1408
|
+
```bash
|
|
1409
|
+
curl http://localhost:3402/info
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
```json
|
|
1413
|
+
{
|
|
1414
|
+
"name": "My API Server",
|
|
1415
|
+
"version": "5.5.0",
|
|
1416
|
+
"transport": "stdio",
|
|
1417
|
+
"port": 3402,
|
|
1418
|
+
"auth": ["api_key", "scoped_token"],
|
|
1419
|
+
"features": {
|
|
1420
|
+
"shadowMode": false,
|
|
1421
|
+
"webhooks": true,
|
|
1422
|
+
"webhookSignatures": true,
|
|
1423
|
+
"refundOnFailure": true,
|
|
1424
|
+
"redis": false,
|
|
1425
|
+
"oauth": false,
|
|
1426
|
+
"plugins": false,
|
|
1427
|
+
"multiServer": false
|
|
1428
|
+
},
|
|
1429
|
+
"pricing": {
|
|
1430
|
+
"defaultCreditsPerCall": 1,
|
|
1431
|
+
"toolPricing": {
|
|
1432
|
+
"expensive-tool": { "creditsPerCall": 10 }
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
"rateLimit": { "globalPerMin": 60 },
|
|
1436
|
+
"endpoints": {
|
|
1437
|
+
"mcp": "/mcp",
|
|
1438
|
+
"health": "/health",
|
|
1439
|
+
"info": "/info",
|
|
1440
|
+
"status": "/status (admin)",
|
|
1441
|
+
"keys": "/keys (admin)",
|
|
1442
|
+
"metrics": "/metrics",
|
|
1443
|
+
"pricing": "/pricing",
|
|
1444
|
+
"audit": "/audit (admin)",
|
|
1445
|
+
"analytics": "/analytics (admin)"
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1380
1450
|
### IP Allowlisting
|
|
1381
1451
|
|
|
1382
1452
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* const { port, adminKey } = await server.start();
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export { PayGateServer } from './server';
|
|
17
|
+
export { PayGateServer, generateRequestId, getRequestId } from './server';
|
|
18
18
|
export { Gate } from './gate';
|
|
19
19
|
export { McpProxy } from './proxy';
|
|
20
20
|
export { HttpMcpProxy } from './http-proxy';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.DEFAULT_CONFIG = exports.KeyGroupManager = exports.PluginManager = exports.VALID_ROLES = exports.ROLE_HIERARCHY = exports.AdminKeyManager = exports.TokenRevocationList = exports.ScopedTokenManager = exports.formatDiagnostics = exports.validateConfig = exports.PayGateError = exports.PayGateClient = exports.RedisSync = exports.RedisSubscriber = exports.parseRedisUrl = exports.RedisClient = exports.TeamManager = exports.AlertEngine = exports.AnalyticsEngine = exports.getDashboardHtml = exports.MetricsCollector = exports.ToolRegistry = exports.maskKeyForAudit = exports.AuditLogger = exports.writeSseKeepAlive = exports.writeSseEvent = exports.writeSseHeaders = exports.SessionManager = exports.OAuthProvider = exports.QuotaTracker = exports.WebhookRouter = exports.WebhookEmitter = exports.StripeWebhookHandler = exports.RateLimiter = exports.UsageMeter = exports.KeyStore = exports.MultiServerRouter = exports.HttpMcpProxy = exports.McpProxy = exports.Gate = exports.PayGateServer = void 0;
|
|
19
|
+
exports.DEFAULT_CONFIG = exports.KeyGroupManager = exports.PluginManager = exports.VALID_ROLES = exports.ROLE_HIERARCHY = exports.AdminKeyManager = exports.TokenRevocationList = exports.ScopedTokenManager = exports.formatDiagnostics = exports.validateConfig = exports.PayGateError = exports.PayGateClient = exports.RedisSync = exports.RedisSubscriber = exports.parseRedisUrl = exports.RedisClient = exports.TeamManager = exports.AlertEngine = exports.AnalyticsEngine = exports.getDashboardHtml = exports.MetricsCollector = exports.ToolRegistry = exports.maskKeyForAudit = exports.AuditLogger = exports.writeSseKeepAlive = exports.writeSseEvent = exports.writeSseHeaders = exports.SessionManager = exports.OAuthProvider = exports.QuotaTracker = exports.WebhookRouter = exports.WebhookEmitter = exports.StripeWebhookHandler = exports.RateLimiter = exports.UsageMeter = exports.KeyStore = exports.MultiServerRouter = exports.HttpMcpProxy = exports.McpProxy = exports.Gate = exports.getRequestId = exports.generateRequestId = exports.PayGateServer = void 0;
|
|
20
20
|
var server_1 = require("./server");
|
|
21
21
|
Object.defineProperty(exports, "PayGateServer", { enumerable: true, get: function () { return server_1.PayGateServer; } });
|
|
22
|
+
Object.defineProperty(exports, "generateRequestId", { enumerable: true, get: function () { return server_1.generateRequestId; } });
|
|
23
|
+
Object.defineProperty(exports, "getRequestId", { enumerable: true, get: function () { return server_1.getRequestId; } });
|
|
22
24
|
var gate_1 = require("./gate");
|
|
23
25
|
Object.defineProperty(exports, "Gate", { enumerable: true, get: function () { return gate_1.Gate; } });
|
|
24
26
|
var proxy_1 = require("./proxy");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,mCAA0E;AAAjE,uGAAA,aAAa,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAAE,sGAAA,YAAY,OAAA;AACvD,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,2CAA4C;AAAnC,0GAAA,YAAY,OAAA;AACrB,mCAA6C;AAApC,2GAAA,iBAAiB,OAAA;AAC1B,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,iCAAqC;AAA5B,mGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mCAAgD;AAAvC,8GAAA,oBAAoB,OAAA;AAC7B,qCAA2C;AAAlC,yGAAA,cAAc,OAAA;AAEvB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA;AACrB,iCAAwC;AAA/B,sGAAA,aAAa,OAAA;AAEtB,qCAA8F;AAArF,yGAAA,cAAc,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,wGAAA,aAAa,OAAA;AAAE,4GAAA,iBAAiB,OAAA;AAC1E,iCAAuD;AAA9C,oGAAA,WAAW,OAAA;AAAE,wGAAA,eAAe,OAAA;AAErC,uCAA0C;AAAjC,wGAAA,YAAY,OAAA;AACrB,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AAIzB,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AACzB,yCAA8C;AAArC,4GAAA,eAAe,OAAA;AAExB,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAEpB,iCAAsC;AAA7B,oGAAA,WAAW,OAAA;AAEpB,+CAA6E;AAApE,2GAAA,WAAW,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,+GAAA,eAAe,OAAA;AAEpD,2CAAyC;AAAhC,uGAAA,SAAS,OAAA;AAElB,mCAAuD;AAA9C,uGAAA,aAAa,OAAA;AAAE,sGAAA,YAAY,OAAA;AAEpC,uDAAuE;AAA9D,kHAAA,cAAc,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE1C,mCAAmE;AAA1D,4GAAA,kBAAkB,OAAA;AAAE,6GAAA,mBAAmB,OAAA;AAEhD,2CAA4E;AAAnE,6GAAA,eAAe,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,yGAAA,WAAW,OAAA;AAErD,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AAEtB,mCAA2C;AAAlC,yGAAA,eAAe,OAAA;AAsBxB,iCAAyC;AAAhC,uGAAA,cAAc,OAAA"}
|
package/dist/server.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* API key is sent via X-API-Key header on /mcp endpoint.
|
|
13
13
|
* Admin endpoints (/keys, /topup, /status) require X-Admin-Key header.
|
|
14
14
|
*/
|
|
15
|
+
import { IncomingMessage } from 'http';
|
|
15
16
|
import { PayGateConfig, ServerBackendConfig } from './types';
|
|
16
17
|
import { Gate } from './gate';
|
|
17
18
|
import { McpProxy } from './proxy';
|
|
@@ -32,6 +33,10 @@ import { PluginManager, PayGatePlugin } from './plugin';
|
|
|
32
33
|
import { KeyGroupManager } from './groups';
|
|
33
34
|
import { ExpiryScanner } from './expiry-scanner';
|
|
34
35
|
import { KeyTemplateManager } from './key-templates';
|
|
36
|
+
/** Generate a unique request ID (16 hex chars = 8 bytes of randomness) */
|
|
37
|
+
export declare function generateRequestId(): string;
|
|
38
|
+
/** Extract request ID from an IncomingMessage (set by PayGateServer handleRequest) */
|
|
39
|
+
export declare function getRequestId(req: IncomingMessage): string | undefined;
|
|
35
40
|
/** Union type for both proxy backends */
|
|
36
41
|
type ProxyBackend = McpProxy | HttpMcpProxy;
|
|
37
42
|
export declare class PayGateServer {
|
|
@@ -134,6 +139,7 @@ export declare class PayGateServer {
|
|
|
134
139
|
private handleRoot;
|
|
135
140
|
private handleStatus;
|
|
136
141
|
private handleHealth;
|
|
142
|
+
private handleInfo;
|
|
137
143
|
private handleCreateKey;
|
|
138
144
|
private handleListKeys;
|
|
139
145
|
private handleTopUp;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -48,9 +48,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
48
48
|
})();
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
50
|
exports.PayGateServer = void 0;
|
|
51
|
+
exports.generateRequestId = generateRequestId;
|
|
52
|
+
exports.getRequestId = getRequestId;
|
|
51
53
|
const http_1 = require("http");
|
|
52
54
|
const fs_1 = require("fs");
|
|
53
55
|
const path_1 = require("path");
|
|
56
|
+
const crypto_1 = require("crypto");
|
|
54
57
|
const types_1 = require("./types");
|
|
55
58
|
const config_validator_1 = require("./config-validator");
|
|
56
59
|
/** Read version from package.json at runtime */
|
|
@@ -87,6 +90,14 @@ const expiry_scanner_1 = require("./expiry-scanner");
|
|
|
87
90
|
const key_templates_1 = require("./key-templates");
|
|
88
91
|
/** Max request body size: 1MB */
|
|
89
92
|
const MAX_BODY_SIZE = 1_048_576;
|
|
93
|
+
/** Generate a unique request ID (16 hex chars = 8 bytes of randomness) */
|
|
94
|
+
function generateRequestId() {
|
|
95
|
+
return `req_${(0, crypto_1.randomBytes)(8).toString('hex')}`;
|
|
96
|
+
}
|
|
97
|
+
/** Extract request ID from an IncomingMessage (set by PayGateServer handleRequest) */
|
|
98
|
+
function getRequestId(req) {
|
|
99
|
+
return req._requestId;
|
|
100
|
+
}
|
|
90
101
|
class PayGateServer {
|
|
91
102
|
gate;
|
|
92
103
|
/** Single-server proxy (when not in multi-server mode) */
|
|
@@ -353,11 +364,16 @@ class PayGateServer {
|
|
|
353
364
|
});
|
|
354
365
|
}
|
|
355
366
|
async handleRequest(req, res) {
|
|
367
|
+
// Request ID: propagate from incoming header or generate new one
|
|
368
|
+
const requestId = req.headers['x-request-id'] || generateRequestId();
|
|
369
|
+
res.setHeader('X-Request-Id', requestId);
|
|
370
|
+
// Stash on request for downstream access
|
|
371
|
+
req._requestId = requestId;
|
|
356
372
|
// CORS headers
|
|
357
373
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
358
374
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
359
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-API-Key, X-Admin-Key, Mcp-Session-Id, Authorization');
|
|
360
|
-
res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Credits-Remaining');
|
|
375
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-API-Key, X-Admin-Key, Mcp-Session-Id, Authorization, X-Request-Id');
|
|
376
|
+
res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Credits-Remaining, X-Request-Id');
|
|
361
377
|
if (req.method === 'OPTIONS') {
|
|
362
378
|
res.writeHead(204);
|
|
363
379
|
res.end();
|
|
@@ -380,6 +396,8 @@ class PayGateServer {
|
|
|
380
396
|
return this.handleMcp(req, res);
|
|
381
397
|
case '/health':
|
|
382
398
|
return this.handleHealth(req, res);
|
|
399
|
+
case '/info':
|
|
400
|
+
return this.handleInfo(req, res);
|
|
383
401
|
case '/status':
|
|
384
402
|
return this.handleStatus(req, res);
|
|
385
403
|
case '/keys':
|
|
@@ -580,6 +598,8 @@ class PayGateServer {
|
|
|
580
598
|
async handleMcp(req, res) {
|
|
581
599
|
this.inflight++;
|
|
582
600
|
res.on('close', () => { this.inflight--; });
|
|
601
|
+
// Extract request ID (set by handleRequest)
|
|
602
|
+
const requestId = req._requestId;
|
|
583
603
|
// Resolve API key from X-API-Key or Bearer token
|
|
584
604
|
const apiKey = this.resolveApiKey(req);
|
|
585
605
|
// GET /mcp — Open SSE stream for server-to-client notifications
|
|
@@ -611,6 +631,7 @@ class PayGateServer {
|
|
|
611
631
|
if (!sessionId || !this.sessions.getSession(sessionId)) {
|
|
612
632
|
sessionId = this.sessions.createSession(apiKey);
|
|
613
633
|
this.audit.log('session.created', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Session created`, {
|
|
634
|
+
requestId,
|
|
614
635
|
sessionId: sessionId.slice(0, 16) + '...',
|
|
615
636
|
});
|
|
616
637
|
}
|
|
@@ -638,6 +659,7 @@ class PayGateServer {
|
|
|
638
659
|
// Audit + metrics for batch
|
|
639
660
|
if (batchResponse.error) {
|
|
640
661
|
this.audit.log('gate.deny', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Batch denied (${calls.length} calls)`, {
|
|
662
|
+
requestId,
|
|
641
663
|
callCount: calls.length,
|
|
642
664
|
errorCode: batchResponse.error.code,
|
|
643
665
|
reason: batchResponse.error.message,
|
|
@@ -649,6 +671,7 @@ class PayGateServer {
|
|
|
649
671
|
else {
|
|
650
672
|
const resultData = batchResponse.result;
|
|
651
673
|
this.audit.log('gate.allow', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Batch allowed (${calls.length} calls)`, {
|
|
674
|
+
requestId,
|
|
652
675
|
callCount: calls.length,
|
|
653
676
|
totalCredits: resultData?.totalCreditsCharged ?? 0,
|
|
654
677
|
});
|
|
@@ -707,6 +730,7 @@ class PayGateServer {
|
|
|
707
730
|
: response.error.code === -32001 ? 'rate_limited'
|
|
708
731
|
: response.error.message || 'denied';
|
|
709
732
|
this.audit.log('gate.deny', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Denied: ${toolName}`, {
|
|
733
|
+
requestId,
|
|
710
734
|
tool: toolName,
|
|
711
735
|
errorCode: response.error.code,
|
|
712
736
|
reason: response.error.message,
|
|
@@ -722,6 +746,7 @@ class PayGateServer {
|
|
|
722
746
|
}
|
|
723
747
|
else {
|
|
724
748
|
this.audit.log('gate.allow', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Allowed: ${toolName}`, {
|
|
749
|
+
requestId,
|
|
725
750
|
tool: toolName,
|
|
726
751
|
});
|
|
727
752
|
// Estimate credits from config (actual deduction tracked in gate)
|
|
@@ -924,6 +949,7 @@ class PayGateServer {
|
|
|
924
949
|
version: PKG_VERSION,
|
|
925
950
|
endpoints: {
|
|
926
951
|
mcp: 'POST /mcp — JSON-RPC (MCP transport). Send X-API-Key header.',
|
|
952
|
+
info: 'GET /info — Server capabilities, features, pricing summary (public)',
|
|
927
953
|
balance: 'GET /balance — Check own credits (requires X-API-Key)',
|
|
928
954
|
dashboard: 'GET /dashboard — Admin web dashboard (browser UI)',
|
|
929
955
|
status: 'GET /status — Usage data JSON (requires X-Admin-Key)',
|
|
@@ -1050,6 +1076,65 @@ class PayGateServer {
|
|
|
1050
1076
|
res.writeHead(httpStatus, { 'Content-Type': 'application/json' });
|
|
1051
1077
|
res.end(JSON.stringify(health));
|
|
1052
1078
|
}
|
|
1079
|
+
// ─── /info — Server capabilities and feature summary ────────────────────────
|
|
1080
|
+
handleInfo(req, res) {
|
|
1081
|
+
if (req.method !== 'GET') {
|
|
1082
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
1083
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const features = {
|
|
1087
|
+
shadowMode: this.config.shadowMode,
|
|
1088
|
+
webhooks: !!this.config.webhookUrl,
|
|
1089
|
+
webhookSignatures: !!this.config.webhookSecret,
|
|
1090
|
+
webhookFilters: !!(this.config.webhookFilters && this.config.webhookFilters.length > 0),
|
|
1091
|
+
refundOnFailure: this.config.refundOnFailure,
|
|
1092
|
+
oauth: !!this.config.oauth,
|
|
1093
|
+
redis: !!this.redisSync,
|
|
1094
|
+
teams: this.teams.listTeams().length > 0,
|
|
1095
|
+
plugins: this.plugins.count > 0,
|
|
1096
|
+
alerts: !!(this.config.alertRules && this.config.alertRules.length > 0),
|
|
1097
|
+
expiryScanner: !!(this.expiryScanner),
|
|
1098
|
+
templates: this.templates.list().length > 0,
|
|
1099
|
+
multiServer: !!this.router,
|
|
1100
|
+
quotas: !!this.config.globalQuota,
|
|
1101
|
+
};
|
|
1102
|
+
const pricing = {
|
|
1103
|
+
defaultCreditsPerCall: this.config.defaultCreditsPerCall,
|
|
1104
|
+
toolPricing: Object.keys(this.config.toolPricing).length > 0
|
|
1105
|
+
? Object.fromEntries(Object.entries(this.config.toolPricing).map(([tool, p]) => [tool, { creditsPerCall: p.creditsPerCall }]))
|
|
1106
|
+
: {},
|
|
1107
|
+
};
|
|
1108
|
+
const auth = ['api_key'];
|
|
1109
|
+
if (this.config.oauth)
|
|
1110
|
+
auth.push('oauth2');
|
|
1111
|
+
auth.push('scoped_token');
|
|
1112
|
+
const info = {
|
|
1113
|
+
name: this.config.name,
|
|
1114
|
+
version: PKG_VERSION,
|
|
1115
|
+
transport: this.router ? 'multi-server' : (this.proxy instanceof http_proxy_1.HttpMcpProxy ? 'http' : 'stdio'),
|
|
1116
|
+
port: this.config.port,
|
|
1117
|
+
auth,
|
|
1118
|
+
features,
|
|
1119
|
+
pricing,
|
|
1120
|
+
rateLimit: {
|
|
1121
|
+
globalPerMin: this.config.globalRateLimitPerMin,
|
|
1122
|
+
},
|
|
1123
|
+
endpoints: {
|
|
1124
|
+
mcp: '/mcp',
|
|
1125
|
+
health: '/health',
|
|
1126
|
+
info: '/info',
|
|
1127
|
+
status: '/status (admin)',
|
|
1128
|
+
keys: '/keys (admin)',
|
|
1129
|
+
metrics: '/metrics',
|
|
1130
|
+
pricing: '/pricing',
|
|
1131
|
+
audit: '/audit (admin)',
|
|
1132
|
+
analytics: '/analytics (admin)',
|
|
1133
|
+
},
|
|
1134
|
+
};
|
|
1135
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1136
|
+
res.end(JSON.stringify(info));
|
|
1137
|
+
}
|
|
1053
1138
|
// ─── /keys — Create ─────────────────────────────────────────────────────────
|
|
1054
1139
|
async handleCreateKey(req, res) {
|
|
1055
1140
|
if (!this.checkAdmin(req, res, 'admin'))
|