paygate-mcp 0.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/dist/cli.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PayGate MCP — CLI entry point.
4
+ *
5
+ * Usage:
6
+ * npx paygate-mcp wrap --server "npx my-mcp-server" --port 3402
7
+ * npx paygate-mcp wrap --server "python server.py" --price 2 --rate-limit 30
8
+ * npx paygate-mcp keys create --name "my-client" --credits 500
9
+ * npx paygate-mcp status
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
package/dist/cli.js ADDED
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * PayGate MCP — CLI entry point.
5
+ *
6
+ * Usage:
7
+ * npx paygate-mcp wrap --server "npx my-mcp-server" --port 3402
8
+ * npx paygate-mcp wrap --server "python server.py" --price 2 --rate-limit 30
9
+ * npx paygate-mcp keys create --name "my-client" --credits 500
10
+ * npx paygate-mcp status
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const server_1 = require("./server");
14
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
15
+ function parseArgs(argv) {
16
+ const command = argv[2] || 'help';
17
+ const flags = {};
18
+ for (let i = 3; i < argv.length; i++) {
19
+ const arg = argv[i];
20
+ if (arg.startsWith('--')) {
21
+ const key = arg.slice(2);
22
+ const next = argv[i + 1];
23
+ if (next && !next.startsWith('--')) {
24
+ flags[key] = next;
25
+ i++;
26
+ }
27
+ else {
28
+ flags[key] = 'true';
29
+ }
30
+ }
31
+ }
32
+ return { command, flags };
33
+ }
34
+ function printUsage() {
35
+ console.log(`
36
+ paygate-mcp — Monetize any MCP server with one command.
37
+
38
+ USAGE:
39
+ paygate-mcp wrap --server <command> [options]
40
+
41
+ OPTIONS:
42
+ --server <cmd> MCP server command to wrap (required)
43
+ e.g. "npx @modelcontextprotocol/server-filesystem /"
44
+ --port <n> HTTP port (default: 3402)
45
+ --price <n> Default credits per tool call (default: 1)
46
+ --rate-limit <n> Max calls/min per key (default: 60, 0=unlimited)
47
+ --name <s> Server display name (default: "PayGate MCP Server")
48
+ --shadow Shadow mode — log but don't enforce payment
49
+ --admin-key <s> Set admin key (default: auto-generated)
50
+ --tool-price <t:n> Per-tool price override (e.g. "search:5,generate:10")
51
+ --import-key <k:c> Import an existing API key with credits (e.g. "pg_abc123:100")
52
+
53
+ EXAMPLES:
54
+ # Wrap a filesystem MCP server
55
+ paygate-mcp wrap --server "npx @modelcontextprotocol/server-filesystem /tmp"
56
+
57
+ # Custom pricing and rate limit
58
+ paygate-mcp wrap --server "python my-server.py" --price 2 --rate-limit 30
59
+
60
+ # Shadow mode (observe without enforcing)
61
+ paygate-mcp wrap --server "node server.js" --shadow
62
+
63
+ # Per-tool pricing
64
+ paygate-mcp wrap --server "node server.js" --tool-price "search:5,generate:10"
65
+ `);
66
+ }
67
+ function parseToolPricing(input) {
68
+ const pricing = {};
69
+ const pairs = input.split(',');
70
+ for (const pair of pairs) {
71
+ const [tool, priceStr] = pair.split(':');
72
+ if (tool && priceStr) {
73
+ pricing[tool.trim()] = { creditsPerCall: parseInt(priceStr.trim(), 10) };
74
+ }
75
+ }
76
+ return pricing;
77
+ }
78
+ // ─── Main ────────────────────────────────────────────────────────────────────
79
+ async function main() {
80
+ const { command, flags } = parseArgs(process.argv);
81
+ switch (command) {
82
+ case 'wrap': {
83
+ const serverCmd = flags['server'];
84
+ if (!serverCmd) {
85
+ console.error('Error: --server is required.\n');
86
+ printUsage();
87
+ process.exit(1);
88
+ }
89
+ // Parse server command into command + args
90
+ const parts = serverCmd.split(/\s+/);
91
+ const serverCommand = parts[0];
92
+ const serverArgs = parts.slice(1);
93
+ const port = parseInt(flags['port'] || '3402', 10);
94
+ const price = parseInt(flags['price'] || '1', 10);
95
+ const rateLimit = parseInt(flags['rate-limit'] || '60', 10);
96
+ const name = flags['name'] || 'PayGate MCP Server';
97
+ const shadowMode = flags['shadow'] === 'true' || flags['shadow'] === undefined && 'shadow' in flags;
98
+ const adminKey = flags['admin-key'];
99
+ const toolPricing = flags['tool-price'] ? parseToolPricing(flags['tool-price']) : {};
100
+ const server = new server_1.PayGateServer({
101
+ serverCommand,
102
+ serverArgs,
103
+ port,
104
+ defaultCreditsPerCall: price,
105
+ globalRateLimitPerMin: rateLimit,
106
+ name,
107
+ shadowMode: !!shadowMode,
108
+ toolPricing,
109
+ }, adminKey);
110
+ // Import keys if specified
111
+ if (flags['import-key']) {
112
+ const pairs = flags['import-key'].split(',');
113
+ for (const pair of pairs) {
114
+ const [key, creditsStr] = pair.split(':');
115
+ if (key && creditsStr) {
116
+ server.gate.store.importKey(key.trim(), 'imported', parseInt(creditsStr.trim(), 10));
117
+ }
118
+ }
119
+ }
120
+ // Handle graceful shutdown
121
+ const shutdown = async () => {
122
+ console.log('\nShutting down...');
123
+ await server.stop();
124
+ process.exit(0);
125
+ };
126
+ process.on('SIGINT', shutdown);
127
+ process.on('SIGTERM', shutdown);
128
+ try {
129
+ const result = await server.start();
130
+ console.log(`
131
+ ╔══════════════════════════════════════════════════╗
132
+ ║ PayGate MCP — Server Running ║
133
+ ╠══════════════════════════════════════════════════╣
134
+ ║ ║
135
+ ║ Endpoint: http://localhost:${String(result.port).padEnd(5)} ║
136
+ ║ Admin Key: ${result.adminKey.slice(0, 20)}... ║
137
+ ║ Wrapping: ${serverCmd.slice(0, 35).padEnd(35)}║
138
+ ║ ║
139
+ ║ Pricing: ${String(price).padEnd(3)} credit(s) per tool call ║
140
+ ║ Rate Limit: ${String(rateLimit).padEnd(3)} calls/min per key ║
141
+ ║ Shadow: ${String(!!shadowMode).padEnd(5)} ║
142
+ ║ ║
143
+ ╠══════════════════════════════════════════════════╣
144
+ ║ POST /mcp — JSON-RPC (X-API-Key header) ║
145
+ ║ GET /status — Dashboard (X-Admin-Key header) ║
146
+ ║ POST /keys — Create key (X-Admin-Key header) ║
147
+ ║ POST /topup — Add credits (X-Admin-Key header)║
148
+ ╚══════════════════════════════════════════════════╝
149
+ `);
150
+ console.log(` Admin key (save this): ${result.adminKey}\n`);
151
+ }
152
+ catch (error) {
153
+ console.error('Failed to start server:', error);
154
+ process.exit(1);
155
+ }
156
+ break;
157
+ }
158
+ case 'help':
159
+ case '--help':
160
+ case '-h':
161
+ printUsage();
162
+ break;
163
+ case 'version':
164
+ case '--version':
165
+ case '-v':
166
+ console.log('paygate-mcp v0.1.0');
167
+ break;
168
+ default:
169
+ console.error(`Unknown command: ${command}\n`);
170
+ printUsage();
171
+ process.exit(1);
172
+ }
173
+ }
174
+ main().catch((error) => {
175
+ console.error('Fatal error:', error);
176
+ process.exit(1);
177
+ });
178
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Gate — The core decision engine.
3
+ *
4
+ * Evaluates whether a tool call should be allowed based on:
5
+ * 1. API key validity
6
+ * 2. Credit balance
7
+ * 3. Rate limit
8
+ *
9
+ * Fail-closed: any check failure => DENY.
10
+ * Shadow mode: log but don't enforce (always ALLOW).
11
+ */
12
+ import { PayGateConfig, GateDecision, ToolCallParams } from './types';
13
+ import { KeyStore } from './store';
14
+ import { RateLimiter } from './rate-limiter';
15
+ import { UsageMeter } from './meter';
16
+ export declare class Gate {
17
+ readonly store: KeyStore;
18
+ readonly rateLimiter: RateLimiter;
19
+ readonly meter: UsageMeter;
20
+ private readonly config;
21
+ constructor(config: PayGateConfig);
22
+ /**
23
+ * Evaluate a tool call request.
24
+ */
25
+ evaluate(apiKey: string | null, toolCall: ToolCallParams): GateDecision;
26
+ /**
27
+ * Check if a method is free (no auth required).
28
+ */
29
+ isFreeMethod(method: string): boolean;
30
+ /**
31
+ * Get price for a tool in credits.
32
+ */
33
+ getToolPrice(toolName: string): number;
34
+ /**
35
+ * Get full status for dashboard.
36
+ */
37
+ getStatus(): {
38
+ name: string;
39
+ shadowMode: boolean;
40
+ activeKeys: number;
41
+ keys: (Omit<import("./types").ApiKeyRecord, "key"> & {
42
+ keyPrefix: string;
43
+ })[];
44
+ usage: import("./types").UsageSummary;
45
+ eventCount: number;
46
+ config: {
47
+ defaultCreditsPerCall: number;
48
+ globalRateLimitPerMin: number;
49
+ toolPricing: Record<string, import("./types").ToolPricing>;
50
+ };
51
+ };
52
+ destroy(): void;
53
+ private recordEvent;
54
+ }
55
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAc,cAAc,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,qBAAa,IAAI;IACf,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,MAAM,EAAE,aAAa;IAOjC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,YAAY;IAwDvE;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAMtC;;OAEG;IACH,SAAS;;;;;;;;;;;;;;;IAgBT,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,WAAW;CAcpB"}
package/dist/gate.js ADDED
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ /**
3
+ * Gate — The core decision engine.
4
+ *
5
+ * Evaluates whether a tool call should be allowed based on:
6
+ * 1. API key validity
7
+ * 2. Credit balance
8
+ * 3. Rate limit
9
+ *
10
+ * Fail-closed: any check failure => DENY.
11
+ * Shadow mode: log but don't enforce (always ALLOW).
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.Gate = void 0;
15
+ const store_1 = require("./store");
16
+ const rate_limiter_1 = require("./rate-limiter");
17
+ const meter_1 = require("./meter");
18
+ class Gate {
19
+ store;
20
+ rateLimiter;
21
+ meter;
22
+ config;
23
+ constructor(config) {
24
+ this.config = config;
25
+ this.store = new store_1.KeyStore();
26
+ this.rateLimiter = new rate_limiter_1.RateLimiter(config.globalRateLimitPerMin);
27
+ this.meter = new meter_1.UsageMeter();
28
+ }
29
+ /**
30
+ * Evaluate a tool call request.
31
+ */
32
+ evaluate(apiKey, toolCall) {
33
+ const toolName = toolCall.name;
34
+ const creditsRequired = this.getToolPrice(toolName);
35
+ // Step 1: API key present?
36
+ if (!apiKey) {
37
+ this.recordEvent(apiKey || 'none', '', toolName, 0, false, 'missing_api_key');
38
+ if (this.config.shadowMode) {
39
+ return { allowed: true, reason: 'shadow:missing_api_key', creditsCharged: 0, remainingCredits: 0 };
40
+ }
41
+ return { allowed: false, reason: 'missing_api_key', creditsCharged: 0, remainingCredits: 0 };
42
+ }
43
+ // Step 2: Valid key?
44
+ const keyRecord = this.store.getKey(apiKey);
45
+ if (!keyRecord) {
46
+ this.recordEvent(apiKey, 'unknown', toolName, 0, false, 'invalid_api_key');
47
+ if (this.config.shadowMode) {
48
+ return { allowed: true, reason: 'shadow:invalid_api_key', creditsCharged: 0, remainingCredits: 0 };
49
+ }
50
+ return { allowed: false, reason: 'invalid_api_key', creditsCharged: 0, remainingCredits: 0 };
51
+ }
52
+ // Step 3: Rate limit?
53
+ const rateResult = this.rateLimiter.check(apiKey);
54
+ if (!rateResult.allowed) {
55
+ this.recordEvent(apiKey, keyRecord.name, toolName, 0, false, rateResult.reason);
56
+ if (this.config.shadowMode) {
57
+ return { allowed: true, reason: `shadow:${rateResult.reason}`, creditsCharged: 0, remainingCredits: keyRecord.credits };
58
+ }
59
+ return { allowed: false, reason: rateResult.reason, creditsCharged: 0, remainingCredits: keyRecord.credits };
60
+ }
61
+ // Step 4: Sufficient credits?
62
+ if (!this.store.hasCredits(apiKey, creditsRequired)) {
63
+ this.recordEvent(apiKey, keyRecord.name, toolName, 0, false, 'insufficient_credits');
64
+ if (this.config.shadowMode) {
65
+ return { allowed: true, reason: 'shadow:insufficient_credits', creditsCharged: 0, remainingCredits: keyRecord.credits };
66
+ }
67
+ return {
68
+ allowed: false,
69
+ reason: `insufficient_credits: need ${creditsRequired}, have ${keyRecord.credits}`,
70
+ creditsCharged: 0,
71
+ remainingCredits: keyRecord.credits,
72
+ };
73
+ }
74
+ // Step 5: ALLOW — deduct credits and record
75
+ this.store.deductCredits(apiKey, creditsRequired);
76
+ this.rateLimiter.record(apiKey);
77
+ const remaining = this.store.getKey(apiKey)?.credits ?? 0;
78
+ this.recordEvent(apiKey, keyRecord.name, toolName, creditsRequired, true);
79
+ return { allowed: true, creditsCharged: creditsRequired, remainingCredits: remaining };
80
+ }
81
+ /**
82
+ * Check if a method is free (no auth required).
83
+ */
84
+ isFreeMethod(method) {
85
+ return this.config.freeMethods.includes(method);
86
+ }
87
+ /**
88
+ * Get price for a tool in credits.
89
+ */
90
+ getToolPrice(toolName) {
91
+ const override = this.config.toolPricing[toolName];
92
+ if (override)
93
+ return override.creditsPerCall;
94
+ return this.config.defaultCreditsPerCall;
95
+ }
96
+ /**
97
+ * Get full status for dashboard.
98
+ */
99
+ getStatus() {
100
+ return {
101
+ name: this.config.name,
102
+ shadowMode: this.config.shadowMode,
103
+ activeKeys: this.store.activeKeyCount,
104
+ keys: this.store.listKeys(),
105
+ usage: this.meter.getSummary(),
106
+ eventCount: this.meter.eventCount,
107
+ config: {
108
+ defaultCreditsPerCall: this.config.defaultCreditsPerCall,
109
+ globalRateLimitPerMin: this.config.globalRateLimitPerMin,
110
+ toolPricing: this.config.toolPricing,
111
+ },
112
+ };
113
+ }
114
+ destroy() {
115
+ this.rateLimiter.destroy();
116
+ }
117
+ recordEvent(apiKey, keyName, tool, creditsCharged, allowed, denyReason) {
118
+ this.meter.record({
119
+ timestamp: new Date().toISOString(),
120
+ apiKey: apiKey.slice(0, 10),
121
+ keyName,
122
+ tool,
123
+ creditsCharged,
124
+ allowed,
125
+ denyReason,
126
+ });
127
+ }
128
+ }
129
+ exports.Gate = Gate;
130
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAGH,mCAAmC;AACnC,iDAA6C;AAC7C,mCAAqC;AAErC,MAAa,IAAI;IACN,KAAK,CAAW;IAChB,WAAW,CAAc;IACzB,KAAK,CAAa;IACV,MAAM,CAAgB;IAEvC,YAAY,MAAqB;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,IAAI,gBAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,IAAI,0BAAW,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACjE,IAAI,CAAC,KAAK,GAAG,IAAI,kBAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,MAAqB,EAAE,QAAwB;QACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC/B,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAEpD,2BAA2B;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;YAC9E,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;YACrG,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;QAC/F,CAAC;QAED,qBAAqB;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;YAC3E,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;YACrG,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;QAC/F,CAAC;QAED,sBAAsB;QACtB,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YAChF,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,UAAU,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;YAC1H,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;QAC/G,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;YACrF,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,6BAA6B,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;YAC1H,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,8BAA8B,eAAe,UAAU,SAAS,CAAC,OAAO,EAAE;gBAClF,cAAc,EAAE,CAAC;gBACjB,gBAAgB,EAAE,SAAS,CAAC,OAAO;aACpC,CAAC;QACJ,CAAC;QAED,4CAA4C;QAC5C,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;QAE1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;IACzF,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,MAAc;QACzB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAAgB;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,cAAc,CAAC;QAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;YAClC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc;YACrC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;YAC9B,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;YACjC,MAAM,EAAE;gBACN,qBAAqB,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB;gBACxD,qBAAqB,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB;gBACxD,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;aACrC;SACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAEO,WAAW,CACjB,MAAc,EAAE,OAAe,EAAE,IAAY,EAC7C,cAAsB,EAAE,OAAgB,EAAE,UAAmB;QAE7D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YAC3B,OAAO;YACP,IAAI;YACJ,cAAc;YACd,OAAO;YACP,UAAU;SACX,CAAC,CAAC;IACL,CAAC;CACF;AA7HD,oBA6HC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * PayGate MCP — Public API.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { PayGateServer } from 'paygate-mcp';
7
+ *
8
+ * const server = new PayGateServer({
9
+ * serverCommand: 'npx',
10
+ * serverArgs: ['@modelcontextprotocol/server-filesystem', '/tmp'],
11
+ * port: 3402,
12
+ * });
13
+ *
14
+ * const { port, adminKey } = await server.start();
15
+ * ```
16
+ */
17
+ export { PayGateServer } from './server';
18
+ export { Gate } from './gate';
19
+ export { McpProxy } from './proxy';
20
+ export { KeyStore } from './store';
21
+ export { UsageMeter } from './meter';
22
+ export { RateLimiter } from './rate-limiter';
23
+ export type { PayGateConfig, JsonRpcRequest, JsonRpcResponse, JsonRpcError, ToolCallParams, ToolInfo, ToolPricing, ApiKeyRecord, UsageEvent, UsageSummary, GateDecision, } from './types';
24
+ export { DEFAULT_CONFIG } from './types';
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * PayGate MCP — Public API.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { PayGateServer } from 'paygate-mcp';
8
+ *
9
+ * const server = new PayGateServer({
10
+ * serverCommand: 'npx',
11
+ * serverArgs: ['@modelcontextprotocol/server-filesystem', '/tmp'],
12
+ * port: 3402,
13
+ * });
14
+ *
15
+ * const { port, adminKey } = await server.start();
16
+ * ```
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.DEFAULT_CONFIG = exports.RateLimiter = exports.UsageMeter = exports.KeyStore = exports.McpProxy = exports.Gate = exports.PayGateServer = void 0;
20
+ var server_1 = require("./server");
21
+ Object.defineProperty(exports, "PayGateServer", { enumerable: true, get: function () { return server_1.PayGateServer; } });
22
+ var gate_1 = require("./gate");
23
+ Object.defineProperty(exports, "Gate", { enumerable: true, get: function () { return gate_1.Gate; } });
24
+ var proxy_1 = require("./proxy");
25
+ Object.defineProperty(exports, "McpProxy", { enumerable: true, get: function () { return proxy_1.McpProxy; } });
26
+ var store_1 = require("./store");
27
+ Object.defineProperty(exports, "KeyStore", { enumerable: true, get: function () { return store_1.KeyStore; } });
28
+ var meter_1 = require("./meter");
29
+ Object.defineProperty(exports, "UsageMeter", { enumerable: true, get: function () { return meter_1.UsageMeter; } });
30
+ var rate_limiter_1 = require("./rate-limiter");
31
+ Object.defineProperty(exports, "RateLimiter", { enumerable: true, get: function () { return rate_limiter_1.RateLimiter; } });
32
+ var types_1 = require("./types");
33
+ Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return types_1.DEFAULT_CONFIG; } });
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,iCAAmC;AAA1B,iGAAA,QAAQ,OAAA;AACjB,iCAAqC;AAA5B,mGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AAgBpB,iCAAyC;AAAhC,uGAAA,cAAc,OAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * UsageMeter — Tracks all tool call events for billing and analytics.
3
+ */
4
+ import { UsageEvent, UsageSummary } from './types';
5
+ export declare class UsageMeter {
6
+ private events;
7
+ private readonly maxEvents;
8
+ constructor(maxEvents?: number);
9
+ record(event: UsageEvent): void;
10
+ getEvents(since?: string): UsageEvent[];
11
+ getSummary(since?: string): UsageSummary;
12
+ clear(): void;
13
+ get eventCount(): number;
14
+ }
15
+ //# sourceMappingURL=meter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../src/meter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEnD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,SAAS,SAAU;IAI/B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ/B,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAKvC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY;IAiDxC,KAAK,IAAI,IAAI;IAIb,IAAI,UAAU,IAAI,MAAM,CAEvB;CACF"}
package/dist/meter.js ADDED
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * UsageMeter — Tracks all tool call events for billing and analytics.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UsageMeter = void 0;
7
+ class UsageMeter {
8
+ events = [];
9
+ maxEvents;
10
+ constructor(maxEvents = 100_000) {
11
+ this.maxEvents = maxEvents;
12
+ }
13
+ record(event) {
14
+ this.events.push(event);
15
+ if (this.events.length > this.maxEvents) {
16
+ const dropCount = Math.floor(this.maxEvents * 0.25);
17
+ this.events = this.events.slice(dropCount);
18
+ }
19
+ }
20
+ getEvents(since) {
21
+ if (!since)
22
+ return [...this.events];
23
+ return this.events.filter(e => e.timestamp >= since);
24
+ }
25
+ getSummary(since) {
26
+ const events = this.getEvents(since);
27
+ const summary = {
28
+ totalCalls: 0,
29
+ totalCreditsSpent: 0,
30
+ totalDenied: 0,
31
+ perTool: {},
32
+ perKey: {},
33
+ denyReasons: {},
34
+ };
35
+ for (const event of events) {
36
+ summary.totalCalls++;
37
+ if (event.allowed) {
38
+ summary.totalCreditsSpent += event.creditsCharged;
39
+ }
40
+ else {
41
+ summary.totalDenied++;
42
+ if (event.denyReason) {
43
+ summary.denyReasons[event.denyReason] = (summary.denyReasons[event.denyReason] || 0) + 1;
44
+ }
45
+ }
46
+ // Per-tool
47
+ if (!summary.perTool[event.tool]) {
48
+ summary.perTool[event.tool] = { calls: 0, credits: 0, denied: 0 };
49
+ }
50
+ summary.perTool[event.tool].calls++;
51
+ if (event.allowed) {
52
+ summary.perTool[event.tool].credits += event.creditsCharged;
53
+ }
54
+ else {
55
+ summary.perTool[event.tool].denied++;
56
+ }
57
+ // Per-key
58
+ const keyLabel = event.keyName || event.apiKey.slice(0, 10);
59
+ if (!summary.perKey[keyLabel]) {
60
+ summary.perKey[keyLabel] = { calls: 0, credits: 0, denied: 0 };
61
+ }
62
+ summary.perKey[keyLabel].calls++;
63
+ if (event.allowed) {
64
+ summary.perKey[keyLabel].credits += event.creditsCharged;
65
+ }
66
+ else {
67
+ summary.perKey[keyLabel].denied++;
68
+ }
69
+ }
70
+ return summary;
71
+ }
72
+ clear() {
73
+ this.events = [];
74
+ }
75
+ get eventCount() {
76
+ return this.events.length;
77
+ }
78
+ }
79
+ exports.UsageMeter = UsageMeter;
80
+ //# sourceMappingURL=meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter.js","sourceRoot":"","sources":["../src/meter.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAIH,MAAa,UAAU;IACb,MAAM,GAAiB,EAAE,CAAC;IACjB,SAAS,CAAS;IAEnC,YAAY,SAAS,GAAG,OAAO;QAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,KAAiB;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;YACpD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAc;QACtB,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,UAAU,CAAC,KAAc;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,OAAO,GAAiB;YAC5B,UAAU,EAAE,CAAC;YACb,iBAAiB,EAAE,CAAC;YACpB,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,EAAE;SAChB,CAAC;QAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,UAAU,EAAE,CAAC;YACrB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,CAAC,iBAAiB,IAAI,KAAK,CAAC,cAAc,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,WAAW,EAAE,CAAC;gBACtB,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;oBACrB,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC3F,CAAC;YACH,CAAC;YAED,WAAW;YACX,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACpE,CAAC;YACD,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,cAAc,CAAC;YAC9D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACvC,CAAC;YAED,UAAU;YACV,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACjE,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,cAAc,CAAC;YAC3D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;YACpC,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF;AA7ED,gCA6EC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * McpProxy — Spawns a wrapped MCP server (stdio) and proxies JSON-RPC
3
+ * through the PayGate for tool-call gating.
4
+ *
5
+ * Architecture:
6
+ * HTTP Client <--JSON-RPC over HTTP--> PayGate Proxy <--stdio--> Wrapped MCP Server
7
+ *
8
+ * Free methods (initialize, tools/list, ping, etc.) pass through without auth.
9
+ * tools/call requests are gated: API key + credits + rate limit.
10
+ */
11
+ import { EventEmitter } from 'events';
12
+ import { JsonRpcRequest, JsonRpcResponse } from './types';
13
+ import { Gate } from './gate';
14
+ export declare class McpProxy extends EventEmitter {
15
+ private process;
16
+ private readonly gate;
17
+ private readonly serverCommand;
18
+ private readonly serverArgs;
19
+ private pendingRequests;
20
+ private buffer;
21
+ private started;
22
+ constructor(gate: Gate, serverCommand: string, serverArgs: string[]);
23
+ /**
24
+ * Start the wrapped MCP server process.
25
+ */
26
+ start(): Promise<void>;
27
+ /**
28
+ * Handle an incoming JSON-RPC request from the client.
29
+ * Gates tools/call through the PayGate. Passes other methods through.
30
+ */
31
+ handleRequest(request: JsonRpcRequest, apiKey: string | null): Promise<JsonRpcResponse>;
32
+ /**
33
+ * Forward a JSON-RPC request to the wrapped server via stdio.
34
+ */
35
+ private forwardToServer;
36
+ /**
37
+ * Parse JSON-RPC responses from the server's stdout.
38
+ * Uses newline-delimited JSON.
39
+ */
40
+ private handleServerOutput;
41
+ /**
42
+ * Gracefully stop the wrapped server.
43
+ */
44
+ stop(): Promise<void>;
45
+ get isRunning(): boolean;
46
+ private errorResponse;
47
+ }
48
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,qBAAa,QAAS,SAAQ,YAAY;IACxC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAW;IACtC,OAAO,CAAC,eAAe,CAIlB;IACL,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IAOnE;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC5B;;;OAGG;IACG,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC;IAoD7F;;OAEG;IACH,OAAO,CAAC,eAAe;IAwCvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,aAAa;CAGtB"}