paygate-mcp 10.4.0 → 10.6.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.
Files changed (43) hide show
  1. package/dist/billable-metrics.d.ts +130 -0
  2. package/dist/billable-metrics.d.ts.map +1 -0
  3. package/dist/billable-metrics.js +387 -0
  4. package/dist/billable-metrics.js.map +1 -0
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +117 -0
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.d.ts +15 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +20 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/openapi-backend.d.ts +68 -0
  13. package/dist/openapi-backend.d.ts.map +1 -0
  14. package/dist/openapi-backend.js +179 -0
  15. package/dist/openapi-backend.js.map +1 -0
  16. package/dist/openapi-to-mcp.d.ts +113 -0
  17. package/dist/openapi-to-mcp.d.ts.map +1 -0
  18. package/dist/openapi-to-mcp.js +318 -0
  19. package/dist/openapi-to-mcp.js.map +1 -0
  20. package/dist/otel-emitter.d.ts +159 -0
  21. package/dist/otel-emitter.d.ts.map +1 -0
  22. package/dist/otel-emitter.js +349 -0
  23. package/dist/otel-emitter.js.map +1 -0
  24. package/dist/pii-masking.d.ts +150 -0
  25. package/dist/pii-masking.d.ts.map +1 -0
  26. package/dist/pii-masking.js +303 -0
  27. package/dist/pii-masking.js.map +1 -0
  28. package/dist/server.d.ts +6 -1
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +111 -1
  31. package/dist/server.js.map +1 -1
  32. package/dist/types.d.ts +24 -0
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/types.js.map +1 -1
  35. package/dist/virtual-server.d.ts +140 -0
  36. package/dist/virtual-server.d.ts.map +1 -0
  37. package/dist/virtual-server.js +339 -0
  38. package/dist/virtual-server.js.map +1 -0
  39. package/dist/x402.d.ts +100 -0
  40. package/dist/x402.d.ts.map +1 -0
  41. package/dist/x402.js +248 -0
  42. package/dist/x402.js.map +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Billable Metric Expressions — Config-driven pricing formulas.
