@mcpaid/sdk 2.0.0 โ†’ 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
5
5
  [![Base Mainnet](https://img.shields.io/badge/Base%20Mainnet-EVM%208453-blue)](https://basescan.org)
6
6
  [![Circle USDC](https://img.shields.io/badge/USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913-brightgreen)](https://basescan.org/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)
7
- [![Test Suite](https://img.shields.io/badge/tests-141%20passing-success.svg)](test)
7
+ [![Test Suite](https://img.shields.io/badge/tests-163%20passing-success.svg)](test)
8
8
 
9
9
  **MCPaid** enables developers of [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers to seamlessly monetize tools with pay-per-use micropayments (e.g. $0.005 / call), gasless AI agent authorizations via **HTTP 402 + EIP-712**, and **automated 60-second on-chain USDC payouts on Base L2**.
10
10
 
@@ -27,16 +27,22 @@
27
27
  - When a developer requests a withdrawal, Cloudflare Workers' isolated cron relayer automatically executes the on-chain ERC-20 transfer on Base L2 every **60 seconds**, stamping confirmed BaseScan receipts directly into the dashboard.
28
28
  - **Zero HTTP Attack Surface**: All payout execution paths run strictly via internal edge cron triggers or authenticated local operator scripts (`mcpaid relayer --run`).
29
29
 
30
- 4. **Zero-Config Live Development Tunnel (`mcpaid dev`)**:
30
+ 4. **Cryptographic Edge Receipts (`X-MCPaid-Receipt`) & Downstream Enforcement**:
31
+ - Single-use, tamper-proof HMAC-SHA256 payment receipts injected by the edge gateway on proxied requests.
32
+ - Downstream origin backends, microservices, and databases verify payment proofs in **5 lines of code**, preventing forked clients or scrapers from bypassing the edge gateway.
33
+ - Per-server secret derivation via HKDF-SHA256 (`mcpaid_sec_...`) with zero-downtime 1-hour grace window key rotation.
34
+ - Built-in anti-replay nonce claim store (`MemoryReceiptStore`, `D1ReceiptStore`) and drop-in Express middleware (`createReceiptMiddleware`).
35
+
36
+ 5. **Zero-Config Live Development Tunnel (`mcpaid dev`)**:
31
37
  - Monetize MCP servers running locally on hardware (`http://127.0.0.1:3000/mcp`) without buying domains or renting cloud VPS servers.
32
38
  - Launches an encrypted TLS 1.3 tunnel with an integrated **Security Shield** that drops direct bypass traffic with `403 Forbidden`.
33
39
 
34
- 5. **Server Management & Anti-Hijacking Security**:
40
+ 6. **Server Management & Anti-Hijacking Security**:
35
41
  - Clean-slate server de-registration via Web Dashboard or CLI (`mcpaid server remove <id>`).
36
42
  - Ownership verification ensures server IDs cannot be overwritten by unauthorized third parties.
37
43
  - Passwordless 2FA email authentication with 30-day sliding-window sessions.
38
44
 
39
- 6. **Agent Safety Circuit Breakers**:
45
+ 7. **Agent Safety Circuit Breakers**:
40
46
  - Built-in velocity limiters (sliding 1-minute window).
41
47
  - Spend ceiling hard caps (`maxPricePerCallUsd`, `maxTotalBudgetUsd`).
42
48
  - Infinite duplicate parameter loop detection.
@@ -316,6 +322,170 @@ print("Tool Result:", resp.json()["result"])
316
322
 
317
323
  ---
318
324
 
325
+ ## ๐Ÿงพ Edge Receipts: Downstream Payment Enforcement
326
+
327
+ When an agent invokes a paid MCP tool, MCPaid's edge verifies the 402 micropayment, credits your ledger, and proxies the request to your upstream server. But what if your upstream server forwards the call to a downstream backend, database, microservice, or webhook (e.g. committing a database write, enqueueing an expensive job, or calling third-party APIs)?
328
+
329
+ Without cryptographic proof, your downstream backend cannot distinguish an authorized edge-settled call from an attacker or forked CLI hitting your internal endpoints directly.
330
+
331
+ **Edge Receipts** solve this downstream trust boundary:
332
+ 1. When a paid call settles, the edge gateway mints a cryptographically signed receipt and injects it as an `X-MCPaid-Receipt` HTTP header (base64url-encoded JSON).
333
+ 2. Your downstream backend verifies the receipt in **5 lines of code** with anti-replay defense and tool binding.
334
+
335
+ ```
336
+ [ AI Agent ]
337
+ โ”‚
338
+ โ”‚ 1. POST /mcp/:serverId (tools/call)
339
+ โ–ผ
340
+ [ MCPaid Edge Gateway ]
341
+ โ”‚
342
+ โ”‚ 2. HTTP 402 Payment Required (Price + Nonce)
343
+ โ–ผ
344
+ [ AI Agent Pays ]
345
+ โ”‚
346
+ โ”‚ 3. Signs gasless EIP-712 micro-permit & replays
347
+ โ–ผ
348
+ [ MCPaid Edge Gateway ]
349
+ โ”‚
350
+ โ”‚ 4. Settles micropayment on Base L2 ledger (97% Dev / 3% Platform)
351
+ โ”‚ 5. Mints signed receipt & proxies call with X-MCPaid-Receipt header
352
+ โ–ผ
353
+ [ Downstream Server / Origin Backend ]
354
+ โ”‚
355
+ โ”‚ 6. Verifies receipt in 5 lines (HMAC-SHA256 + atomic nonce claim)
356
+ โ–ผ
357
+ [ Commits DB write / executes heavy compute / returns response ]
358
+ ```
359
+
360
+ ### 1. Retrieve Your Server's Receipt Secret
361
+
362
+ Each server has a deterministic receipt secret derived via `HKDF-SHA256` from the edge master secret. Retrieve it via the CLI:
363
+
364
+ ```bash
365
+ # Display your server's receipt secret
366
+ npx @mcpaid/sdk server receipt-secret <serverId>
367
+
368
+ # Rotate secret (previous secret remains valid for 1-hour grace window)
369
+ npx @mcpaid/sdk server receipt-secret <serverId> --rotate
370
+
371
+ # Automatically append or update MCPAID_RECEIPT_SECRET in your local .env
372
+ npx @mcpaid/sdk server receipt-secret <serverId> --env
373
+ ```
374
+
375
+ ### 2. Downstream Verification Code Snippets
376
+
377
+ #### Option A: Express / Node.js Middleware
378
+
379
+ Use the built-in `createReceiptMiddleware` for drop-in Express protection:
380
+
381
+ ```typescript
382
+ import express from 'express';
383
+ import { createReceiptMiddleware, MemoryReceiptStore } from '@mcpaid/sdk';
384
+
385
+ const app = express();
386
+ app.use(express.json());
387
+
388
+ // Reject direct scrapers or un-settled calls in 5 lines
389
+ app.post(
390
+ '/v1/heavy-compute',
391
+ createReceiptMiddleware({
392
+ secret: process.env.MCPAID_RECEIPT_SECRET!,
393
+ expectedTool: 'heavy_compute',
394
+ store: new MemoryReceiptStore(), // Prevents replay attacks
395
+ }),
396
+ (req: any, res) => {
397
+ // req.mcpaidReceipt contains verified settlement metadata
398
+ res.json({ success: true, payer: req.mcpaidReceipt.agentWallet });
399
+ }
400
+ );
401
+
402
+ app.listen(3000);
403
+ ```
404
+
405
+ #### Option B: Cloudflare Worker / Serverless Edge
406
+
407
+ Validate inside a Cloudflare Worker or Edge Function using `verifyEdgeReceipt` and SQLite/D1 replay storage:
408
+
409
+ ```typescript
410
+ import { verifyEdgeReceipt, D1ReceiptStore } from '@mcpaid/sdk';
411
+
412
+ export default {
413
+ async fetch(request: Request, env: any): Promise<Response> {
414
+ const error = await verifyEdgeReceipt(
415
+ {
416
+ secret: env.MCPAID_RECEIPT_SECRET,
417
+ previousSecret: env.MCPAID_PREVIOUS_RECEIPT_SECRET, // 1-hr rotation grace window
418
+ store: new D1ReceiptStore(env.DB), // Atomic SQLite anti-replay
419
+ },
420
+ {
421
+ receipt: request.headers.get('X-MCPaid-Receipt'),
422
+ expectedTool: 'cloud_sync_push',
423
+ maxAgeSeconds: 300, // 5-minute expiry
424
+ }
425
+ );
426
+
427
+ if (error) {
428
+ return new Response(JSON.stringify({ error: 'payment_required', message: error }), {
429
+ status: 402,
430
+ headers: { 'Content-Type': 'application/json' },
431
+ });
432
+ }
433
+
434
+ // Proceed with state-changing database write or API call
435
+ return new Response(JSON.stringify({ status: 'committed' }), { status: 200 });
436
+ },
437
+ };
438
+ ```
439
+
440
+ #### Option C: Python Downstream Backend (FastAPI / Flask)
441
+
442
+ Verify receipts in Python using standard library cryptographic primitives (`hmac`, `hashlib`):
443
+
444
+ ```python
445
+ import base64, hashlib, hmac, json, os, time
446
+ from fastapi import FastAPI, Header, HTTPException
447
+
448
+ app = FastAPI()
449
+ SECRET = os.environ["MCPAID_RECEIPT_SECRET"]
450
+ claimed_nonces = set()
451
+
452
+ def verify_receipt(receipt_header: str, expected_tool: str) -> dict:
453
+ if not receipt_header:
454
+ raise HTTPException(status_code=402, detail="Missing X-MCPaid-Receipt header")
455
+
456
+ # Pad base64url string if necessary and decode
457
+ padded = receipt_header + "=" * ((4 - len(receipt_header) % 4) % 4)
458
+ receipt = json.loads(base64.urlsafe_b64decode(padded).decode("utf-8"))
459
+
460
+ if receipt.get("v") != 1 or receipt.get("toolName") != expected_tool:
461
+ raise HTTPException(status_code=402, detail="Invalid receipt tool or version")
462
+
463
+ if time.time() > receipt.get("exp", 0) + 60:
464
+ raise HTTPException(status_code=402, detail="Receipt expired")
465
+
466
+ # Recompute HMAC-SHA256 on canonical JSON without 'sig'
467
+ sig = receipt.pop("sig", "")
468
+ canonical = json.dumps(receipt, sort_keys=True, separators=(",", ":"))
469
+ computed = hmac.new(SECRET.encode(), canonical.encode(), hashlib.sha256).hexdigest()
470
+
471
+ if not hmac.compare_digest(sig, computed):
472
+ raise HTTPException(status_code=402, detail="Cryptographic signature mismatch")
473
+
474
+ nonce = receipt["challengeNonce"]
475
+ if nonce in claimed_nonces:
476
+ raise HTTPException(status_code=402, detail="Receipt replay attack detected")
477
+ claimed_nonces.add(nonce)
478
+
479
+ return receipt
480
+
481
+ @app.post("/v1/db-commit")
482
+ def commit_action(x_mcpaid_receipt: str = Header(None)):
483
+ verified = verify_receipt(x_mcpaid_receipt, expected_tool="db_commit")
484
+ return {"status": "success", "amount_paid_micro": verified["amountMicro"]}
485
+ ```
486
+
487
+ ---
488
+
319
489
  ## ๐Ÿ› ๏ธ CLI Command Reference
320
490
 
321
491
  | Command | Arguments / Flags | Description |
@@ -327,6 +497,7 @@ print("Tool Result:", resp.json()["result"])
327
497
  | `mcpaid publish` | `[config-path] [--gateway <url>]` | Publish and monetize an MCP server on MCPaid Edge Gateway. |
328
498
  | `mcpaid server list` | `โ€”` | List all MCP servers and pricing rules registered under your account. |
329
499
  | `mcpaid server remove` | `<server-id>` | Disconnect and permanently remove an MCP server (clean slate). |
500
+ | `mcpaid server receipt-secret` | `<id> [--rotate] [--env]` | Retrieve or rotate HMAC-SHA256 Edge Receipt secret for backend verification. |
330
501
  | `mcpaid login` | `[--email <addr>]` | Sign in with passwordless 2FA email confirmation code. |
331
502
  | `mcpaid whoami` | `โ€”` | Display authenticated developer profile and payout wallet. |
332
503
  | `mcpaid logout` | `โ€”` | Revoke active session token and wipe local credentials. |
@@ -352,16 +523,16 @@ print("Tool Result:", resp.json()["result"])
352
523
 
353
524
  ## ๐Ÿงช Comprehensive Test Suite
354
525
 
355
- MCPaid includes **150 automated unit and integration tests** across 23 suites covering edge handlers, cryptographic verifiers, smart contract splits, financial ledgers, and the automated relayer:
526
+ MCPaid includes **163 automated unit and integration tests** across 25 suites covering edge handlers, cryptographic verifiers, smart contract splits, financial ledgers, edge receipts, and the automated relayer:
356
527
 
357
528
  ```bash
358
529
  npm test
359
530
  ```
360
531
 
361
532
  ```
362
- # tests 150
363
- # suites 23
364
- # pass 150
533
+ # tests 163
534
+ # suites 25
535
+ # pass 163
365
536
  # fail 0
366
537
  ```
367
538
 
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAqDH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAM3C;AAED,wBAAgB,eAAe,IAAI,cAAc,GAAG,IAAI,CASvD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAG3D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAOvC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW7D;AA8gBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAmB5D;AA+6BD,wBAAsB,MAAM,kBAkE3B"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAqDH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAM3C;AAED,wBAAgB,eAAe,IAAI,cAAc,GAAG,IAAI,CASvD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAG3D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAOvC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW7D;AA+gBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAmB5D;AAkkCD,wBAAsB,MAAM,kBAkE3B"}
package/dist/cli.js CHANGED
@@ -126,6 +126,7 @@ Commands:
126
126
  server add [config-path] Register an MCP server on MCPaid Edge Gateway
127
127
  server list List your registered MCP servers
128
128
  server remove <id> Disconnect and remove an MCP server from MCPaid
129
+ server receipt-secret <id> View or rotate Edge Receipt secret for backend verification (--rotate, --env)
129
130
  login Sign in to your MCPaid developer account
130
131
  logout Log out and remove local credentials
131
132
  whoami Show currently authenticated developer account
@@ -1124,6 +1125,7 @@ Choose how to proceed:
1124
1125
  creds.payoutWallet = config.payoutWallet;
1125
1126
  saveCredentials(creds);
1126
1127
  }
1128
+ const receiptSecret = data.receiptSecret;
1127
1129
  console.log(`
1128
1130
  ======================================================
1129
1131
  ๐ŸŽ‰ MCP Server Successfully Published to MCPaid!
@@ -1133,6 +1135,7 @@ Choose how to proceed:
1133
1135
  โ€ข Edge Gateway: ${gatewayUrl}/mcp/${config.serverId}
1134
1136
  โ€ข Upstream: ${upstreamUrl}
1135
1137
  โ€ข Payout: ${config.payoutWallet} (Base L2)
1138
+ ${receiptSecret ? `โ€ข Edge Receipt Secret: ${receiptSecret}` : ''}
1136
1139
  โ€ข Configured Tools (${config.tools.length}):
1137
1140
  ${config.tools.map((t) => ` โ€ข ${t.toolName.padEnd(20)} -> ${t.type === 'free' ? 'FREE' : `$${t.priceUsd} USDC`}`).join('\n')}
1138
1141
 
@@ -1140,6 +1143,31 @@ ${config.tools.map((t) => ` โ€ข ${t.toolName.padEnd(20)} -> ${t.type === 'free
1140
1143
  npx @mcpaid/sdk bridge --gateway ${gatewayUrl}/mcp/${config.serverId}
1141
1144
  ======================================================
1142
1145
  `);
1146
+ if (receiptSecret) {
1147
+ console.log(`๐Ÿ” Downstream Verification:
1148
+ Use verifyEdgeReceipt() from @mcpaid/sdk in your backend to ensure callers actually paid at the edge.`);
1149
+ const envPath = resolve(process.cwd(), '.env');
1150
+ const hasEnvFlag = hasFlag(args, 'env');
1151
+ const shouldSave = hasEnvFlag
1152
+ ? true
1153
+ : (await promptQuestion('Save MCPAID_RECEIPT_SECRET to .env? (Y/n): ')).toLowerCase() !== 'n';
1154
+ if (shouldSave) {
1155
+ try {
1156
+ let envContent = existsSync(envPath) ? readFileSync(envPath, 'utf-8') : '';
1157
+ if (envContent.includes('MCPAID_RECEIPT_SECRET=')) {
1158
+ envContent = envContent.replace(/MCPAID_RECEIPT_SECRET=.*/g, `MCPAID_RECEIPT_SECRET=${receiptSecret}`);
1159
+ }
1160
+ else {
1161
+ envContent += `\n# MCPaid Edge Receipt Secret for backend verification\nMCPAID_RECEIPT_SECRET=${receiptSecret}\n`;
1162
+ }
1163
+ writeFileSync(envPath, envContent, 'utf-8');
1164
+ console.log(`โœ… Saved MCPAID_RECEIPT_SECRET to ${envPath}\n`);
1165
+ }
1166
+ catch (err) {
1167
+ console.warn(`Could not update .env: ${err.message}`);
1168
+ }
1169
+ }
1170
+ }
1143
1171
  }
1144
1172
  async function handleServerList() {
1145
1173
  const args = process.argv.slice(3);
@@ -1253,6 +1281,110 @@ Clean slate achieved. You can republish anytime with:
1253
1281
  npx @mcpaid/sdk publish
1254
1282
  `);
1255
1283
  }
1284
+ async function handleServerReceiptSecret(targetServerId) {
1285
+ const args = process.argv.slice(3);
1286
+ const gatewayUrl = getFlagValue(args, 'gateway') || process.env.MCPAID_GATEWAY_URL || 'https://mcpaid.dev';
1287
+ const isRotate = args.includes('--rotate') || args.includes('-r');
1288
+ const isSaveEnv = args.includes('--env') || args.includes('-e');
1289
+ let serverId = targetServerId;
1290
+ if (serverId && serverId.startsWith('-')) {
1291
+ serverId = undefined;
1292
+ }
1293
+ if (!serverId) {
1294
+ const nonFlags = args.filter(a => !a.startsWith('-') && a !== 'receipt-secret' && a !== 'secret');
1295
+ if (nonFlags.length > 0) {
1296
+ serverId = nonFlags[0];
1297
+ }
1298
+ }
1299
+ const creds = loadCredentials();
1300
+ const token = creds?.token || process.env.MCPAID_TOKEN;
1301
+ if (!token) {
1302
+ console.log('โŒ You must be logged in to access server receipt secrets.');
1303
+ console.log('Run: npx @mcpaid/sdk login');
1304
+ return;
1305
+ }
1306
+ if (!serverId) {
1307
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1308
+ serverId = await new Promise((res) => {
1309
+ rl.question('Enter the ID of the MCP server: ', (ans) => {
1310
+ rl.close();
1311
+ res(ans.trim());
1312
+ });
1313
+ });
1314
+ }
1315
+ if (!serverId) {
1316
+ console.error('โŒ Error: Server ID is required. Example: npx @mcpaid/sdk server receipt-secret my-server');
1317
+ return;
1318
+ }
1319
+ if (isRotate) {
1320
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1321
+ const ans = await new Promise((res) => {
1322
+ rl.question(`โš ๏ธ Rotate Edge Receipt secret for "${serverId}"? (Previous secret remains valid for 1-hour grace window) (y/N): `, (a) => {
1323
+ rl.close();
1324
+ res(a.trim().toLowerCase());
1325
+ });
1326
+ });
1327
+ if (ans !== 'y' && ans !== 'yes') {
1328
+ console.log('Operation cancelled.');
1329
+ return;
1330
+ }
1331
+ }
1332
+ const endpoint = isRotate
1333
+ ? `${gatewayUrl}/v1/servers/${encodeURIComponent(serverId)}/receipt-secret/rotate`
1334
+ : `${gatewayUrl}/v1/servers/${encodeURIComponent(serverId)}/receipt-secret`;
1335
+ const res = await fetch(endpoint, {
1336
+ method: isRotate ? 'POST' : 'GET',
1337
+ headers: {
1338
+ Authorization: `Bearer ${token}`,
1339
+ 'Content-Type': 'application/json',
1340
+ },
1341
+ });
1342
+ const data = (await res.json().catch(() => ({})));
1343
+ if (!res.ok || !data.success) {
1344
+ console.error(`โŒ Failed to retrieve receipt secret: ${data.error || JSON.stringify(data)}`);
1345
+ return;
1346
+ }
1347
+ console.log(`
1348
+ ======================================================
1349
+ ๐Ÿ”‘ MCPaid Edge Receipt Secret
1350
+ ======================================================
1351
+ โ€ข Server ID: ${data.serverId}
1352
+ โ€ข Receipt Secret: ${data.receiptSecret}
1353
+ ${data.previousReceiptSecret ? `โ€ข Previous Secret: ${data.previousReceiptSecret} (1-hr grace window active)` : ''}
1354
+ ======================================================
1355
+ ๐Ÿ“‹ Downstream Backend Verification (TypeScript / Node):
1356
+ import { verifyEdgeReceipt } from '@mcpaid/sdk';
1357
+
1358
+ const err = await verifyEdgeReceipt(env, {
1359
+ receipt: request.headers.get('X-MCPaid-Receipt'),
1360
+ expectedTool: 'my_paid_tool',
1361
+ });
1362
+ ======================================================
1363
+ `);
1364
+ if (isSaveEnv) {
1365
+ const envPath = resolve(process.cwd(), '.env');
1366
+ let envContent = existsSync(envPath) ? readFileSync(envPath, 'utf-8') : '';
1367
+ if (envContent.includes('MCPAID_RECEIPT_SECRET=')) {
1368
+ envContent = envContent.replace(/MCPAID_RECEIPT_SECRET=.*/g, `MCPAID_RECEIPT_SECRET=${data.receiptSecret}`);
1369
+ }
1370
+ else {
1371
+ envContent += `\n# MCPaid Edge Receipt Secret for backend verification\nMCPAID_RECEIPT_SECRET=${data.receiptSecret}\n`;
1372
+ }
1373
+ if (data.previousReceiptSecret) {
1374
+ if (envContent.includes('MCPAID_PREVIOUS_RECEIPT_SECRET=')) {
1375
+ envContent = envContent.replace(/MCPAID_PREVIOUS_RECEIPT_SECRET=.*/g, `MCPAID_PREVIOUS_RECEIPT_SECRET=${data.previousReceiptSecret}`);
1376
+ }
1377
+ else {
1378
+ envContent += `MCPAID_PREVIOUS_RECEIPT_SECRET=${data.previousReceiptSecret}\n`;
1379
+ }
1380
+ }
1381
+ writeFileSync(envPath, envContent, 'utf-8');
1382
+ console.log(`โœ… Saved MCPAID_RECEIPT_SECRET to ${envPath}\n`);
1383
+ if (data.previousReceiptSecret) {
1384
+ console.log(`โ„น๏ธ Saved MCPAID_PREVIOUS_RECEIPT_SECRET (active for 1-hr grace period)`);
1385
+ }
1386
+ }
1387
+ }
1256
1388
  async function handleServer() {
1257
1389
  const sub = process.argv[3];
1258
1390
  if (sub === 'list' || sub === 'ls') {
@@ -1264,13 +1396,17 @@ async function handleServer() {
1264
1396
  if (sub === 'remove' || sub === 'rm' || sub === 'delete' || sub === 'disconnect') {
1265
1397
  return handleServerRemove(process.argv[4]);
1266
1398
  }
1399
+ if (sub === 'receipt-secret' || sub === 'secret') {
1400
+ return handleServerReceiptSecret(process.argv[4]);
1401
+ }
1267
1402
  console.log(`
1268
1403
  Usage: npx @mcpaid/sdk server <command>
1269
1404
 
1270
1405
  Commands:
1271
- add [config-path] Publish and monetize an MCP server on MCPaid Edge Gateway
1272
- list List all MCP servers registered under your account
1273
- remove <server-id> Disconnect and remove an MCP server from MCPaid network
1406
+ add [config-path] Publish and monetize an MCP server on MCPaid Edge Gateway
1407
+ list List all MCP servers registered under your account
1408
+ remove <server-id> Disconnect and remove an MCP server from MCPaid network
1409
+ receipt-secret <server-id> Retrieve or rotate Edge Receipt secret for backend verification (--rotate, --env)
1274
1410
  `);
1275
1411
  }
1276
1412
  async function handleWithdraw(amountArg) {