@pincerpay/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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +30 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/client.d.ts +28 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +60 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/index.d.ts +5 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +3 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/prompts/debug-transaction.d.ts +3 -0
  16. package/dist/prompts/debug-transaction.d.ts.map +1 -0
  17. package/dist/prompts/debug-transaction.js +31 -0
  18. package/dist/prompts/debug-transaction.js.map +1 -0
  19. package/dist/prompts/get-started.d.ts +3 -0
  20. package/dist/prompts/get-started.d.ts.map +1 -0
  21. package/dist/prompts/get-started.js +40 -0
  22. package/dist/prompts/get-started.js.map +1 -0
  23. package/dist/prompts/index.d.ts +3 -0
  24. package/dist/prompts/index.d.ts.map +1 -0
  25. package/dist/prompts/index.js +11 -0
  26. package/dist/prompts/index.js.map +1 -0
  27. package/dist/prompts/integrate-agent.d.ts +3 -0
  28. package/dist/prompts/integrate-agent.d.ts.map +1 -0
  29. package/dist/prompts/integrate-agent.js +41 -0
  30. package/dist/prompts/integrate-agent.js.map +1 -0
  31. package/dist/prompts/integrate-merchant.d.ts +3 -0
  32. package/dist/prompts/integrate-merchant.d.ts.map +1 -0
  33. package/dist/prompts/integrate-merchant.js +39 -0
  34. package/dist/prompts/integrate-merchant.js.map +1 -0
  35. package/dist/resources/chain-config.d.ts +3 -0
  36. package/dist/resources/chain-config.d.ts.map +1 -0
  37. package/dist/resources/chain-config.js +29 -0
  38. package/dist/resources/chain-config.js.map +1 -0
  39. package/dist/resources/docs.d.ts +3 -0
  40. package/dist/resources/docs.d.ts.map +1 -0
  41. package/dist/resources/docs.js +460 -0
  42. package/dist/resources/docs.js.map +1 -0
  43. package/dist/resources/index.d.ts +4 -0
  44. package/dist/resources/index.d.ts.map +1 -0
  45. package/dist/resources/index.js +9 -0
  46. package/dist/resources/index.js.map +1 -0
  47. package/dist/resources/openapi-spec.d.ts +4 -0
  48. package/dist/resources/openapi-spec.d.ts.map +1 -0
  49. package/dist/resources/openapi-spec.js +28 -0
  50. package/dist/resources/openapi-spec.js.map +1 -0
  51. package/dist/server.d.ts +18 -0
  52. package/dist/server.d.ts.map +1 -0
  53. package/dist/server.js +48 -0
  54. package/dist/server.js.map +1 -0
  55. package/dist/tools/check-transaction.d.ts +4 -0
  56. package/dist/tools/check-transaction.d.ts.map +1 -0
  57. package/dist/tools/check-transaction.js +50 -0
  58. package/dist/tools/check-transaction.js.map +1 -0
  59. package/dist/tools/estimate-gas.d.ts +3 -0
  60. package/dist/tools/estimate-gas.d.ts.map +1 -0
  61. package/dist/tools/estimate-gas.js +88 -0
  62. package/dist/tools/estimate-gas.js.map +1 -0
  63. package/dist/tools/generate-ucp.d.ts +3 -0
  64. package/dist/tools/generate-ucp.d.ts.map +1 -0
  65. package/dist/tools/generate-ucp.js +103 -0
  66. package/dist/tools/generate-ucp.js.map +1 -0
  67. package/dist/tools/index.d.ts +4 -0
  68. package/dist/tools/index.d.ts.map +1 -0
  69. package/dist/tools/index.js +19 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/tools/list-chains.d.ts +4 -0
  72. package/dist/tools/list-chains.d.ts.map +1 -0
  73. package/dist/tools/list-chains.js +56 -0
  74. package/dist/tools/list-chains.js.map +1 -0
  75. package/dist/tools/scaffold-agent.d.ts +3 -0
  76. package/dist/tools/scaffold-agent.d.ts.map +1 -0
  77. package/dist/tools/scaffold-agent.js +93 -0
  78. package/dist/tools/scaffold-agent.js.map +1 -0
  79. package/dist/tools/scaffold-middleware.d.ts +3 -0
  80. package/dist/tools/scaffold-middleware.d.ts.map +1 -0
  81. package/dist/tools/scaffold-middleware.js +160 -0
  82. package/dist/tools/scaffold-middleware.js.map +1 -0
  83. package/dist/tools/validate-config.d.ts +3 -0
  84. package/dist/tools/validate-config.d.ts.map +1 -0
  85. package/dist/tools/validate-config.js +105 -0
  86. package/dist/tools/validate-config.js.map +1 -0
  87. package/dist/transport/http.d.ts +7 -0
  88. package/dist/transport/http.d.ts.map +1 -0
  89. package/dist/transport/http.js +34 -0
  90. package/dist/transport/http.js.map +1 -0
  91. package/package.json +70 -0