3
+ *
4
+ * Instead of flat per-call pricing, define expressions that compute
5
+ * cost based on request/response attributes:
6
+ *
7
+ * cost = input_tokens * 0.001 + output_tokens * 0.003
8
+ * cost = max(1, file_size_kb * 0.5)
9
+ * cost = base_cost + (duration_ms / 1000) * 2
10
+ *
11
+ * SECURITY: Expressions are parsed with a safe recursive descent parser.
12
+ * NO JavaScript eval(), NO Function constructor. The parser only
13
+ * supports arithmetic (+, -, *, /, %), built-in math functions
14
+ * (min, max, ceil, floor, round, abs, sqrt, log, pow),
15
+ * numeric literals, and named variables.
16
+ *
17
+ * Features:
18
+ * - Safe expression parsing (AST-based, no code execution)
19
+ * - Built-in math functions: min, max, ceil, floor, round, abs
20
+ * - Variable binding from tool args and response fields
21
+ * - Per-tool metric definitions
22
+ * - Fallback to flat pricing if expression errors
23
+ * - Statistics and audit trail
24
+ *
25
+ * Zero external dependencies.
26
+ */
27
+ export interface BillableMetric {
28
+ /** Unique metric ID. */
29
+ id: string;
30
+ /** Human-readable name. */
31
+ name: string;
32
+ /** Expression string (e.g., 'input_tokens * 0.001 + output_tokens * 0.003'). */
33
+ expression: string;
34
+ /** Tools this metric applies to. Empty = all. */
35
+ tools: string[];
36
+ /** Minimum cost (floor). Default: 0. */
37
+ minCost?: number;
38
+ /** Maximum cost (ceiling). Default: Infinity. */
39
+ maxCost?: number;
40
+ /** Whether this metric is active. Default: true. */
41
+ active: boolean;
42
+ /** Description. */
43
+ description?: string;
44
+ /** Fallback flat cost if expression fails. Default: 1. */
45
+ fallbackCost?: number;
46
+ }
47
+ export interface MetricContext {
48
+ /** Tool name. */
49
+ tool: string;
50
+ /** Input arguments (flattened key-value). */
51
+ inputArgs: Record<string, unknown>;
52
+ /** Response content (if post-call). */
53
+ responseContent?: string;
54
+ /** Response size in bytes. */
55
+ responseSizeBytes?: number;
56
+ /** Call duration in ms. */
57
+ durationMs?: number;
58
+ /** Input size in bytes. */
59
+ inputSizeBytes?: number;
60
+ /** Custom variables injected by caller. */
61
+ customVars?: Record<string, number>;
62
+ }
63
+ export interface MetricResult {
64
+ /** Computed cost in credits. */
65
+ cost: number;
66
+ /** Metric ID used. */
67
+ metricId: string;
68
+ /** Whether fallback was used. */
69
+ usedFallback: boolean;
70
+ /** Error if expression failed. */
71
+ error?: string;
72
+ /** Variables resolved for the expression. */
73
+ resolvedVars: Record<string, number>;
74
+ }
75
+ export interface BillableMetricStats {
76
+ /** Total evaluations. */
77
+ totalEvaluations: number;
78
+ /** Successful expression evaluations. */
79
+ successfulEvals: number;
80
+ /** Fallback evaluations (expression error). */
81
+ fallbackEvals: number;
82
+ /** Total credits computed. */
83
+ totalCreditsComputed: number;
84
+ /** Evaluations by metric ID. */
85
+ byMetric: Record<string, number>;
86
+ /** Evaluations by tool. */
87
+ byTool: Record<string, number>;
88
+ }
89
+ /**
90
+ * Safely compute a math expression with named variables.
91
+ *
92
+ * Uses a recursive descent parser. No JavaScript code execution.
93
+ * Only supports: numbers, variables, +, -, *, /, %, parentheses,
94
+ * and built-in math functions (min, max, ceil, floor, round, abs, sqrt, log, pow).
95
+ */
96
+ export declare function computeExpression(expression: string, vars: Record<string, number>): number;
97
+ export declare class BillableMetricEngine {
98
+ private metrics;
99
+ private stats;
100
+ constructor(metrics?: BillableMetric[]);
101
+ /** Get all metrics. */
102
+ getMetrics(): BillableMetric[];
103
+ /** Add or update a metric. */
104
+ upsertMetric(metric: BillableMetric): BillableMetric;
105
+ /** Remove a metric by ID. */
106
+ removeMetric(id: string): boolean;
107
+ /**
108
+ * Find the matching metric for a tool.
109
+ * Returns the first active metric whose tool list matches.
110
+ */
111
+ findMetric(tool: string): BillableMetric | null;
112
+ /**
113
+ * Compute cost for a tool call using billable metric expressions.
114
+ *
115
+ * @param context - Context with args, response, timing data
116
+ * @returns Result with computed cost, or null if no metric matches
117
+ */
118
+ computeCost(context: MetricContext): MetricResult | null;
119
+ /** Get statistics. */
120
+ getStats(): BillableMetricStats;
121
+ /** Reset stats. */
122
+ resetStats(): void;
123
+ /** Export metrics for backup/serialization. */
124
+ exportMetrics(): BillableMetric[];
125
+ /** Import metrics. */
126
+ importMetrics(metrics: BillableMetric[], mode?: 'merge' | 'replace'): number;
127
+ /** Destroy. */
128
+ destroy(): void;
129
+ }
130
+ //# sourceMappingURL=billable-metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billable-metrics.d.ts","sourceRoot":"","sources":["../src/billable-metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+ /**
3
+ * Billable Metric Expressions — Config-driven pricing formulas.
4
+ *
5
+ * Instead of flat per-call pricing, define expressions that compute
6
+ * cost based on request/response attributes:
7
+ *
8
+ * cost = input_tokens * 0.001 + output_tokens * 0.003
9
+ * cost = max(1, file_size_kb * 0.5)
10
+ * cost = base_cost + (duration_ms / 1000) * 2
11
+ *
12
+ * SECURITY: Expressions are parsed with a safe recursive descent parser.
13
+ * NO JavaScript eval(), NO Function constructor. The parser only
14
+ * supports arithmetic (+, -, *, /, %), built-in math functions
15
+ * (min, max, ceil, floor, round, abs, sqrt, log, pow),
16
+ * numeric literals, and named variables.
17
+ *
18
+ * Features:
19
+ * - Safe expression parsing (AST-based, no code execution)
20
+ * - Built-in math functions: min, max, ceil, floor, round, abs
21
+ * - Variable binding from tool args and response fields
22
+ * - Per-tool metric definitions
23
+ * - Fallback to flat pricing if expression errors
24
+ * - Statistics and audit trail
25
+ *
26
+ * Zero external dependencies.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.BillableMetricEngine = void 0;
30
+ exports.computeExpression = computeExpression;
31
+ /** Tokenize an expression string into a list of tokens. */
32
+ function tokenize(expr) {
33
+ const tokens = [];
34
+ let i = 0;
35
+ while (i < expr.length) {
36
+ const ch = expr[i];
37
+ // Skip whitespace
38
+ if (/\s/.test(ch)) {
39
+ i++;
40
+ continue;
41
+ }
42
+ // Number literal
43
+ if (/[0-9.]/.test(ch)) {
44
+ let num = '';
45
+ while (i < expr.length && /[0-9.]/.test(expr[i])) {
46
+ num += expr[i++];
47
+ }
48
+ tokens.push({ type: 'number', value: num, numValue: parseFloat(num) });
49
+ continue;
50
+ }
51
+ // Identifier (variable name or function name)
52
+ if (/[a-zA-Z_]/.test(ch)) {
53
+ let ident = '';
54
+ while (i < expr.length && /[a-zA-Z0-9_]/.test(expr[i])) {
55
+ ident += expr[i++];
56
+ }
57
+ tokens.push({ type: 'ident', value: ident });
58
+ continue;
59
+ }
60
+ // Arithmetic operators
61
+ if ('+-*/%'.includes(ch)) {
62
+ tokens.push({ type: 'op', value: ch });
63
+ i++;
64
+ continue;
65
+ }
66
+ // Parentheses and comma
67
+ if (ch === '(') {
68
+ tokens.push({ type: 'lparen', value: '(' });
69
+ i++;
70
+ continue;
71
+ }
72
+ if (ch === ')') {
73
+ tokens.push({ type: 'rparen', value: ')' });
74
+ i++;
75
+ continue;
76
+ }
77
+ if (ch === ',') {
78
+ tokens.push({ type: 'comma', value: ',' });
79
+ i++;
80
+ continue;
81
+ }
82
+ throw new Error(`Unexpected character: ${ch} at position ${i}`);
83
+ }
84
+ tokens.push({ type: 'eof', value: '' });
85
+ return tokens;
86
+ }
87
+ /**
88
+ * Recursive descent parser for arithmetic expressions.
89
+ * Grammar:
90
+ * expr = addSub
91
+ * addSub = mulDiv (('+' | '-') mulDiv)*
92
+ * mulDiv = unary (('*' | '/' | '%') unary)*
93
+ * unary = ('-' | '+')? primary
94
+ * primary = NUMBER | IDENT | IDENT '(' args ')' | '(' expr ')'
95
+ * args = expr (',' expr)*
96
+ */
97
+ class ExprParser {
98
+ tokens;
99
+ pos = 0;
100
+ vars;
101
+ funcs;
102
+ constructor(tokens, vars) {
103
+ this.tokens = tokens;
104
+ this.vars = vars;
105
+ this.funcs = {
106
+ min: Math.min,
107
+ max: Math.max,
108
+ ceil: Math.ceil,
109
+ floor: Math.floor,
110
+ round: Math.round,
111
+ abs: Math.abs,
112
+ sqrt: Math.sqrt,
113
+ log: Math.log,
114
+ log10: Math.log10,
115
+ pow: Math.pow,
116
+ };
117
+ }
118
+ parse() {
119
+ const result = this.parseAddSub();
120
+ if (this.tokens[this.pos].type !== 'eof') {
121
+ throw new Error(`Unexpected token: ${this.tokens[this.pos].value}`);
122
+ }
123
+ return result;
124
+ }
125
+ parseAddSub() {
126
+ let left = this.parseMulDiv();
127
+ while (this.pos < this.tokens.length && this.tokens[this.pos].type === 'op' && '+-'.includes(this.tokens[this.pos].value)) {
128
+ const op = this.tokens[this.pos++].value;
129
+ const right = this.parseMulDiv();
130
+ left = op === '+' ? left + right : left - right;
131
+ }
132
+ return left;
133
+ }
134
+ parseMulDiv() {
135
+ let left = this.parseUnary();
136
+ while (this.pos < this.tokens.length && this.tokens[this.pos].type === 'op' && '*/%'.includes(this.tokens[this.pos].value)) {
137
+ const op = this.tokens[this.pos++].value;
138
+ const right = this.parseUnary();
139
+ if (op === '*')
140
+ left *= right;
141
+ else if (op === '/')
142
+ left = right !== 0 ? left / right : 0;
143
+ else
144
+ left = right !== 0 ? left % right : 0;
145
+ }
146
+ return left;
147
+ }
148
+ parseUnary() {
149
+ if (this.tokens[this.pos].type === 'op' && this.tokens[this.pos].value === '-') {
150
+ this.pos++;
151
+ return -this.parsePrimary();
152
+ }
153
+ if (this.tokens[this.pos].type === 'op' && this.tokens[this.pos].value === '+') {
154
+ this.pos++;
155
+ }
156
+ return this.parsePrimary();
157
+ }
158
+ parsePrimary() {
159
+ const token = this.tokens[this.pos];
160
+ // Number literal
161
+ if (token.type === 'number') {
162
+ this.pos++;
163
+ return token.numValue;
164
+ }
165
+ // Identifier (variable or function call)
166
+ if (token.type === 'ident') {
167
+ this.pos++;
168
+ // Check if it's a function call: IDENT '(' args ')'
169
+ if (this.pos < this.tokens.length && this.tokens[this.pos].type === 'lparen') {
170
+ const func = this.funcs[token.value];
171
+ if (!func)
172
+ throw new Error(`Unknown function: ${token.value}`);
173
+ this.pos++; // skip (
174
+ const args = [];
175
+ if (this.tokens[this.pos].type !== 'rparen') {
176
+ args.push(this.parseAddSub());
177
+ while (this.tokens[this.pos].type === 'comma') {
178
+ this.pos++; // skip ,
179
+ args.push(this.parseAddSub());
180
+ }
181
+ }
182
+ if (this.tokens[this.pos].type !== 'rparen') {
183
+ throw new Error('Expected closing parenthesis');
184
+ }
185
+ this.pos++; // skip )
186
+ return func(...args);
187
+ }
188
+ // Variable lookup
189
+ const val = this.vars[token.value];
190
+ if (val === undefined) {
191
+ throw new Error(`Unknown variable: ${token.value}`);
192
+ }
193
+ return val;
194
+ }
195
+ // Parenthesized expression
196
+ if (token.type === 'lparen') {
197
+ this.pos++; // skip (
198
+ const result = this.parseAddSub();
199
+ if (this.tokens[this.pos].type !== 'rparen') {
200
+ throw new Error('Expected closing parenthesis');
201
+ }
202
+ this.pos++; // skip )
203
+ return result;
204
+ }
205
+ throw new Error(`Unexpected token: ${token.value}`);
206
+ }
207
+ }
208
+ /**
209
+ * Safely compute a math expression with named variables.
210
+ *
211
+ * Uses a recursive descent parser. No JavaScript code execution.
212
+ * Only supports: numbers, variables, +, -, *, /, %, parentheses,
213
+ * and built-in math functions (min, max, ceil, floor, round, abs, sqrt, log, pow).
214
+ */
215
+ function computeExpression(expression, vars) {
216
+ const tokens = tokenize(expression);
217
+ const parser = new ExprParser(tokens, vars);
218
+ return parser.parse();
219
+ }
220
+ // ─── Billable Metrics Engine ─────────────────────────────────────────────────
221
+ class BillableMetricEngine {
222
+ metrics = [];
223
+ stats = {
224
+ totalEvaluations: 0,
225
+ successfulEvals: 0,
226
+ fallbackEvals: 0,
227
+ totalCreditsComputed: 0,
228
+ byMetric: {},
229
+ byTool: {},
230
+ };
231
+ constructor(metrics) {
232
+ if (metrics)
233
+ this.metrics = [...metrics];
234
+ }
235
+ /** Get all metrics. */
236
+ getMetrics() { return [...this.metrics]; }
237
+ /** Add or update a metric. */
238
+ upsertMetric(metric) {
239
+ // Validate expression syntax by tokenizing
240
+ try {
241
+ tokenize(metric.expression);
242
+ }
243
+ catch (err) {
244
+ throw new Error(`Invalid expression: ${err}`);
245
+ }
246
+ const idx = this.metrics.findIndex(m => m.id === metric.id);
247
+ if (idx >= 0) {
248
+ this.metrics[idx] = metric;
249
+ }
250
+ else {
251
+ this.metrics.push(metric);
252
+ }
253
+ return metric;
254
+ }
255
+ /** Remove a metric by ID. */
256
+ removeMetric(id) {
257
+ const idx = this.metrics.findIndex(m => m.id === id);
258
+ if (idx < 0)
259
+ return false;
260
+ this.metrics.splice(idx, 1);
261
+ return true;
262
+ }
263
+ /**
264
+ * Find the matching metric for a tool.
265
+ * Returns the first active metric whose tool list matches.
266
+ */
267
+ findMetric(tool) {
268
+ for (const metric of this.metrics) {
269
+ if (!metric.active)
270
+ continue;
271
+ if (metric.tools.length === 0 || metric.tools.includes(tool)) {
272
+ return metric;
273
+ }
274
+ }
275
+ return null;
276
+ }
277
+ /**
278
+ * Compute cost for a tool call using billable metric expressions.
279
+ *
280
+ * @param context - Context with args, response, timing data
281
+ * @returns Result with computed cost, or null if no metric matches
282
+ */
283
+ computeCost(context) {
284
+ const metric = this.findMetric(context.tool);
285
+ if (!metric)
286
+ return null;
287
+ this.stats.totalEvaluations++;
288
+ this.stats.byMetric[metric.id] = (this.stats.byMetric[metric.id] ?? 0) + 1;
289
+ this.stats.byTool[context.tool] = (this.stats.byTool[context.tool] ?? 0) + 1;
290
+ // Build variable map from context
291
+ const vars = {
292
+ // Built-in variables
293
+ input_size_bytes: context.inputSizeBytes ?? 0,
294
+ input_size_kb: (context.inputSizeBytes ?? 0) / 1024,
295
+ response_size_bytes: context.responseSizeBytes ?? 0,
296
+ response_size_kb: (context.responseSizeBytes ?? 0) / 1024,
297
+ duration_ms: context.durationMs ?? 0,
298
+ duration_s: (context.durationMs ?? 0) / 1000,
299
+ // Inject custom variables
300
+ ...(context.customVars ?? {}),
301
+ };
302
+ // Extract numeric values from input args (flatten one level)
303
+ if (context.inputArgs) {
304
+ for (const [key, value] of Object.entries(context.inputArgs)) {
305
+ if (typeof value === 'number') {
306
+ vars[key] = value;
307
+ }
308
+ else if (typeof value === 'string') {
309
+ vars[`${key}_length`] = value.length;
310
+ }
311
+ else if (typeof value === 'boolean') {
312
+ vars[key] = value ? 1 : 0;
313
+ }
314
+ }
315
+ }
316
+ try {
317
+ let cost = computeExpression(metric.expression, vars);
318
+ // Apply floor/ceiling
319
+ if (metric.minCost !== undefined)
320
+ cost = Math.max(metric.minCost, cost);
321
+ if (metric.maxCost !== undefined)
322
+ cost = Math.min(metric.maxCost, cost);
323
+ // Round to nearest integer (credits are whole numbers)
324
+ cost = Math.round(cost);
325
+ if (cost < 0)
326
+ cost = 0;
327
+ this.stats.successfulEvals++;
328
+ this.stats.totalCreditsComputed += cost;
329
+ return {
330
+ cost,
331
+ metricId: metric.id,
332
+ usedFallback: false,
333
+ resolvedVars: vars,
334
+ };
335
+ }
336
+ catch (err) {
337
+ // Expression failed — use fallback
338
+ const fallback = metric.fallbackCost ?? 1;
339
+ this.stats.fallbackEvals++;
340
+ this.stats.totalCreditsComputed += fallback;
341
+ return {
342
+ cost: fallback,
343
+ metricId: metric.id,
344
+ usedFallback: true,
345
+ error: String(err),
346
+ resolvedVars: vars,
347
+ };
348
+ }
349
+ }
350
+ /** Get statistics. */
351
+ getStats() {
352
+ return { ...this.stats };
353
+ }
354
+ /** Reset stats. */
355
+ resetStats() {
356
+ this.stats = {
357
+ totalEvaluations: 0,
358
+ successfulEvals: 0,
359
+ fallbackEvals: 0,
360
+ totalCreditsComputed: 0,
361
+ byMetric: {},
362
+ byTool: {},
363
+ };
364
+ }
365
+ /** Export metrics for backup/serialization. */
366
+ exportMetrics() {
367
+ return JSON.parse(JSON.stringify(this.metrics));
368
+ }
369
+ /** Import metrics. */
370
+ importMetrics(metrics, mode = 'merge') {
371
+ if (mode === 'replace') {
372
+ this.metrics = [];
373
+ }
374
+ let imported = 0;
375
+ for (const m of metrics) {
376
+ this.upsertMetric(m);
377
+ imported++;
378
+ }
379
+ return imported;
380
+ }
381
+ /** Destroy. */
382
+ destroy() {
383
+ this.metrics = [];
384
+ }
385
+ }
386
+ exports.BillableMetricEngine = BillableMetricEngine;
387
+ //# sourceMappingURL=billable-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billable-metrics.js","sourceRoot":"","sources":["../src/billable-metrics.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA2OH;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B9C,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA4OH;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B9C,CAAC"}
package/dist/cli.js CHANGED
@@ -53,6 +53,7 @@ function printUsage() {
53
53
  paygate-mcp wrap --server <command> [options] # stdio transport
54
54
  paygate-mcp wrap --remote-url <url> [options] # Streamable HTTP transport
55
55
  paygate-mcp wrap --config <path> [options] # load from config file
56
+ paygate-mcp wrap-api --openapi <spec.json> [opts] # wrap REST API as MCP tools
56
57
  paygate-mcp init [--output <path>] [--force] # interactive setup wizard
57
58
  paygate-mcp validate --config <path> # validate config without starting
58
59
  paygate-mcp completions <bash|zsh|fish> # generate shell completions
@@ -569,6 +570,122 @@ async function main() {
569
570
  }
570
571
  break;
571
572
  }
