paygate-mcp 0.8.0 → 0.9.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 +96 -11
- package/dist/cli.js +40 -4
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +119 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +262 -0
- package/dist/client.js.map +1 -0
- package/dist/http-proxy.d.ts +5 -0
- package/dist/http-proxy.d.ts.map +1 -1
- package/dist/http-proxy.js +10 -0
- package/dist/http-proxy.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +5 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +10 -0
- package/dist/proxy.js.map +1 -1
- package/dist/router.d.ts +57 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +233 -0
- package/dist/router.js.map +1 -0
- package/dist/server.d.ts +9 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +20 -5
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
30
30
|
- **Credit Billing** — Each tool call costs credits (configurable per-tool)
|
|
31
31
|
- **Rate Limiting** — Sliding window per-key rate limits + per-tool rate limits
|
|
32
32
|
- **Usage Metering** — Track who called what, when, and how much they spent
|
|
33
|
+
- **Multi-Server Mode** — Wrap N MCP servers behind one PayGate with tool prefix routing
|
|
34
|
+
- **Client SDK** — `PayGateClient` with auto 402 retry, balance tracking, and typed errors
|
|
33
35
|
- **Two Transports** — Wrap local servers via stdio or remote servers via Streamable HTTP
|
|
34
36
|
- **Per-Tool ACL** — Whitelist/blacklist tools per API key (enterprise access control)
|
|
35
37
|
- **Per-Tool Rate Limits** — Independent rate limits per tool, not just global
|
|
@@ -88,6 +90,75 @@ The proxy handles:
|
|
|
88
90
|
|
|
89
91
|
When started, you'll see your admin key in the console. Save it.
|
|
90
92
|
|
|
93
|
+
### Multi-Server Mode
|
|
94
|
+
|
|
95
|
+
Wrap multiple MCP servers behind a single PayGate instance. Tools are prefixed with the server name:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npx paygate-mcp wrap --config multi-server.json
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Example `multi-server.json`:
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"port": 3402,
|
|
105
|
+
"defaultCreditsPerCall": 1,
|
|
106
|
+
"servers": [
|
|
107
|
+
{
|
|
108
|
+
"prefix": "fs",
|
|
109
|
+
"serverCommand": "npx",
|
|
110
|
+
"serverArgs": ["@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"prefix": "github",
|
|
114
|
+
"remoteUrl": "https://github-mcp.example.com/mcp"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Tools are exposed with prefixes: `fs:read_file`, `fs:write_file`, `github:search_repos`, etc. Pricing and ACLs work on the prefixed names:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"toolPricing": {
|
|
125
|
+
"github:search_repos": { "creditsPerCall": 5 },
|
|
126
|
+
"fs:read_file": { "creditsPerCall": 1 }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Credits are shared across all backends — one API key works for all servers.
|
|
132
|
+
|
|
133
|
+
### Client SDK
|
|
134
|
+
|
|
135
|
+
Use `PayGateClient` to call tools from TypeScript/Node.js with auto 402 retry:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { PayGateClient, PayGateError } from 'paygate-mcp/client';
|
|
139
|
+
|
|
140
|
+
const client = new PayGateClient({
|
|
141
|
+
url: 'http://localhost:3402',
|
|
142
|
+
apiKey: 'pg_abc123...',
|
|
143
|
+
autoRetry: true,
|
|
144
|
+
onCreditsNeeded: async (info) => {
|
|
145
|
+
// Called when credits run out — add credits and return true to retry
|
|
146
|
+
await topUpCredits(info.creditsRequired);
|
|
147
|
+
return true;
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const tools = await client.listTools();
|
|
152
|
+
const result = await client.callTool('search', { query: 'hello' });
|
|
153
|
+
const balance = await client.getBalance();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Features:
|
|
157
|
+
- **Auto 402 retry**: When a tool call returns payment-required, calls `onCreditsNeeded` and retries
|
|
158
|
+
- **Balance tracking**: `client.lastKnownBalance` tracks credits from `getBalance()` calls
|
|
159
|
+
- **Typed errors**: `PayGateError` with `.isPaymentRequired`, `.isRateLimited`, `.isExpired` helpers
|
|
160
|
+
- **Zero dependencies**: Uses Node.js built-in `http`/`https`
|
|
161
|
+
|
|
91
162
|
### Create API Keys
|
|
92
163
|
|
|
93
164
|
```bash
|
|
@@ -213,7 +284,7 @@ These MCP methods pass through without auth or billing:
|
|
|
213
284
|
--config <path> Load settings from a JSON config file
|
|
214
285
|
```
|
|
215
286
|
|
|
216
|
-
> **Note:** Use `--server` OR `--remote-url
|
|
287
|
+
> **Note:** Use `--server` OR `--remote-url` for single-server mode. Use `servers` in a config file for multi-server mode.
|
|
217
288
|
|
|
218
289
|
### Persistent Storage
|
|
219
290
|
|
|
@@ -397,7 +468,7 @@ CLI flags override config file values when both are specified.
|
|
|
397
468
|
## Programmatic API
|
|
398
469
|
|
|
399
470
|
```typescript
|
|
400
|
-
import { PayGateServer
|
|
471
|
+
import { PayGateServer } from 'paygate-mcp';
|
|
401
472
|
|
|
402
473
|
// Wrap a local server (stdio)
|
|
403
474
|
const server = new PayGateServer({
|
|
@@ -410,14 +481,28 @@ const server = new PayGateServer({
|
|
|
410
481
|
},
|
|
411
482
|
});
|
|
412
483
|
|
|
413
|
-
// Or gate a remote server (Streamable HTTP)
|
|
414
|
-
const remoteServer = new PayGateServer({
|
|
415
|
-
serverCommand: '',
|
|
416
|
-
port: 3402,
|
|
417
|
-
defaultCreditsPerCall: 5,
|
|
418
|
-
}, undefined, undefined, 'https://my-mcp-server.example.com/mcp');
|
|
419
|
-
|
|
420
484
|
const { port, adminKey } = await server.start();
|
|
485
|
+
|
|
486
|
+
// Multi-server mode
|
|
487
|
+
const multiServer = new PayGateServer(
|
|
488
|
+
{ serverCommand: '', port: 3402, defaultCreditsPerCall: 1 },
|
|
489
|
+
undefined, undefined, undefined, undefined,
|
|
490
|
+
[
|
|
491
|
+
{ prefix: 'fs', serverCommand: 'npx', serverArgs: ['@modelcontextprotocol/server-filesystem', '/tmp'] },
|
|
492
|
+
{ prefix: 'api', remoteUrl: 'https://my-mcp-server.example.com/mcp' },
|
|
493
|
+
]
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// Client SDK
|
|
497
|
+
import { PayGateClient } from 'paygate-mcp/client';
|
|
498
|
+
|
|
499
|
+
const client = new PayGateClient({
|
|
500
|
+
url: `http://localhost:${port}`,
|
|
501
|
+
apiKey: 'pg_...',
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
const tools = await client.listTools();
|
|
505
|
+
const result = await client.callTool('search', { query: 'hello' });
|
|
421
506
|
```
|
|
422
507
|
|
|
423
508
|
## Security
|
|
@@ -458,8 +543,8 @@ const { port, adminKey } = await server.start();
|
|
|
458
543
|
- [x] Per-tool ACL — whitelist/blacklist tools per key
|
|
459
544
|
- [x] Per-tool rate limits — independent limits per tool
|
|
460
545
|
- [x] Key expiry (TTL) — auto-expire API keys
|
|
461
|
-
- [
|
|
462
|
-
- [
|
|
546
|
+
- [x] Multi-server mode — wrap N MCP servers behind one PayGate
|
|
547
|
+
- [x] Client SDK — `PayGateClient` with auto 402 retry
|
|
463
548
|
- [ ] OAuth 2.1 — MCP spec mandates it for production
|
|
464
549
|
|
|
465
550
|
## Requirements
|
package/dist/cli.js
CHANGED
|
@@ -76,6 +76,14 @@ function printUsage() {
|
|
|
76
76
|
# Gate a remote MCP server (Streamable HTTP transport)
|
|
77
77
|
paygate-mcp wrap --remote-url "https://my-server.example.com/mcp" --price 5
|
|
78
78
|
|
|
79
|
+
# Multi-server mode: wrap N servers behind one PayGate
|
|
80
|
+
paygate-mcp wrap --config multi-server.json
|
|
81
|
+
# Config file: { "servers": [
|
|
82
|
+
# { "prefix": "fs", "serverCommand": "npx", "serverArgs": ["@mcp/server-filesystem", "/tmp"] },
|
|
83
|
+
# { "prefix": "gh", "remoteUrl": "https://github-mcp.example.com/mcp" }
|
|
84
|
+
# ]}
|
|
85
|
+
# Tools become: "fs:read_file", "gh:search_repos", etc.
|
|
86
|
+
|
|
79
87
|
# Custom pricing and rate limit
|
|
80
88
|
paygate-mcp wrap --server "python my-server.py" --price 2 --rate-limit 30
|
|
81
89
|
|
|
@@ -114,13 +122,20 @@ async function main() {
|
|
|
114
122
|
process.exit(1);
|
|
115
123
|
}
|
|
116
124
|
}
|
|
125
|
+
// Multi-server mode check
|
|
126
|
+
const multiServers = fileConfig.servers;
|
|
127
|
+
const isMultiServer = multiServers && multiServers.length > 0;
|
|
117
128
|
const serverCmd = flags['server'] || (fileConfig.serverCommand ? [fileConfig.serverCommand, ...(fileConfig.serverArgs || [])].join(' ') : '');
|
|
118
129
|
const remoteUrl = flags['remote-url'] || fileConfig.remoteUrl;
|
|
119
|
-
if (!serverCmd && !remoteUrl) {
|
|
120
|
-
console.error('Error: --server, --remote-url, or --config is required.\n');
|
|
130
|
+
if (!serverCmd && !remoteUrl && !isMultiServer) {
|
|
131
|
+
console.error('Error: --server, --remote-url, or --config (with servers[]) is required.\n');
|
|
121
132
|
printUsage();
|
|
122
133
|
process.exit(1);
|
|
123
134
|
}
|
|
135
|
+
if (isMultiServer && (serverCmd || remoteUrl)) {
|
|
136
|
+
console.error('Error: use "servers" array OR --server/--remote-url, not both.\n');
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
124
139
|
if (serverCmd && remoteUrl) {
|
|
125
140
|
console.error('Error: use --server OR --remote-url, not both.\n');
|
|
126
141
|
process.exit(1);
|
|
@@ -155,7 +170,7 @@ async function main() {
|
|
|
155
170
|
toolPricing,
|
|
156
171
|
webhookUrl,
|
|
157
172
|
refundOnFailure: !!refundOnFailure,
|
|
158
|
-
}, adminKey, stateFile, remoteUrl, stripeSecret);
|
|
173
|
+
}, adminKey, stateFile, remoteUrl, stripeSecret, multiServers);
|
|
159
174
|
// Import keys from CLI flags
|
|
160
175
|
if (flags['import-key']) {
|
|
161
176
|
const pairs = flags['import-key'].split(',');
|
|
@@ -182,6 +197,18 @@ async function main() {
|
|
|
182
197
|
process.on('SIGTERM', shutdown);
|
|
183
198
|
try {
|
|
184
199
|
const result = await server.start();
|
|
200
|
+
// Build backend display string
|
|
201
|
+
let backendDisplay;
|
|
202
|
+
if (isMultiServer) {
|
|
203
|
+
const prefixes = multiServers.map(s => s.prefix).join(', ');
|
|
204
|
+
backendDisplay = `multi (${multiServers.length}) → ${prefixes}`.slice(0, 35);
|
|
205
|
+
}
|
|
206
|
+
else if (remoteUrl) {
|
|
207
|
+
backendDisplay = ('HTTP → ' + remoteUrl.slice(0, 28));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
backendDisplay = ('stdio → ' + (serverCmd || serverCommand).slice(0, 27));
|
|
211
|
+
}
|
|
185
212
|
console.log(`
|
|
186
213
|
╔══════════════════════════════════════════════════╗
|
|
187
214
|
║ PayGate MCP — Server Running ║
|
|
@@ -189,7 +216,7 @@ async function main() {
|
|
|
189
216
|
║ ║
|
|
190
217
|
║ Endpoint: http://localhost:${String(result.port).padEnd(5)} ║
|
|
191
218
|
║ Admin Key: ${result.adminKey.slice(0, 20)}... ║
|
|
192
|
-
║ Backend: ${
|
|
219
|
+
║ Backend: ${backendDisplay.padEnd(35)}║
|
|
193
220
|
║ ║
|
|
194
221
|
║ Pricing: ${String(price).padEnd(3)} credit(s) per tool call ║
|
|
195
222
|
║ Rate Limit: ${String(rateLimit).padEnd(3)} calls/min per key ║
|
|
@@ -208,6 +235,15 @@ async function main() {
|
|
|
208
235
|
║ POST /limits — Set spending limit (Admin) ║
|
|
209
236
|
╚══════════════════════════════════════════════════╝
|
|
210
237
|
`);
|
|
238
|
+
// Show multi-server details
|
|
239
|
+
if (isMultiServer) {
|
|
240
|
+
console.log(' Multi-server backends:');
|
|
241
|
+
for (const s of multiServers) {
|
|
242
|
+
const transport = s.remoteUrl ? `HTTP → ${s.remoteUrl}` : `stdio → ${s.serverCommand} ${(s.serverArgs || []).join(' ')}`;
|
|
243
|
+
console.log(` ${s.prefix}: ${transport}`);
|
|
244
|
+
}
|
|
245
|
+
console.log('');
|
|
246
|
+
}
|
|
211
247
|
console.log(` Admin key (save this): ${result.adminKey}\n`);
|
|
212
248
|
}
|
|
213
249
|
catch (error) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA;;;;;;;GAOG;;AAEH,qCAAyC;AAEzC,2BAAkC;AAClC,+BAA4B;AAE5B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACrF,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,OAAO,CAAC;IAAC,CAAC;AAC7B,CAAC,CAAC,EAAE,CAAC;AAEL,gFAAgF;AAEhF,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IAClC,MAAM,KAAK,GAA2B,EAAE,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBAClB,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA;;;;;;;GAOG;;AAEH,qCAAyC;AAEzC,2BAAkC;AAClC,+BAA4B;AAE5B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACrF,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,OAAO,CAAC;IAAC,CAAC;AAC7B,CAAC,CAAC,EAAE,CAAC;AAEL,gFAAgF;AAEhF,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IAClC,MAAM,KAAK,GAA2B,EAAE,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBAClB,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDX,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,OAAO,GAAgC,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QAC3E,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AA0BD,gFAAgF;AAEhF,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,gCAAgC;YAChC,IAAI,UAAU,GAAe,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,IAAA,iBAAY,EAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;oBACnD,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC/B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,8BAA+B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;oBACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;YAED,0BAA0B;YAC1B,MAAM,YAAY,GAAsC,UAAU,CAAC,OAAO,CAAC;YAC3E,MAAM,aAAa,GAAG,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;YAE9D,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,EAAE,GAAG,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9I,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC;YAE9D,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC/C,OAAO,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;gBAC5F,UAAU,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,IAAI,aAAa,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,CAAC;gBAC9C,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;gBAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;gBAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,wDAAwD;YACxD,IAAI,aAAa,GAAG,UAAU,CAAC,aAAa,IAAI,EAAE,CAAC;YACnD,IAAI,UAAU,GAAa,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC;YACvD,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC3C,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC;YAED,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,qBAAqB,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5F,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,qBAAqB,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YACtG,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,aAAa,IAAI,oBAAoB,IAAI,oBAAoB,CAAC;YACvG,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,MAAM,IAAI,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,IAAI,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC;YACxI,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC;YAC3D,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;YACjH,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC;YAC9D,MAAM,YAAY,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,mBAAmB,CAAC;YAC9E,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,UAAU,CAAC,UAAU,IAAI,IAAI,CAAC;YACzE,MAAM,eAAe,GAAG,KAAK,CAAC,mBAAmB,CAAC,KAAK,MAAM,IAAI,mBAAmB,IAAI,KAAK,IAAI,UAAU,CAAC,eAAe,IAAI,KAAK,CAAC;YAErI,MAAM,MAAM,GAAG,IAAI,sBAAa,CAAC;gBAC/B,aAAa;gBACb,UAAU;gBACV,IAAI;gBACJ,qBAAqB,EAAE,KAAK;gBAC5B,qBAAqB,EAAE,SAAS;gBAChC,IAAI;gBACJ,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,WAAW;gBACX,UAAU;gBACV,eAAe,EAAE,CAAC,CAAC,eAAe;aACnC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;YAE/D,6BAA6B;YAC7B,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAC1C,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;wBACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;oBACvF,CAAC;gBACH,CAAC;YACH,CAAC;YAED,+BAA+B;YAC/B,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;gBAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBACnE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YAED,2BAA2B;YAC3B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;gBAC1B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAClC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAEhC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;gBAEpC,+BAA+B;gBAC/B,IAAI,cAAsB,CAAC;gBAC3B,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,QAAQ,GAAG,YAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC7D,cAAc,GAAG,UAAU,YAAa,CAAC,MAAM,OAAO,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAChF,CAAC;qBAAM,IAAI,SAAS,EAAE,CAAC;oBACrB,cAAc,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBACxD,CAAC;qBAAM,CAAC;oBACN,cAAc,GAAG,CAAC,UAAU,GAAG,CAAC,SAAS,IAAI,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC5E,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC;;;;;oCAKgB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;mBAC9C,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;mBAC5B,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;;mBAEzB,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;mBACvB,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;mBAC3B,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;mBAC9B,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;mBACnE,CAAC,YAAY,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;mBAC/D,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;mBACpC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;;;;;;;;;;CAU3E,CAAC,CAAC;gBAEK,4BAA4B;gBAC5B,IAAI,aAAa,EAAE,CAAC;oBAClB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;oBACxC,KAAK,MAAM,CAAC,IAAI,YAAa,EAAE,CAAC;wBAC9B,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBACzH,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;oBAC/C,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClB,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,4BAA4B,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;YAC/D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM;QACR,CAAC;QAED,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,UAAU,EAAE,CAAC;YACb,MAAM;QAER,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;YAC3C,MAAM;QAER;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;YAC/C,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PayGateClient — Client SDK for consuming PayGate-protected MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Auto 402 retry: when a tool call returns -32402 (payment required),
|
|
6
|
+
* the client can automatically call a top-up function and retry.
|
|
7
|
+
* - Balance tracking: monitors remaining credits locally.
|
|
8
|
+
* - Connection management: handles MCP Streamable HTTP transport.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { PayGateClient } from 'paygate-mcp/client';
|
|
13
|
+
*
|
|
14
|
+
* const client = new PayGateClient({
|
|
15
|
+
* url: 'http://localhost:3402',
|
|
16
|
+
* apiKey: 'pg_abc123...',
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const tools = await client.listTools();
|
|
20
|
+
* const result = await client.callTool('search', { query: 'hello' });
|
|
21
|
+
* const balance = await client.getBalance();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface PayGateClientConfig {
|
|
25
|
+
/** PayGate server URL (e.g., "http://localhost:3402") */
|
|
26
|
+
url: string;
|
|
27
|
+
/** API key for authentication */
|
|
28
|
+
apiKey: string;
|
|
29
|
+
/** Request timeout in ms (default: 30000) */
|
|
30
|
+
timeout?: number;
|
|
31
|
+
/** Auto-retry on 402 (payment required). Calls onCreditsNeeded before retry.
|
|
32
|
+
* Default: false. */
|
|
33
|
+
autoRetry?: boolean;
|
|
34
|
+
/** Called when credits are needed (402 response). Return true if credits
|
|
35
|
+
* were added (e.g., via external top-up), false to abort. */
|
|
36
|
+
onCreditsNeeded?: (info: CreditsNeededInfo) => Promise<boolean>;
|
|
37
|
+
/** Max auto-retries per request (default: 1) */
|
|
38
|
+
maxRetries?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface CreditsNeededInfo {
|
|
41
|
+
tool: string;
|
|
42
|
+
creditsRequired: number;
|
|
43
|
+
remainingCredits: number;
|
|
44
|
+
}
|
|
45
|
+
export interface ToolInfo {
|
|
46
|
+
name: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
inputSchema?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
export interface ToolCallResult {
|
|
51
|
+
content: Array<{
|
|
52
|
+
type: string;
|
|
53
|
+
text?: string;
|
|
54
|
+
[k: string]: unknown;
|
|
55
|
+
}>;
|
|
56
|
+
isError?: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface BalanceInfo {
|
|
59
|
+
name: string;
|
|
60
|
+
credits: number;
|
|
61
|
+
totalSpent: number;
|
|
62
|
+
totalCalls: number;
|
|
63
|
+
spendingLimit: number;
|
|
64
|
+
remainingBudget: number | null;
|
|
65
|
+
lastUsedAt: string | null;
|
|
66
|
+
allowedTools: string[];
|
|
67
|
+
deniedTools: string[];
|
|
68
|
+
expiresAt: string | null;
|
|
69
|
+
}
|
|
70
|
+
export declare class PayGateClient {
|
|
71
|
+
private readonly baseUrl;
|
|
72
|
+
private readonly apiKey;
|
|
73
|
+
private readonly timeout;
|
|
74
|
+
private readonly autoRetry;
|
|
75
|
+
private readonly maxRetries;
|
|
76
|
+
private readonly onCreditsNeeded?;
|
|
77
|
+
private nextId;
|
|
78
|
+
private _lastBalance;
|
|
79
|
+
constructor(config: PayGateClientConfig);
|
|
80
|
+
/**
|
|
81
|
+
* List available tools from the gated MCP server.
|
|
82
|
+
*/
|
|
83
|
+
listTools(): Promise<ToolInfo[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Call a tool on the gated MCP server.
|
|
86
|
+
* If autoRetry is enabled and the server returns -32402 (payment required),
|
|
87
|
+
* the client will call onCreditsNeeded and retry.
|
|
88
|
+
*/
|
|
89
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<ToolCallResult>;
|
|
90
|
+
/**
|
|
91
|
+
* Get balance information for the current API key.
|
|
92
|
+
*/
|
|
93
|
+
getBalance(): Promise<BalanceInfo>;
|
|
94
|
+
/**
|
|
95
|
+
* Send an initialize request to the MCP server.
|
|
96
|
+
*/
|
|
97
|
+
initialize(): Promise<Record<string, unknown>>;
|
|
98
|
+
/**
|
|
99
|
+
* Ping the server.
|
|
100
|
+
*/
|
|
101
|
+
ping(): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* Get the last known balance (from the last getBalance() call).
|
|
104
|
+
* Returns null if getBalance() hasn't been called yet.
|
|
105
|
+
*/
|
|
106
|
+
get lastKnownBalance(): number | null;
|
|
107
|
+
private rpcCall;
|
|
108
|
+
private httpPost;
|
|
109
|
+
private httpGet;
|
|
110
|
+
}
|
|
111
|
+
export declare class PayGateError extends Error {
|
|
112
|
+
readonly code: number;
|
|
113
|
+
readonly data?: unknown;
|
|
114
|
+
constructor(code: number, message: string, data?: unknown);
|
|
115
|
+
get isPaymentRequired(): boolean;
|
|
116
|
+
get isRateLimited(): boolean;
|
|
117
|
+
get isExpired(): boolean;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PayGateClient — Client SDK for consuming PayGate-protected MCP servers.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Auto 402 retry: when a tool call returns -32402 (payment required),
|
|
7
|
+
* the client can automatically call a top-up function and retry.
|
|
8
|
+
* - Balance tracking: monitors remaining credits locally.
|
|
9
|
+
* - Connection management: handles MCP Streamable HTTP transport.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { PayGateClient } from 'paygate-mcp/client';
|
|
14
|
+
*
|
|
15
|
+
* const client = new PayGateClient({
|
|
16
|
+
* url: 'http://localhost:3402',
|
|
17
|
+
* apiKey: 'pg_abc123...',
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const tools = await client.listTools();
|
|
21
|
+
* const result = await client.callTool('search', { query: 'hello' });
|
|
22
|
+
* const balance = await client.getBalance();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
30
|
+
}
|
|
31
|
+
Object.defineProperty(o, k2, desc);
|
|
32
|
+
}) : (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
o[k2] = m[k];
|
|
35
|
+
}));
|
|
36
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
37
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
38
|
+
}) : function(o, v) {
|
|
39
|
+
o["default"] = v;
|
|
40
|
+
});
|
|
41
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
42
|
+
var ownKeys = function(o) {
|
|
43
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
44
|
+
var ar = [];
|
|
45
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
46
|
+
return ar;
|
|
47
|
+
};
|
|
48
|
+
return ownKeys(o);
|
|
49
|
+
};
|
|
50
|
+
return function (mod) {
|
|
51
|
+
if (mod && mod.__esModule) return mod;
|
|
52
|
+
var result = {};
|
|
53
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
54
|
+
__setModuleDefault(result, mod);
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
})();
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.PayGateError = exports.PayGateClient = void 0;
|
|
60
|
+
const http = __importStar(require("http"));
|
|
61
|
+
const https = __importStar(require("https"));
|
|
62
|
+
// ─── Client ─────────────────────────────────────────────────────────────────
|
|
63
|
+
class PayGateClient {
|
|
64
|
+
baseUrl;
|
|
65
|
+
apiKey;
|
|
66
|
+
timeout;
|
|
67
|
+
autoRetry;
|
|
68
|
+
maxRetries;
|
|
69
|
+
onCreditsNeeded;
|
|
70
|
+
nextId = 1;
|
|
71
|
+
_lastBalance = null;
|
|
72
|
+
constructor(config) {
|
|
73
|
+
this.baseUrl = new URL(config.url);
|
|
74
|
+
this.apiKey = config.apiKey;
|
|
75
|
+
this.timeout = config.timeout || 30_000;
|
|
76
|
+
this.autoRetry = config.autoRetry || false;
|
|
77
|
+
this.maxRetries = config.maxRetries || 1;
|
|
78
|
+
this.onCreditsNeeded = config.onCreditsNeeded;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* List available tools from the gated MCP server.
|
|
82
|
+
*/
|
|
83
|
+
async listTools() {
|
|
84
|
+
const response = await this.rpcCall('tools/list', {});
|
|
85
|
+
if (response.error) {
|
|
86
|
+
throw new PayGateError(response.error.code, response.error.message, response.error.data);
|
|
87
|
+
}
|
|
88
|
+
const result = response.result;
|
|
89
|
+
return result?.tools || [];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Call a tool on the gated MCP server.
|
|
93
|
+
* If autoRetry is enabled and the server returns -32402 (payment required),
|
|
94
|
+
* the client will call onCreditsNeeded and retry.
|
|
95
|
+
*/
|
|
96
|
+
async callTool(name, args) {
|
|
97
|
+
let retries = 0;
|
|
98
|
+
while (true) {
|
|
99
|
+
const response = await this.rpcCall('tools/call', { name, arguments: args || {} });
|
|
100
|
+
if (response.error) {
|
|
101
|
+
// Check if it's a payment-required error
|
|
102
|
+
if (response.error.code === -32402 && this.autoRetry && retries < this.maxRetries) {
|
|
103
|
+
const data = response.error.data;
|
|
104
|
+
const creditsRequired = data?.creditsRequired || 0;
|
|
105
|
+
const remainingCredits = data?.remainingCredits || 0;
|
|
106
|
+
if (this.onCreditsNeeded) {
|
|
107
|
+
const shouldRetry = await this.onCreditsNeeded({
|
|
108
|
+
tool: name,
|
|
109
|
+
creditsRequired,
|
|
110
|
+
remainingCredits,
|
|
111
|
+
});
|
|
112
|
+
if (shouldRetry) {
|
|
113
|
+
retries++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
throw new PayGateError(response.error.code, response.error.message, response.error.data);
|
|
119
|
+
}
|
|
120
|
+
const result = response.result;
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get balance information for the current API key.
|
|
126
|
+
*/
|
|
127
|
+
async getBalance() {
|
|
128
|
+
const response = await this.httpGet('/balance');
|
|
129
|
+
const balance = response;
|
|
130
|
+
this._lastBalance = balance.credits;
|
|
131
|
+
return balance;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Send an initialize request to the MCP server.
|
|
135
|
+
*/
|
|
136
|
+
async initialize() {
|
|
137
|
+
const response = await this.rpcCall('initialize', {
|
|
138
|
+
protocolVersion: '2024-11-05',
|
|
139
|
+
capabilities: {},
|
|
140
|
+
clientInfo: { name: 'paygate-client', version: '1.0.0' },
|
|
141
|
+
});
|
|
142
|
+
if (response.error) {
|
|
143
|
+
throw new PayGateError(response.error.code, response.error.message, response.error.data);
|
|
144
|
+
}
|
|
145
|
+
return response.result;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Ping the server.
|
|
149
|
+
*/
|
|
150
|
+
async ping() {
|
|
151
|
+
const response = await this.rpcCall('ping', {});
|
|
152
|
+
return !response.error;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the last known balance (from the last getBalance() call).
|
|
156
|
+
* Returns null if getBalance() hasn't been called yet.
|
|
157
|
+
*/
|
|
158
|
+
get lastKnownBalance() {
|
|
159
|
+
return this._lastBalance;
|
|
160
|
+
}
|
|
161
|
+
// ─── Internal ─────────────────────────────────────────────────────────────
|
|
162
|
+
async rpcCall(method, params) {
|
|
163
|
+
const id = this.nextId++;
|
|
164
|
+
const body = JSON.stringify({
|
|
165
|
+
jsonrpc: '2.0',
|
|
166
|
+
id,
|
|
167
|
+
method,
|
|
168
|
+
params,
|
|
169
|
+
});
|
|
170
|
+
const responseBody = await this.httpPost('/mcp', body, {
|
|
171
|
+
'Content-Type': 'application/json',
|
|
172
|
+
'X-API-Key': this.apiKey,
|
|
173
|
+
});
|
|
174
|
+
return JSON.parse(responseBody);
|
|
175
|
+
}
|
|
176
|
+
httpPost(path, body, headers) {
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
const isHttps = this.baseUrl.protocol === 'https:';
|
|
179
|
+
const transport = isHttps ? https : http;
|
|
180
|
+
const options = {
|
|
181
|
+
hostname: this.baseUrl.hostname,
|
|
182
|
+
port: this.baseUrl.port || (isHttps ? 443 : 80),
|
|
183
|
+
path,
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: {
|
|
186
|
+
...headers,
|
|
187
|
+
'Content-Length': String(Buffer.byteLength(body)),
|
|
188
|
+
},
|
|
189
|
+
timeout: this.timeout,
|
|
190
|
+
};
|
|
191
|
+
const req = transport.request(options, (res) => {
|
|
192
|
+
let data = '';
|
|
193
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
194
|
+
res.on('end', () => resolve(data));
|
|
195
|
+
});
|
|
196
|
+
req.on('error', reject);
|
|
197
|
+
req.on('timeout', () => {
|
|
198
|
+
req.destroy();
|
|
199
|
+
reject(new Error(`Request timed out after ${this.timeout}ms`));
|
|
200
|
+
});
|
|
201
|
+
req.write(body);
|
|
202
|
+
req.end();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
httpGet(path) {
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
const isHttps = this.baseUrl.protocol === 'https:';
|
|
208
|
+
const transport = isHttps ? https : http;
|
|
209
|
+
const options = {
|
|
210
|
+
hostname: this.baseUrl.hostname,
|
|
211
|
+
port: this.baseUrl.port || (isHttps ? 443 : 80),
|
|
212
|
+
path,
|
|
213
|
+
method: 'GET',
|
|
214
|
+
headers: {
|
|
215
|
+
'X-API-Key': this.apiKey,
|
|
216
|
+
},
|
|
217
|
+
timeout: this.timeout,
|
|
218
|
+
};
|
|
219
|
+
const req = transport.request(options, (res) => {
|
|
220
|
+
let data = '';
|
|
221
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
222
|
+
res.on('end', () => {
|
|
223
|
+
try {
|
|
224
|
+
resolve(JSON.parse(data));
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
reject(new Error(`Invalid JSON response: ${data.slice(0, 100)}`));
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
req.on('error', reject);
|
|
232
|
+
req.on('timeout', () => {
|
|
233
|
+
req.destroy();
|
|
234
|
+
reject(new Error(`Request timed out after ${this.timeout}ms`));
|
|
235
|
+
});
|
|
236
|
+
req.end();
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.PayGateClient = PayGateClient;
|
|
241
|
+
// ─── Error class ──────────────────────────────────────────────────────────
|
|
242
|
+
class PayGateError extends Error {
|
|
243
|
+
code;
|
|
244
|
+
data;
|
|
245
|
+
constructor(code, message, data) {
|
|
246
|
+
super(message);
|
|
247
|
+
this.name = 'PayGateError';
|
|
248
|
+
this.code = code;
|
|
249
|
+
this.data = data;
|
|
250
|
+
}
|
|
251
|
+
get isPaymentRequired() {
|
|
252
|
+
return this.code === -32402;
|
|
253
|
+
}
|
|
254
|
+
get isRateLimited() {
|
|
255
|
+
return this.message.includes('rate_limit');
|
|
256
|
+
}
|
|
257
|
+
get isExpired() {
|
|
258
|
+
return this.message.includes('expired');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.PayGateError = PayGateError;
|
|
262
|
+
//# sourceMappingURL=client.js.map
|