@@ -0,0 +1,460 @@
1
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ const DOCS = {
3
+ "getting-started": {
4
+ title: "Getting Started with PincerPay",
5
+ content: `# Getting Started with PincerPay
6
+
7
+ PincerPay is an on-chain USDC payment gateway for AI agents using the x402 protocol (HTTP 402).
8
+ No card rails — pure stablecoin settlement on Solana (primary), Base, and Polygon.
9
+
10
+ ## Prerequisites
11
+
12
+ - Node.js 22+
13
+ - \`"type": "module"\` in your package.json — both SDKs are **ESM-only**. Without this, you'll get \`ERR_MODULE_NOT_FOUND\`.
14
+ - A USDC wallet (Solana or EVM) for receiving/sending payments
15
+
16
+ ## Choose Your Path
17
+
18
+ ### Merchant — Accept USDC payments from AI agents
19
+ You have an API and want to add payment walls so agents pay per request.
20
+
21
+ 1. **Install**: \`npm install @pincerpay/merchant\`
22
+ 2. **Get an API key**: Sign up at https://pincerpay.com/dashboard → Settings → API Keys (\`pp_live_...\`)
23
+ 3. **Generate code**: Use the \`scaffold-x402-middleware\` tool (supports Express, Hono, Next.js)
24
+ 4. **Validate config**: Use the \`validate-payment-config\` tool to check your setup
25
+ 5. **Add discovery**: Use the \`generate-ucp-manifest\` tool for agent discoverability
26
+
27
+ → Full guide: \`docs://pincerpay/merchant\`
28
+
29
+ ### Agent Developer — Build agents that pay for API access
30
+ You're building an AI agent that needs to automatically pay for paywalled APIs.
31
+
32
+ 1. **Install**: \`npm install @pincerpay/agent\`
33
+ 2. **Generate code**: Use the \`scaffold-agent-client\` tool with your chain and spending limits
34
+ 3. **Estimate costs**: Use the \`estimate-gas-cost\` tool to understand fees on your chain
35
+
36
+ → Full guide: \`docs://pincerpay/agent\`
37
+
38
+ ### Already Integrated? Troubleshooting
39
+ Use the \`debug-transaction\` prompt with your transaction hash, or see \`docs://pincerpay/troubleshooting\`.
40
+
41
+ ## Security Checklist
42
+ - Add \`.env*\` to \`.gitignore\` — **never commit API keys or private keys**
43
+ - Store wallet keys in environment variables, not source code
44
+ - Use \`pp_test_\` keys and devnet chains during development
45
+
46
+ ## Devnet vs Mainnet
47
+
48
+ | Environment | Chain Shorthand | Notes |
49
+ |-------------|----------------|-------|
50
+ | Development | \`"solana-devnet"\` | Free devnet USDC. Use Solana faucet for SOL. |
51
+ | Development | \`"base-sepolia"\` | Free testnet USDC via Circle faucet. |
52
+ | Production | \`"solana"\` | Real USDC on Solana mainnet. |
53
+ | Production | \`"base"\` | Real USDC on Base mainnet. |
54
+
55
+ **Both merchant and agent must use the same chain** (e.g., both on \`"solana-devnet"\`).
56
+
57
+ ## How It Works
58
+
59
+ 1. Merchant wraps API routes with PincerPay middleware
60
+ 2. Agent calls the API and receives HTTP 402 with payment challenge
61
+ 3. Agent SDK automatically signs a USDC transfer
62
+ 4. PincerPay facilitator verifies the signature and broadcasts the transaction
63
+ 5. Merchant delivers the protected resource
64
+
65
+ ## Supported Chains
66
+ - **Solana** (primary) — ~$0.00025 gas, 400ms block time
67
+ - **Base** (EVM) — ~$0.001-0.01 gas, 2s block time
68
+ - **Polygon** (EVM) — ~$0.001-0.005 gas, 2s block time
69
+
70
+ ## Key Concepts
71
+ - **Optimistic Finality**: Payments under $1 USDC are released after mempool broadcast (~200ms)
72
+ - **Gas Passthrough**: Agents pay gas costs in USDC (via Kora on Solana, meta-txns on EVM), not merchants
73
+ - **x402 Protocol**: HTTP 402-based payment challenges (Coinbase open standard)
74
+ - **Prices vs Policies**: Route \`price\` uses human-readable amounts ("0.01"), spending \`policies\` use base units ("10000")`,
75
+ },
76
+ merchant: {
77
+ title: "Merchant Integration Guide",
78
+ content: `# Merchant SDK Integration
79
+
80
+ ## Install
81
+
82
+ \`\`\`bash
83
+ npm install @pincerpay/merchant
84
+ \`\`\`
85
+
86
+ Sub-path imports are available for tree-shaking: \`@pincerpay/merchant/express\` and \`@pincerpay/merchant/hono\`.
87
+
88
+ ## Express Middleware
89
+
90
+ \`\`\`typescript
91
+ import express from "express";
92
+ import { pincerpay } from "@pincerpay/merchant/express";
93
+
94
+ const app = express();
95
+
96
+ app.use(
97
+ pincerpay({
98
+ apiKey: process.env.PINCERPAY_API_KEY!,
99
+ merchantAddress: "YOUR_SOLANA_WALLET_ADDRESS",
100
+ routes: {
101
+ "GET /api/weather": { price: "0.001", chain: "solana" },
102
+ "GET /api/premium": { price: "0.01", chain: "solana" },
103
+ },
104
+ })
105
+ );
106
+ \`\`\`
107
+
108
+ ## Hono Middleware
109
+
110
+ \`\`\`typescript
111
+ import { Hono } from "hono";
112
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
113
+
114
+ const app = new Hono();
115
+
116
+ app.use(
117
+ "*",
118
+ pincerpayHono({
119
+ apiKey: process.env.PINCERPAY_API_KEY!,
120
+ merchantAddress: "YOUR_SOLANA_WALLET_ADDRESS",
121
+ routes: {
122
+ "GET /api/weather": { price: "0.001", chain: "solana" },
123
+ },
124
+ })
125
+ );
126
+ \`\`\`
127
+
128
+ ## Next.js (Hono Adapter)
129
+
130
+ Next.js doesn't have native x402 middleware. Use Hono as a lightweight handler in a catch-all App Router route:
131
+
132
+ \`\`\`typescript
133
+ // app/api/[...route]/route.ts
134
+ import { Hono } from "hono";
135
+ import { handle } from "hono/vercel";
136
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
137
+
138
+ const app = new Hono().basePath("/api");
139
+
140
+ app.use("*", pincerpayHono({
141
+ apiKey: process.env.PINCERPAY_API_KEY!,
142
+ merchantAddress: "YOUR_SOLANA_WALLET_ADDRESS",
143
+ routes: {
144
+ "GET /api/weather": {
145
+ price: "0.01",
146
+ chain: "solana",
147
+ },
148
+ },
149
+ }));
150
+
151
+ app.get("/weather", (c) => {
152
+ return c.json({ forecast: "sunny", temp: 72 });
153
+ });
154
+
155
+ export const GET = handle(app);
156
+ export const POST = handle(app);
157
+ \`\`\`
158
+
159
+ **Notes:** \`basePath("/api")\` must match the catch-all location. Route handlers use paths relative to basePath (\`/weather\` → \`/api/weather\`). Install: \`npm install @pincerpay/merchant hono\`.
160
+
161
+ ## Multi-Chain Routes
162
+
163
+ Accept payments on multiple chains per route — agents auto-select the chain they have funds on:
164
+
165
+ \`\`\`typescript
166
+ routes: {
167
+ "GET /api/weather": {
168
+ price: "0.01",
169
+ chains: ["solana", "base", "polygon"],
170
+ },
171
+ }
172
+ \`\`\`
173
+
174
+ If neither \`chain\` nor \`chains\` is specified, defaults to \`"solana"\`.
175
+
176
+ ## Configuration
177
+
178
+ | Field | Required | Description |
179
+ |-------|----------|-------------|
180
+ | apiKey | Yes | Your PincerPay API key (\`pp_live_...\` or \`pp_test_...\`) |
181
+ | merchantAddress | Yes | Your USDC wallet address |
182
+ | facilitatorUrl | No | Custom facilitator URL (defaults to PincerPay hosted) |
183
+ | routes | Yes | Map of route patterns to paywall configs |
184
+
185
+ ## Route Config
186
+
187
+ | Field | Required | Description |
188
+ |-------|----------|-------------|
189
+ | price | Yes | USDC price as human-readable string (e.g., "0.01" = 1 cent) |
190
+ | chain | No | Chain shorthand (default: "solana") |
191
+ | chains | No | Array of chain shorthands for multi-chain support |
192
+ | description | No | Human-readable description shown in 402 response |
193
+
194
+ ## Utility: toBaseUnits
195
+
196
+ Convert human-readable USDC to base units (useful for spending policies):
197
+
198
+ \`\`\`typescript
199
+ import { toBaseUnits } from "@pincerpay/merchant";
200
+ toBaseUnits("0.01"); // → "10000"
201
+ toBaseUnits("1.00"); // → "1000000"
202
+ \`\`\``,
203
+ },
204
+ agent: {
205
+ title: "Agent Integration Guide",
206
+ content: `# Agent SDK Integration
207
+
208
+ ## Install
209
+
210
+ \`\`\`bash
211
+ npm install @pincerpay/agent
212
+ \`\`\`
213
+
214
+ No peer dependencies — transitive deps (\`@solana/kit\`, \`viem\`, \`@x402/*\`) install automatically.
215
+
216
+ ## Basic Usage
217
+
218
+ \`\`\`typescript
219
+ import { PincerPayAgent } from "@pincerpay/agent";
220
+
221
+ const agent = await PincerPayAgent.create({
222
+ chains: ["solana"],
223
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
224
+ });
225
+
226
+ // agent.fetch() is a drop-in replacement for fetch
227
+ const response = await agent.fetch("https://api.example.com/weather");
228
+ const data = await response.json();
229
+ \`\`\`
230
+
231
+ **Note:** \`PincerPayAgent.create()\` is async (required for Solana key derivation). For EVM-only agents, you can also use \`new PincerPayAgent(config)\` (synchronous).
232
+
233
+ ## With Spending Policies
234
+
235
+ **Important:** Spending policies use **base units** (6 decimals), NOT human-readable amounts. \`BigInt("0.10")\` will throw at runtime!
236
+
237
+ \`\`\`typescript
238
+ const agent = await PincerPayAgent.create({
239
+ chains: ["solana"],
240
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
241
+ // Spending policies use base units: 1 USDC = "1000000", $0.10 = "100000"
242
+ policies: [
243
+ {
244
+ maxPerTransaction: "100000", // $0.10 per API call
245
+ maxPerDay: "5000000", // $5.00 per day
246
+ },
247
+ ],
248
+ });
249
+ \`\`\`
250
+
251
+ | Human Amount | Base Units |
252
+ |-------------|------------|
253
+ | $0.01 | \`"10000"\` |
254
+ | $0.10 | \`"100000"\` |
255
+ | $1.00 | \`"1000000"\` |
256
+ | $10.00 | \`"10000000"\` |
257
+
258
+ Multiply human amount × 1,000,000 to get base units. Or use \`toBaseUnits("0.10")\` from \`@pincerpay/merchant\`.
259
+
260
+ ## Runtime Policy Management
261
+
262
+ \`\`\`typescript
263
+ // Pre-check if a payment would be allowed
264
+ const check = agent.checkPolicy("500000"); // 0.50 USDC
265
+ if (!check.allowed) console.log(check.reason);
266
+
267
+ // Update spending limits dynamically
268
+ agent.setPolicy({ maxPerTransaction: "5000000", maxPerDay: "50000000" });
269
+
270
+ // Monitor daily spending
271
+ const { date, amount } = agent.getDailySpend();
272
+ console.log(\`Spent \${amount} base units on \${date}\`);
273
+
274
+ // Get current policy
275
+ const policy = agent.getPolicy();
276
+ \`\`\`
277
+
278
+ ## Agent Properties
279
+
280
+ | Property | Description |
281
+ |----------|-------------|
282
+ | \`agent.fetch(url, init?)\` | Payment-enabled fetch — auto-handles 402 challenges |
283
+ | \`agent.solanaAddress\` | Agent's Solana public key (only available via \`.create()\`) |
284
+ | \`agent.evmAddress\` | Agent's EVM public address |
285
+ | \`agent.chains\` | Configured chain shorthands |
286
+ | \`agent.checkPolicy(amountBaseUnits)\` | Pre-check \`{ allowed, reason? }\` against spending limits |
287
+ | \`agent.setPolicy(policy)\` | Replace spending policy at runtime |
288
+ | \`agent.getPolicy()\` | Get current spending policy |
289
+ | \`agent.getDailySpend()\` | Get \`{ date: string, amount: bigint }\` for today's tracked spend |
290
+
291
+ ## How x402 Payment Flow Works
292
+
293
+ 1. \`agent.fetch(url)\` calls the merchant API
294
+ 2. Server returns HTTP 402 with \`X-Payment\` header (x402 challenge)
295
+ 3. Agent SDK extracts payment requirements (amount, chain, recipient)
296
+ 4. Agent signs a USDC transfer transaction
297
+ 5. PincerPay facilitator verifies + broadcasts the transaction
298
+ 6. Agent retries the original request with the payment proof
299
+ 7. Server validates payment and returns the protected resource
300
+
301
+ ## Multi-Chain Support
302
+
303
+ \`\`\`typescript
304
+ const agent = await PincerPayAgent.create({
305
+ chains: ["solana", "base"],
306
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
307
+ evmPrivateKey: process.env.AGENT_EVM_KEY!,
308
+ });
309
+ \`\`\`
310
+
311
+ The agent automatically selects the correct chain based on the merchant's 402 response.
312
+
313
+ ## Environment Variables
314
+
315
+ \`\`\`
316
+ AGENT_SOLANA_KEY=your_base58_private_key_here
317
+ # or for EVM:
318
+ AGENT_EVM_KEY=0xyour_hex_private_key_here
319
+ \`\`\`
320
+
321
+ **Never commit private keys.** Ensure \`.env*\` is in \`.gitignore\`.`,
322
+ },
323
+ troubleshooting: {
324
+ title: "Troubleshooting Common Issues",
325
+ content: `# Troubleshooting
326
+
327
+ ## Common Issues
328
+
329
+ | Symptom | Cause | Fix |
330
+ |---------|-------|-----|
331
+ | \`ERR_MODULE_NOT_FOUND\` | ESM import issues | Add \`"type": "module"\` to package.json or use \`.mts\` extension. Both \`@pincerpay/merchant\` and \`@pincerpay/agent\` are ESM-only. |
332
+ | \`SyntaxError: Cannot use import statement\` | CommonJS project importing ESM | Add \`"type": "module"\` to package.json. |
333
+ | 402 but no payment attempted | Chain mismatch | Agent and merchant must use the same chain (e.g., both \`"solana-devnet"\`). Check \`chains\` array. |
334
+ | \`Invalid base58 character\` | Wrong key format for Solana | Solana private keys are base58 (alphanumeric, no \`0x\` prefix). EVM keys are hex (\`0x...\`). |
335
+ | Payment succeeds but 402 persists | Facilitator URL mismatch | Both merchant and agent must use the same facilitator. Default: \`https://facilitator.pincerpay.com\`. |
336
+ | \`Exceeds per-transaction limit\` | Spending policy too restrictive | Increase \`maxPerTransaction\` — value is in **base units** (6 decimals). \`"1000000"\` = $1.00 USDC. |
337
+ | \`BigInt("0.10")\` throws | Human-readable amount in policy | Policies use base units, not human amounts. Use \`"100000"\` not \`"0.10"\` for $0.10. |
338
+ | \`At least one wallet key required\` | No private key configured | Set \`solanaPrivateKey\` or \`evmPrivateKey\` in agent config. Check \`.env\` is loaded. |
339
+ | Route not matching for 402 | Wrong route pattern format | Pattern must be \`"METHOD /path"\` — e.g., \`"GET /api/weather"\`. Uppercase method, space, leading slash. |
340
+ | \`pp_live_\` key on devnet | API key environment mismatch | Use \`pp_test_\` keys for devnet chains. |
341
+
342
+ ## Devnet Funding
343
+
344
+ - **Solana devnet SOL**: https://faucet.solana.com
345
+ - **Solana devnet USDC**: Request from PincerPay team or use a devnet DEX
346
+ - **Base Sepolia ETH**: Base Sepolia faucet
347
+ - **Base Sepolia USDC**: Circle testnet USDC faucet
348
+
349
+ ## Debugging Tips
350
+
351
+ 1. **Verify 402 response**: \`curl -s -w "\\nHTTP Status: %{http_code}\\n" http://localhost:3000/api/endpoint\` — should return 402 with \`paymentRequirements\` JSON
352
+ 2. **Check chain match**: Both merchant route config and agent \`chains\` array must use identical chain shorthands
353
+ 3. **Test agent fetch**: \`const response = await agent.fetch(url); console.log(response.status);\` — should be 200 after payment
354
+ 4. **Inspect spending**: \`console.log(agent.getDailySpend())\` to see current daily spend tracking
355
+ 5. **Validate config**: Use the \`validate-payment-config\` MCP tool to check your merchant config for errors`,
356
+ },
357
+ reference: {
358
+ title: "API Reference",
359
+ content: `# PincerPay Reference
360
+
361
+ ## Chain Shorthands
362
+
363
+ | Shorthand | Network | CAIP-2 ID | Notes |
364
+ |-----------|---------|-----------|-------|
365
+ | \`solana\` | Solana Mainnet | \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\` | Primary chain, default |
366
+ | \`solana-devnet\` | Solana Devnet | \`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\` | Solana testnet |
367
+ | \`base\` | Base Mainnet | \`eip155:8453\` | EVM, low fees |
368
+ | \`base-sepolia\` | Base Sepolia | \`eip155:84532\` | EVM testnet |
369
+ | \`polygon\` | Polygon Mainnet | \`eip155:137\` | EVM |
370
+ | \`polygon-amoy\` | Polygon Amoy | \`eip155:80002\` | Polygon testnet |
371
+
372
+ ## USDC Amounts (6 Decimals)
373
+
374
+ Route \`price\` fields use human-readable strings. Spending \`policies\` use base unit strings.
375
+
376
+ | Human Amount | Base Units | Route \`price\` | Policy value |
377
+ |-------------|------------|---------------|--------------|
378
+ | $0.001 | 1,000 | \`"0.001"\` | \`"1000"\` |
379
+ | $0.01 | 10,000 | \`"0.01"\` | \`"10000"\` |
380
+ | $0.10 | 100,000 | \`"0.10"\` | \`"100000"\` |
381
+ | $1.00 | 1,000,000 | \`"1.00"\` | \`"1000000"\` |
382
+ | $10.00 | 10,000,000 | \`"10.00"\` | \`"10000000"\` |
383
+ | $100.00 | 100,000,000 | \`"100.00"\` | \`"100000000"\` |
384
+
385
+ Convert: multiply human amount × 1,000,000. Or use \`toBaseUnits("0.01")\` from \`@pincerpay/merchant\`.
386
+
387
+ ## Package Exports
388
+
389
+ | Package | Key Exports |
390
+ |---------|-------------|
391
+ | \`@pincerpay/merchant\` | \`pincerpay\` (Express), \`pincerpayHono\` (Hono), \`PincerPayClient\` (low-level), \`toBaseUnits\`, \`resolveRouteChains\`, \`getUsdcAsset\` |
392
+ | \`@pincerpay/merchant/express\` | \`pincerpay\` (tree-shakeable sub-path import) |
393
+ | \`@pincerpay/merchant/hono\` | \`pincerpayHono\` (tree-shakeable sub-path import) |
394
+ | \`@pincerpay/agent\` | \`PincerPayAgent\` (main agent class), \`SolanaSmartAgent\` (Squads session keys — advanced) |
395
+ | \`@pincerpay/core\` | \`PincerPayConfig\`, \`AgentConfig\`, \`SpendingPolicy\`, \`RoutePaywallConfig\`, \`ChainConfig\` (types) |
396
+
397
+ ## PincerPayClient Methods (Low-Level)
398
+
399
+ For advanced users building custom middleware:
400
+
401
+ | Method | Description |
402
+ |--------|-------------|
403
+ | \`verify(paymentPayload, paymentRequirements)\` | Verify a raw x402 payment payload |
404
+ | \`settle(paymentPayload, paymentRequirements)\` | Settle a verified payment on-chain |
405
+ | \`getSupported()\` | Get supported schemes/networks from the facilitator |
406
+ | \`getStatus(txHash)\` | Get transaction status by hash |
407
+
408
+ Most users should use \`pincerpay()\` or \`pincerpayHono()\` middleware instead.
409
+
410
+ ## PincerPayAgent Properties & Methods
411
+
412
+ | Member | Description |
413
+ |--------|-------------|
414
+ | \`agent.fetch(url, init?)\` | Payment-enabled fetch — auto-handles 402 challenges |
415
+ | \`agent.solanaAddress\` | Agent's Solana public key (only via \`.create()\`) |
416
+ | \`agent.evmAddress\` | Agent's EVM public address |
417
+ | \`agent.chains\` | Configured chain shorthands |
418
+ | \`agent.checkPolicy(amountBaseUnits)\` | Pre-check \`{ allowed, reason? }\` against spending limits |
419
+ | \`agent.setPolicy(policy)\` | Replace spending policy at runtime |
420
+ | \`agent.getPolicy()\` | Get current spending policy |
421
+ | \`agent.getDailySpend()\` | Get \`{ date: string, amount: bigint }\` for today's tracked spend |
422
+
423
+ ## Route Pattern Format
424
+
425
+ Route patterns must follow this format: \`"METHOD /path"\`
426
+
427
+ - **Method**: Uppercase HTTP method (GET, POST, PUT, DELETE, PATCH)
428
+ - **Space**: Single space between method and path
429
+ - **Path**: Must start with \`/\`
430
+
431
+ Examples: \`"GET /api/weather"\`, \`"POST /api/submit"\`, \`"GET /api/data/:id"\``,
432
+ },
433
+ };
434
+ export function registerDocsResources(server) {
435
+ const topics = Object.keys(DOCS);
436
+ server.resource("docs", new ResourceTemplate("docs://pincerpay/{topic}", {
437
+ list: async () => ({
438
+ resources: topics.map((key) => ({
439
+ uri: `docs://pincerpay/${key}`,
440
+ name: DOCS[key].title,
441
+ mimeType: "text/markdown",
442
+ })),
443
+ }),
444
+ }), async (uri, { topic }) => {
445
+ const doc = DOCS[topic];
446
+ if (!doc) {
447
+ throw new Error(`Unknown doc topic: "${topic}". Available: ${topics.join(", ")}`);
448
+ }
449
+ return {
450
+ contents: [
451
+ {
452
+ uri: uri.href,
453
+ text: doc.content,
454
+ mimeType: "text/markdown",
455
+ },
456
+ ],
457
+ };
458
+ });
459
+ }
460
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/resources/docs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAE3E,MAAM,IAAI,GAAuD;IAC/D,iBAAiB,EAAE;QACjB,KAAK,EAAE,gCAAgC;QACvC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+HAqEkH;KAC5H;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,4BAA4B;QACnC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4HN;KACJ;IACD,KAAK,EAAE;QACL,KAAK,EAAE,yBAAyB;QAChC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sEAmHyD;KACnE;IACD,eAAe,EAAE;QACf,KAAK,EAAE,+BAA+B;QACtC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8GA8BiG;KAC3G;IACD,SAAS,EAAE;QACT,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAwEqE;KAC/E;CACF,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,MAAM,CAAC,QAAQ,CACb,MAAM,EACN,IAAI,gBAAgB,CAAC,0BAA0B,EAAE;QAC/C,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC9B,GAAG,EAAE,oBAAoB,GAAG,EAAE;gBAC9B,IAAI,EAAE,IAAI,CAAC,GAAG,CAAE,CAAC,KAAK;gBACtB,QAAQ,EAAE,eAAwB;aACnC,CAAC,CAAC;SACJ,CAAC;KACH,CAAC,EACF,KAAK,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAe,CAAC,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,uBAAuB,KAAK,iBAAiB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjE,CAAC;QACJ,CAAC;QACD,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,IAAI,EAAE,GAAG,CAAC,OAAO;oBACjB,QAAQ,EAAE,eAAe;iBAC1B;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { FacilitatorClient } from "../client.js";
3
+ export declare function registerResources(server: McpServer, client: FacilitatorClient): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKtD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,iBAAiB,QAK1B"}
@@ -0,0 +1,9 @@
1
+ import { registerChainResources } from "./chain-config.js";
2
+ import { registerOpenApiResource } from "./openapi-spec.js";
3
+ import { registerDocsResources } from "./docs.js";
4
+ export function registerResources(server, client) {
5
+ registerChainResources(server);
6
+ registerOpenApiResource(server, client);
7
+ registerDocsResources(server);
8
+ }
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,UAAU,iBAAiB,CAC/B,MAAiB,EACjB,MAAyB;IAEzB,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { FacilitatorClient } from "../client.js";
3
+ export declare function registerOpenApiResource(server: McpServer, client: FacilitatorClient): void;
4
+ //# sourceMappingURL=openapi-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-spec.d.ts","sourceRoot":"","sources":["../../src/resources/openapi-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,iBAAiB,QA8B1B"}
@@ -0,0 +1,28 @@
1
+ export function registerOpenApiResource(server, client) {
2
+ server.resource("openapi-spec", "pincerpay://openapi", async (uri) => {
3
+ try {
4
+ const spec = await client.getOpenApiSpec();
5
+ return {
6
+ contents: [
7
+ {
8
+ uri: uri.href,
9
+ text: JSON.stringify(spec, null, 2),
10
+ mimeType: "application/json",
11
+ },
12
+ ],
13
+ };
14
+ }
15
+ catch (err) {
16
+ return {
17
+ contents: [
18
+ {
19
+ uri: uri.href,
20
+ text: `Failed to fetch OpenAPI spec: ${err instanceof Error ? err.message : String(err)}`,
21
+ mimeType: "text/plain",
22
+ },
23
+ ],
24
+ };
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=openapi-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-spec.js","sourceRoot":"","sources":["../../src/resources/openapi-spec.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAAyB;IAEzB,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,qBAAqB,EACrB,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;YAC3C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;wBACnC,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,iCAAiC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;wBACzF,QAAQ,EAAE,YAAY;qBACvB;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface PincerPayMcpConfig {
3
+ /** PincerPay API key (pp_live_... or pp_test_...) */
4
+ apiKey?: string;
5
+ /** Facilitator URL (defaults to https://facilitator.pincerpay.com) */
6
+ facilitatorUrl?: string;
7
+ }
8
+ /**
9
+ * Create a configured PincerPay MCP server with all tools,
10
+ * resources, and prompts registered.
11
+ *
12
+ * Tools that don't require auth (scaffolding, gas estimates,
13
+ * chain listing) work without an API key. Operations tools
14
+ * (transaction status) require a key and return a helpful error
15
+ * if none is configured.
16
+ */
17
+ export declare function createPincerPayMcpServer(config?: PincerPayMcpConfig): McpServer;
18
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,GAAE,kBAAuB,aAuCvE"}
package/dist/server.js ADDED
@@ -0,0 +1,48 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FacilitatorClient } from "./client.js";
3
+ import { registerTools } from "./tools/index.js";
4
+ import { registerResources } from "./resources/index.js";
5
+ import { registerPrompts } from "./prompts/index.js";
6
+ /**
7
+ * Create a configured PincerPay MCP server with all tools,
8
+ * resources, and prompts registered.
9
+ *
10
+ * Tools that don't require auth (scaffolding, gas estimates,
11
+ * chain listing) work without an API key. Operations tools
12
+ * (transaction status) require a key and return a helpful error
13
+ * if none is configured.
14
+ */
15
+ export function createPincerPayMcpServer(config = {}) {
16
+ const server = new McpServer({
17
+ name: "pincerpay",
18
+ version: "0.1.0",
19
+ }, {
20
+ instructions: "PincerPay is an on-chain USDC payment gateway for AI agents — no card rails, " +
21
+ "pure stablecoin settlement via the x402 protocol (HTTP 402). Solana is the primary " +
22
+ "chain; Base and Polygon are optional EVM alternatives.\n\n" +
23
+ "ROLE ROUTING: When a user wants to integrate PincerPay, first determine their role:\n" +
24
+ "- Merchant (accept payments): use the `integrate-merchant` prompt → scaffold-x402-middleware → validate-payment-config → generate-ucp-manifest\n" +
25
+ "- Agent developer (make payments): use the `integrate-agent` prompt → scaffold-agent-client → estimate-gas-cost\n" +
26
+ "- Unclear: use the `get-started` prompt to triage\n" +
27
+ "- Debugging: use the `debug-transaction` prompt\n\n" +
28
+ "KEY GOTCHAS to always warn about:\n" +
29
+ "1. Route `price` uses human-readable USDC (\"0.01\"), but spending `policies` use base units with 6 decimals (\"10000\" = $0.01). Using \"0.10\" in a policy causes BigInt() to throw.\n" +
30
+ "2. ESM required: \"type\": \"module\" in package.json — SDKs are ESM-only.\n" +
31
+ "3. Security: .gitignore must include .env* — never commit API keys or private keys.\n" +
32
+ "4. Use devnet chains for testing (solana-devnet, base-sepolia).\n\n" +
33
+ "Docs resources: docs://pincerpay/getting-started, docs://pincerpay/merchant, " +
34
+ "docs://pincerpay/agent, docs://pincerpay/troubleshooting, docs://pincerpay/reference.",
35
+ capabilities: {
36
+ logging: {},
37
+ },
38
+ });
39
+ const client = new FacilitatorClient({
40
+ apiKey: config.apiKey,
41
+ facilitatorUrl: config.facilitatorUrl,
42
+ });
43
+ registerTools(server, client);
44
+ registerResources(server, client);
45
+ registerPrompts(server);
46
+ return server;
47
+ }
48
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AASrD;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAA6B,EAAE;IACtE,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EACV,+EAA+E;YAC/E,qFAAqF;YACrF,4DAA4D;YAC5D,uFAAuF;YACvF,kJAAkJ;YAClJ,mHAAmH;YACnH,qDAAqD;YACrD,qDAAqD;YACrD,qCAAqC;YACrC,0LAA0L;YAC1L,8EAA8E;YAC9E,uFAAuF;YACvF,qEAAqE;YACrE,+EAA+E;YAC/E,uFAAuF;QACzF,YAAY,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ;KACF,CACF,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { FacilitatorClient } from "../client.js";
3
+ export declare function registerCheckTransaction(server: McpServer, client: FacilitatorClient): void;
4
+ //# sourceMappingURL=check-transaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-transaction.d.ts","sourceRoot":"","sources":["../../src/tools/check-transaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAWtD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,iBAAiB,QA8C1B"}
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ const inputSchema = {
3
+ txHash: z
4
+ .string()
5
+ .min(1)
6
+ .describe("Transaction hash (EVM hex) or signature (Solana base58) to look up."),
7
+ };
8
+ export function registerCheckTransaction(server, client) {
9
+ server.tool("check-transaction-status", "Query the PincerPay facilitator for the status of a payment transaction. " +
10
+ "Returns chain, amount, addresses, status (pending/mempool/optimistic/confirmed/failed), " +
11
+ "and timestamps. Requires a PincerPay API key.", inputSchema, async ({ txHash }) => {
12
+ try {
13
+ client.requireAuth();
14
+ }
15
+ catch (err) {
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: err instanceof Error ? err.message : String(err),
21
+ },
22
+ ],
23
+ isError: true,
24
+ };
25
+ }
26
+ try {
27
+ const result = await client.getStatus(txHash);
28
+ return {
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: JSON.stringify(result, null, 2),
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ catch (err) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `Failed to fetch transaction status: ${err instanceof Error ? err.message : String(err)}`,
43
+ },
44
+ ],
45
+ isError: true,
46
+ };
47
+ }
48
+ });
49
+ }
50
+ //# sourceMappingURL=check-transaction.js.map