573
+ case 'wrap-api': {
574
+ // ─── wrap-api: Convert OpenAPI spec → gated MCP tools ───────────────
575
+ const specPath = flags['openapi'] || flags['spec'];
576
+ if (!specPath) {
577
+ console.error('Error: --openapi <path-or-url> is required for wrap-api.\n');
578
+ console.log(' Usage: paygate-mcp wrap-api --openapi <spec.json> [--base-url <url>] [options]');
579
+ console.log('');
580
+ console.log(' Wraps any REST API described by an OpenAPI 3.x spec as gated MCP tools.');
581
+ console.log(' All standard PayGate options (--port, --price, --rate-limit, etc.) apply.');
582
+ console.log('');
583
+ console.log(' Options:');
584
+ console.log(' --openapi <path> Path to OpenAPI 3.x spec (JSON)');
585
+ console.log(' --base-url <url> Override base URL for API calls');
586
+ console.log(' --prefix <s> Prefix for tool names (e.g. "api_")');
587
+ console.log(' --tag-filter <s> Only include operations with this tag');
588
+ console.log('');
589
+ process.exit(1);
590
+ }
591
+ let specJson;
592
+ try {
593
+ specJson = (0, fs_1.readFileSync)(specPath, 'utf-8');
594
+ // Validate it's parseable JSON
595
+ JSON.parse(specJson);
596
+ }
597
+ catch (err) {
598
+ console.error(`Error reading OpenAPI spec: ${err.message}`);
599
+ process.exit(1);
600
+ }
601
+ const apiBaseUrl = flags['base-url'] || undefined;
602
+ const apiPrefix = flags['prefix'] || undefined;
603
+ const apiTagFilter = flags['tag-filter'] || undefined;
604
+ const apiPortFlag = flags['port'] || env('PAYGATE_PORT');
605
+ const apiPriceFlag = flags['price'] || env('PAYGATE_PRICE');
606
+ const apiRateLimitFlag = flags['rate-limit'] || env('PAYGATE_RATE_LIMIT');
607
+ const apiShadowFlag = ('shadow' in flags) || env('PAYGATE_SHADOW') === 'true';
608
+ const apiAdminKeyFlag = flags['admin-key'] || env('PAYGATE_ADMIN_KEY');
609
+ const apiStateFileFlag = flags['state-file'] || env('PAYGATE_STATE_FILE');
610
+ const apiLogLevelFlag = flags['log-level'] || env('PAYGATE_LOG_LEVEL');
611
+ const apiLogFormatFlag = flags['log-format'] || env('PAYGATE_LOG_FORMAT');
612
+ const apiToolPriceFlag = flags['tool-price'] || env('PAYGATE_TOOL_PRICE');
613
+ const apiRedisUrlFlag = flags['redis-url'] || env('PAYGATE_REDIS_URL');
614
+ const apiPort = parseInt(apiPortFlag || '3402', 10);
615
+ const apiPrice = parseInt(apiPriceFlag || '1', 10);
616
+ const apiRateLimit = parseInt(apiRateLimitFlag || '60', 10);
617
+ // Build a dummy serverCommand since PayGateServer requires it
618
+ const config = {
619
+ serverCommand: '__openapi__',
620
+ serverArgs: [],
621
+ port: apiPort,
622
+ defaultCreditsPerCall: apiPrice,
623
+ globalRateLimitPerMin: apiRateLimit,
624
+ shadowMode: !!apiShadowFlag,
625
+ openApiSpec: specJson,
626
+ openApiBaseUrl: apiBaseUrl,
627
+ logLevel: apiLogLevelFlag || 'info',
628
+ logFormat: apiLogFormatFlag || 'text',
629
+ name: 'PayGate MCP (OpenAPI)',
630
+ toolPricing: apiToolPriceFlag ? parseToolPricing(apiToolPriceFlag) : {},
631
+ };
632
+ const apiServer = new server_1.PayGateServer(config, apiAdminKeyFlag, apiStateFileFlag, undefined, // remoteUrl
633
+ undefined, // stripeSecret
634
+ undefined, // servers
635
+ apiRedisUrlFlag);
636
+ // Handle graceful shutdown
637
+ let apiShuttingDown = false;
638
+ const apiShutdown = async (reason) => {
639
+ if (apiShuttingDown)
640
+ return;
641
+ apiShuttingDown = true;
642
+ console.log(`\nGraceful shutdown initiated${reason ? ` (${reason})` : ''}…`);
643
+ await apiServer.gracefulStop(30_000);
644
+ process.exit(reason ? 1 : 0);
645
+ };
646
+ process.on('SIGINT', () => apiShutdown());
647
+ process.on('SIGTERM', () => apiShutdown());
648
+ try {
649
+ const result = await apiServer.start();
650
+ // Get tool count from the OpenAPI backend
651
+ const handler = apiServer.handler;
652
+ let toolCount = 0;
653
+ try {
654
+ const toolsResp = await handler.handleRequest({ jsonrpc: '2.0', id: 'init', method: 'tools/list', params: {} }, null);
655
+ toolCount = (toolsResp?.result?.tools || []).length;
656
+ }
657
+ catch { /* ignore */ }
658
+ console.log(`
659
+ ╔══════════════════════════════════════════════════╗
660
+ ║ PayGate MCP — OpenAPI Wrapped ║
661
+ ╠══════════════════════════════════════════════════╣
662
+ ║ ║
663
+ ║ Endpoint: http://localhost:${String(result.port).padEnd(5)} ║
664
+ ║ Admin Key: ${result.adminKey.slice(0, 20)}... ║
665
+ ║ Backend: OpenAPI (${String(toolCount).padEnd(3)} tools) ║
666
+ ║ Source: ${specPath.slice(0, 35).padEnd(35)}║
667
+ ║ ║
668
+ ║ Pricing: ${String(apiPrice).padEnd(3)} credit(s) per tool call ║
669
+ ║ Rate Limit: ${String(apiRateLimit).padEnd(3)} calls/min per key ║
670
+ ║ Shadow: ${String(!!apiShadowFlag).padEnd(5)} ║
671
+ ║ ║
672
+ ╚══════════════════════════════════════════════════╝
673
+ `);
674
+ console.log(` Admin key (save this): ${result.adminKey}\n`);
675
+ // Dry run
676
+ const isDryRun = flags['dry-run'] === 'true' || 'dry-run' in flags;
677
+ if (isDryRun) {
678
+ console.log(` Discovered ${toolCount} tool(s) from OpenAPI spec. Dry run complete.\n`);
679
+ await apiServer.stop();
680
+ process.exit(0);
681
+ }
682
+ }
683
+ catch (error) {
684
+ console.error('Failed to start server:', error);
685
+ process.exit(1);
686
+ }
687
+ break;
688
+ }
572
689
  case 'help':
573
690
  case '--help':
574
691
  case '-h':