mpp32-mcp-server 1.7.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -4,6 +4,37 @@ All notable changes to `mpp32-mcp-server` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
5
5
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.8.0] - 2026-07-14
8
+
9
+ ### Fixed
10
+
11
+ * **Tempo payments now actually work.** `completeTempoPayment` called
12
+ `client.pay(...)`, a method that does not exist on the mppx client —
13
+ every Tempo payment attempt threw `client.pay is not a function` before
14
+ a transaction was ever signed. The signer now uses the real mppx API:
15
+ `Mppx.create({ methods: [tempo({ account })], polyfill: false })
16
+ .createCredential(response)`, driven by the raw `WWW-Authenticate`
17
+ challenge header. Verified end-to-end against Tempo Mainnet (chain 4217):
18
+ the client parses the live challenge, signs a TIP-20 pathUSD transfer,
19
+ and the backend's on-chain verification accepts/rejects it correctly.
20
+ * **Authorization header format.** mppx credentials serialize as the full
21
+ `Payment <base64url>` header value; the old code re-prefixed it, producing
22
+ the invalid `Payment Payment <…>`. The credential is now set verbatim.
23
+ * **No more fetch polyfill side effect.** `Mppx.create` polyfills
24
+ `globalThis.fetch` by default; the signer now passes `polyfill: false` so
25
+ the MCP server's own fetch is never wrapped.
26
+
27
+ ### Changed
28
+
29
+ * Tempo (pathUSD) is now enabled in MPP32 production alongside x402 on
30
+ Solana and Base — `MPP32_PRIVATE_KEY` (0x-prefixed EVM key) pays both
31
+ x402-on-Base and Tempo challenges automatically.
32
+ * **`mppx` promoted from optional peer dependency to a pinned direct
33
+ dependency (`0.4.12`).** With Tempo live in production, an `npx` user
34
+ must never hit "Tempo payment client not available. Install: npm install
35
+ mppx viem" — the signer now works out of the box. Adds mppx's five
36
+ transitive dependencies; `viem` was already bundled.
37
+
7
38
  ## [1.7.0] - 2026-06-07
8
39
 
9
40
  ### Changed
package/README.md CHANGED
@@ -17,16 +17,23 @@ One install. Pay any x402 endpoint on Solana from your agent. Browse a federated
17
17
  |:-----|:-------|:--------|:------|
18
18
  | x402 | Production | Solana (mainnet) | USDC |
19
19
  | x402 | Production | Base | USDC |
20
- | Tempo | Envelope wired, gated off in production until the client flow is verified end to end | Ethereum L2 | pathUSD |
21
- | ACP / AP2 / AGTP | Envelopes wired, gated off in production | Multi chain | per protocol |
20
+ | Tempo | Production | Tempo (mainnet, chain 4217) | pathUSD |
21
+ | AP2 / AGTP | Production (authorization and identity layers) | Chain agnostic | per protocol |
22
+ | ACP | Envelope wired, gated off in production | Multi chain | checkout session |
22
23
 
23
- The MCP server ships signers for both Solana and Base out of the box. When a paid call returns a 402, the server picks the network that matches the key you configured and settles the payment in one round trip.
24
+ The MCP server ships signers for Solana, Base, and Tempo out of the box. When a paid call returns a 402, the server picks the rail that matches the key you configured and settles the payment in one round trip. `MPP32_SOLANA_PRIVATE_KEY` pays x402 on Solana; `MPP32_PRIVATE_KEY` (0x-prefixed EVM key) pays x402 on Base and Tempo pathUSD challenges.
24
25
 
25
- ## Try it free first (no keys, no setup)
26
+ ## Free Tier: 10 calls/day, no wallet required
26
27
 
27
- The MCP server exposes a **`try_solana_token_intelligence_free`** tool that returns the full Intelligence Oracle payload (alpha score, rug risk, whale activity, smart money signals, 24h pump probability, market data) for any Solana token with **zero configuration** — no `MPP32_AGENT_KEY`, no Solana key, no payment. Rate-limited to 10 calls/minute per IP. Use it to evaluate the oracle, then switch to `get_solana_token_intelligence` for unlimited attributed usage at $0.008/query (M32 holders save up to 40%).
28
+ Every agent session gets **10 free Intelligence Oracle calls per day** no wallet, no USDC, no payment setup. Just set `MPP32_AGENT_KEY` (free, instant, no signup at [mpp32.org/agent-console](https://mpp32.org/agent-console)) and start calling `get_solana_token_intelligence`. Free tier resets at midnight UTC.
28
29
 
29
- Just install the server and ask your agent: _"Use mpp32 to get a free intelligence preview for SOL."_
30
+ This lets you **test your full MCP integration end-to-end** before committing any crypto. Build working prototypes, evaluate the data quality, and ship to production the free tier covers typical development and light usage indefinitely.
31
+
32
+ After free tier: $0.008/query paid via x402 (USDC on Solana). M32 holders save up to 40%.
33
+
34
+ ### Quick anonymous test (no keys at all)
35
+
36
+ The **`try_solana_token_intelligence_free`** tool returns the same payload with zero configuration — just install and call. Rate-limited to 10/minute per IP. Good for a quick taste, but the 10/day free tier with an agent key is better for real work.
30
37
 
31
38
  ## Why this beats running your own integrations
32
39
 
@@ -257,7 +264,7 @@ Sessions are scoped, revocable, and rotate cleanly. The key is hashed at rest on
257
264
 
258
265
  x402 payments are verified on chain through the Solana facilitator (for SVM) or the Base facilitator (for EVM). MPP32 never holds custody of funds. Every paid call settles directly from the caller's wallet to the provider's wallet.
259
266
 
260
- Tempo, ACP, AP2, and AGTP envelopes are implemented in the proxy and tested against synthetic challenges, but the corresponding client signing flows are not yet exposed by this MCP. Those rails stay disabled in production until each has a verified end to end client flow. Treat the catalog as an x402 catalog today; the rest will light up as their clients land.
267
+ Tempo payments are verified on chain by the proxy's mppx integration: the client signs a TIP-20 pathUSD transfer against the live challenge and the server confirms the transfer on Tempo mainnet before releasing the response. AP2 and AGTP run as live authorization and identity layers on every paid route. The ACP envelope is implemented and tested against synthetic challenges but stays disabled in production until its checkout-session client flow is verified end to end.
261
268
 
262
269
  ## For API providers
263
270
 
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
5
  import { signX402Payment } from "./x402-signers.js";
6
- const SERVER_VERSION = "1.7.0";
6
+ const SERVER_VERSION = "1.8.0";
7
7
  // ── Env loading: trim and sanitize aggressively ─────────────────────────────
8
8
  // Copy-paste from Claude Desktop / Cursor / Windsurf JSON config UIs frequently
9
9
  // adds trailing \n, \r, NBSP, BOM, or wraps the value in literal quotes. Any
@@ -171,7 +171,11 @@ const server = new McpServer({
171
171
  version: SERVER_VERSION,
172
172
  });
173
173
  function buildHeaders(extra = {}) {
174
- const headers = {};
174
+ const headers = {
175
+ // Identifies this surface to the backend's usage tracking so MCP traffic
176
+ // can be measured separately from web/SDK/direct-API traffic.
177
+ "X-MPP32-Client": `mcp-server/${SERVER_VERSION}`,
178
+ };
175
179
  for (const [k, v] of Object.entries(extra)) {
176
180
  headers[k] = safeHeaderValue(k, v);
177
181
  }
@@ -181,6 +185,12 @@ function buildHeaders(extra = {}) {
181
185
  return headers;
182
186
  }
183
187
  function isHttpCallable(svc) {
188
+ // Prefer the server's authoritative `callable` flag when provided. The server
189
+ // knows things the URL cannot tell us — e.g. a native service that hasn't
190
+ // completed endpoint verification (the proxy will 403 it) or an M32
191
+ // token-gated service that needs an on-chain balance proof.
192
+ if (typeof svc.callable === "boolean")
193
+ return svc.callable;
184
194
  if (svc.source === "native")
185
195
  return true;
186
196
  const url = svc.endpointUrl ?? "";
@@ -190,6 +200,21 @@ function isHttpCallable(svc) {
190
200
  return false;
191
201
  return /^https?:\/\//.test(url);
192
202
  }
203
+ // Human-readable explanation for why a service is not callable through this MCP.
204
+ function notCallableLabel(svc) {
205
+ switch (svc.callableReason) {
206
+ case "pending_verification":
207
+ return "No — provider hasn't completed endpoint verification yet";
208
+ case "m32_token_gated":
209
+ return svc.m32Required
210
+ ? `Token-gated — hold ${svc.m32Required.toLocaleString()}+ M32 and use the dedicated tool`
211
+ : "Token-gated — requires M32 holdings via the dedicated tool";
212
+ case "listing_only":
213
+ return "No — listing only";
214
+ default:
215
+ return "No — listing only";
216
+ }
217
+ }
193
218
  // ── Tool 0: get_mpp32_diagnostics ───────────────────────────────────────────
194
219
  // Lets the user (and Claude) see exactly what the MCP process detected at
195
220
  // startup. The single most common failure mode is "I set the env var but it
@@ -253,7 +278,8 @@ server.tool("get_mpp32_diagnostics", "Report what the mpp32-mcp-server detected
253
278
  `- x402 (USDC on Base/EVM) payment: ${PRIVATE_KEY ? "yes" : "no — set MPP32_PRIVATE_KEY"}`,
254
279
  `- M32 holder pricing (SIWS verified): ${siwsVerifiedAddress ? `yes — ${siwsTier} tier, ${siwsDiscountPercent}% off every paid query` : (AGENT_KEY && SOLANA_PRIVATE_KEY ? "pending — auto verification runs once at startup" : "no — set MPP32_AGENT_KEY + MPP32_SOLANA_PRIVATE_KEY")}`,
255
280
  ``,
256
- `**Ready to pay end-to-end:** ${readyToPay ? "YES — try `get_solana_token_intelligence` with token=\"M32\" to confirm." : "NO see the missing items above. Meanwhile, you can still call `try_solana_token_intelligence_free` (10/min/IP, no keys required) to evaluate the oracle."}`,
281
+ `**Ready to use:** ${AGENT_KEY ? "YES — you have 10 FREE Intelligence Oracle calls/day. Try `get_solana_token_intelligence` with token=\"M32\" now." : "SET MPP32_AGENT_KEY to get 10 FREE calls/day. Get one at " + API_URL + "/agent-console."}`,
282
+ `**Ready to pay (after free tier):** ${readyToPay ? "YES — x402 signing configured." : "NO — set MPP32_SOLANA_PRIVATE_KEY (or MPP32_PRIVATE_KEY for EVM) to pay after free tier exhausted."}`,
257
283
  ``,
258
284
  `**If a variable shows NOT SET but you set it in claude_desktop_config.json:**`,
259
285
  `1. Confirm the file path Claude Desktop actually reads:`,
@@ -370,7 +396,7 @@ server.tool("list_mpp32_services", "Browse the MPP32 federated catalog of 4,500+
370
396
  `- **Category:** ${s.category ?? "—"}`,
371
397
  `- **Price:** ${priceLabel}`,
372
398
  `- **Protocols:** ${protos}`,
373
- `- **Callable via this MCP:** ${callable ? "Yes — use `call_mpp32_endpoint`" : "No — listing only"}`,
399
+ `- **Callable via this MCP:** ${callable ? "Yes — use `call_mpp32_endpoint`" : notCallableLabel(s)}`,
374
400
  s.description ? `- **Description:** ${s.description}` : null,
375
401
  s.endpointUrl && !callable ? `- **Install / direct URL:** \`${s.endpointUrl}\`` : null,
376
402
  s.websiteUrl ? `- **Website:** ${s.websiteUrl}` : null,
@@ -451,7 +477,7 @@ server.tool("call_mpp32_endpoint", "Call any HTTP-callable service in the MPP32
451
477
  return await callViaLegacyProxy(slug, method, parsedBody, query, path);
452
478
  });
453
479
  // ── Tool 3: get_solana_token_intelligence ───────────────────────────────────
454
- server.tool("get_solana_token_intelligence", "Get real-time Solana token intelligence from the MPP32 Intelligence Oracle. Returns alpha score (0-100), rug risk assessment, whale activity, smart money signals, 24h pump probability, projected ROI ranges, and aggregated DexScreener/Jupiter/CoinGecko market data. Costs $0.008 per query, paid automatically via x402 (USDC on Solana) or Tempo (pathUSD on Eth L2). M32 token holders receive up to 40% discount once their wallet is signature-verified. Set MPP32_AGENT_KEY in config to attribute calls to your dashboard. **New users with no keys configured: call `try_solana_token_intelligence_free` first** — it returns the same payload, rate-limited to 10/min, no payment or key required.", {
480
+ server.tool("get_solana_token_intelligence", "Get real-time Solana token intelligence from the MPP32 Intelligence Oracle. Returns alpha score (0-100), rug risk assessment, whale activity, smart money signals, 24h pump probability, projected ROI ranges, and aggregated DexScreener/Jupiter/CoinGecko market data. **FREE TIER: Every agent session gets 10 free calls per day no wallet, no USDC, no payment setup required.** Just set MPP32_AGENT_KEY. After free tier: $0.008/query paid via x402 (USDC on Solana). M32 token holders receive up to 40% discount.", {
455
481
  token: z
456
482
  .string()
457
483
  .describe("Solana token mint address or ticker symbol (e.g. SOL, BONK, JUP, M32, or full base58 address)."),
@@ -473,7 +499,7 @@ server.tool("get_solana_token_intelligence", "Get real-time Solana token intelli
473
499
  // trying MPP32 — they see real alpha scores and signals BEFORE encountering
474
500
  // any payment wall. This is the conversion funnel fix: agents today bounce
475
501
  // off the 402, so we let them taste the product first.
476
- server.tool("try_solana_token_intelligence_free", "FREE preview of the MPP32 Intelligence Oracle. No payment, no agent key, no Solana private key required. Returns the SAME payload as the paid endpoint (alpha score, rug risk, whale activity, smart money signals, pump probability, market data) for any Solana token. Rate-limited to 10 calls/minute per IP. Use this to evaluate the data quality. Once you're convinced, set MPP32_AGENT_KEY + a payment key and switch to `get_solana_token_intelligence` for unlimited, attributed usage and M32-holder discounts.", {
502
+ server.tool("try_solana_token_intelligence_free", "FREE preview of the MPP32 Intelligence Oracle quick anonymous test, no keys required. Rate-limited to 10 calls/minute per IP. Returns the same payload as the paid endpoint. **Better option: get an MPP32_AGENT_KEY from mpp32.org/agent-console and call `get_solana_token_intelligence` instead you get 10 FREE attributed calls per day, plus dashboard tracking, before any payment is needed.**", {
477
503
  token: z
478
504
  .string()
479
505
  .describe("Solana token mint address or ticker symbol (e.g. SOL, BONK, JUP, M32, or full base58 address)."),
@@ -481,7 +507,7 @@ server.tool("try_solana_token_intelligence_free", "FREE preview of the MPP32 Int
481
507
  try {
482
508
  const res = await fetchWithTimeout(`${API_URL}/api/intelligence/demo`, {
483
509
  method: "POST",
484
- headers: { "Content-Type": "application/json" },
510
+ headers: buildHeaders({ "Content-Type": "application/json" }),
485
511
  body: JSON.stringify({ token }),
486
512
  });
487
513
  const text = await res.text();
@@ -496,7 +522,7 @@ server.tool("try_solana_token_intelligence_free", "FREE preview of the MPP32 Int
496
522
  return {
497
523
  content: [{
498
524
  type: "text",
499
- text: `Demo rate limit reached (10 calls/minute per IP). Wait a minute and retry, or set up paid access for unlimited queries:\n\n1. Get an agent key: ${API_URL}/agent-console\n2. Add MPP32_AGENT_KEY + MPP32_SOLANA_PRIVATE_KEY to your MCP config\n3. Call \`get_solana_token_intelligence\` instead $0.008/query, M32 holders save up to 40%.`,
525
+ text: `Demo rate limit reached (10 calls/minute per IP). **Better option:** Get a free agent key at ${API_URL}/agent-console 10 FREE attributed calls/day with dashboard tracking, no payment setup required. After free tier, $0.008/query.`,
500
526
  }],
501
527
  };
502
528
  }
@@ -635,7 +661,7 @@ server.tool("scan_portfolio_m32", "M32-gated full wallet portfolio scan. Discove
635
661
  async function fetchPivxGovernance() {
636
662
  const res = await fetchWithTimeout(`${API_URL}/api/governance`, {
637
663
  timeoutMs: 15_000,
638
- headers: { Accept: "application/json" },
664
+ headers: buildHeaders({ Accept: "application/json" }),
639
665
  });
640
666
  if (!res.ok) {
641
667
  throw new Error(`MPP32 governance endpoint returned HTTP ${res.status}`);
@@ -916,10 +942,9 @@ async function signAndRetry(execUrl, reqBody, challenge) {
916
942
  catch (err) {
917
943
  // Fall through to Tempo if available
918
944
  if (challenge.wwwAuthenticate && PRIVATE_KEY) {
919
- const parsed = parseWwwAuthenticate(challenge.wwwAuthenticate);
920
945
  try {
921
- const token = await completeTempoPayment(parsed.params, PRIVATE_KEY);
922
- paymentHeaders["Authorization"] = `Payment ${token}`;
946
+ const token = await completeTempoPayment(challenge.wwwAuthenticate, PRIVATE_KEY);
947
+ paymentHeaders["Authorization"] = token;
923
948
  usedProtocol = "pathUSD (Tempo)";
924
949
  }
925
950
  catch (tempoErr) {
@@ -944,8 +969,8 @@ async function signAndRetry(execUrl, reqBody, challenge) {
944
969
  };
945
970
  }
946
971
  try {
947
- const token = await completeTempoPayment(parsed.params, PRIVATE_KEY);
948
- paymentHeaders["Authorization"] = `Payment ${token}`;
972
+ const token = await completeTempoPayment(challenge.wwwAuthenticate, PRIVATE_KEY);
973
+ paymentHeaders["Authorization"] = token;
949
974
  usedProtocol = "pathUSD (Tempo)";
950
975
  }
951
976
  catch (err) {
@@ -1252,10 +1277,9 @@ async function callViaLegacyProxy(slug, method, body, query, path) {
1252
1277
  }
1253
1278
  catch (err) {
1254
1279
  if (wwwAuth && PRIVATE_KEY) {
1255
- const parsed = parseWwwAuthenticate(wwwAuth);
1256
1280
  try {
1257
- const token = await completeTempoPayment(parsed.params, PRIVATE_KEY);
1258
- paymentHeaders["Authorization"] = `Payment ${token}`;
1281
+ const token = await completeTempoPayment(wwwAuth, PRIVATE_KEY);
1282
+ paymentHeaders["Authorization"] = token;
1259
1283
  usedProtocol = "pathUSD (Tempo)";
1260
1284
  }
1261
1285
  catch (te) {
@@ -1268,10 +1292,9 @@ async function callViaLegacyProxy(slug, method, body, query, path) {
1268
1292
  }
1269
1293
  }
1270
1294
  else if (wwwAuth && PRIVATE_KEY) {
1271
- const parsed = parseWwwAuthenticate(wwwAuth);
1272
1295
  try {
1273
- const token = await completeTempoPayment(parsed.params, PRIVATE_KEY);
1274
- paymentHeaders["Authorization"] = `Payment ${token}`;
1296
+ const token = await completeTempoPayment(wwwAuth, PRIVATE_KEY);
1297
+ paymentHeaders["Authorization"] = token;
1275
1298
  usedProtocol = "pathUSD (Tempo)";
1276
1299
  }
1277
1300
  catch (err) {
@@ -1398,9 +1421,8 @@ async function legacyIntelligenceCall(token, walletAddress) {
1398
1421
  catch (x402Err) {
1399
1422
  if (wwwAuth && PRIVATE_KEY) {
1400
1423
  try {
1401
- const parsed = parseWwwAuthenticate(wwwAuth);
1402
- const tempoToken = await completeTempoPayment(parsed.params, PRIVATE_KEY);
1403
- paymentHeaders["Authorization"] = `Payment ${tempoToken}`;
1424
+ const tempoToken = await completeTempoPayment(wwwAuth, PRIVATE_KEY);
1425
+ paymentHeaders["Authorization"] = tempoToken;
1404
1426
  usedProtocol = "pathUSD (Tempo)";
1405
1427
  }
1406
1428
  catch (tempoErr) {
@@ -1422,9 +1444,8 @@ async function legacyIntelligenceCall(token, walletAddress) {
1422
1444
  }
1423
1445
  else if (wwwAuth && PRIVATE_KEY) {
1424
1446
  try {
1425
- const parsed = parseWwwAuthenticate(wwwAuth);
1426
- const tempoToken = await completeTempoPayment(parsed.params, PRIVATE_KEY);
1427
- paymentHeaders["Authorization"] = `Payment ${tempoToken}`;
1447
+ const tempoToken = await completeTempoPayment(wwwAuth, PRIVATE_KEY);
1448
+ paymentHeaders["Authorization"] = tempoToken;
1428
1449
  usedProtocol = "pathUSD (Tempo)";
1429
1450
  }
1430
1451
  catch (tempoErr) {
@@ -1490,7 +1511,11 @@ function parseWwwAuthenticate(header) {
1490
1511
  }
1491
1512
  return { scheme, params };
1492
1513
  }
1493
- async function completeTempoPayment(challengeParams, privateKey) {
1514
+ // Signs a Tempo TIP-20 transfer for the challenge carried in a 402 response's
1515
+ // raw WWW-Authenticate header and returns the FULL Authorization header value
1516
+ // ("Payment <b64>", mppx Credential.serialize format) — callers must set it
1517
+ // verbatim, never re-prefix with "Payment ".
1518
+ async function completeTempoPayment(wwwAuthenticateHeader, privateKey) {
1494
1519
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1495
1520
  let mppxClient;
1496
1521
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1506,10 +1531,16 @@ async function completeTempoPayment(challengeParams, privateKey) {
1506
1531
  }
1507
1532
  try {
1508
1533
  const account = viemAccounts.privateKeyToAccount(privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`);
1534
+ // polyfill: false — never clobber the host process's globalThis.fetch.
1509
1535
  const client = mppxClient.Mppx.create({
1510
1536
  methods: [mppxClient.tempo({ account })],
1537
+ polyfill: false,
1538
+ });
1539
+ const challengeResponse = new Response(null, {
1540
+ status: 402,
1541
+ headers: { "WWW-Authenticate": wwwAuthenticateHeader },
1511
1542
  });
1512
- return (await client.pay(challengeParams));
1543
+ return (await client.createCredential(challengeResponse));
1513
1544
  }
1514
1545
  catch (payErr) {
1515
1546
  throw new Error(`Tempo payment failed: ${payErr instanceof Error ? payErr.message : String(payErr)}`);
@@ -25,7 +25,7 @@ export interface X402PaymentEnvelope {
25
25
  }
26
26
  export declare function isSvmNetwork(network: string): boolean;
27
27
  export declare function isEvmNetwork(network: string): boolean;
28
- export declare function signX402PaymentSvm(requirements: X402PaymentRequirements, rawKey: string, rpcUrlOverride?: string, echoedVersion?: number): Promise<string>;
28
+ export declare function signX402PaymentSvm(requirements: X402PaymentRequirements, rawKey: string, rpcUrlOverride?: string, echoedVersion?: number, computeUnitLimitOverride?: number): Promise<string>;
29
29
  export declare function signX402PaymentEvm(requirements: X402PaymentRequirements, rawKey: string, echoedVersion?: number): Promise<string>;
30
30
  export interface SignX402Args {
31
31
  paymentRequiredHeader: string;
@@ -109,7 +109,7 @@ async function buildSolanaSigner(rawKey, deps) {
109
109
  }
110
110
  // ── SVM signer ──────────────────────────────────────────────────────────────
111
111
  const DEFAULT_SOLANA_RPC = "https://api.mainnet-beta.solana.com";
112
- export async function signX402PaymentSvm(requirements, rawKey, rpcUrlOverride, echoedVersion = 1) {
112
+ export async function signX402PaymentSvm(requirements, rawKey, rpcUrlOverride, echoedVersion = 1, computeUnitLimitOverride) {
113
113
  if (requirements.scheme !== "exact") {
114
114
  throw new Error(`SVM x402 scheme "${requirements.scheme}" not implemented; only "exact" is supported.`);
115
115
  }
@@ -158,7 +158,12 @@ export async function signX402PaymentSvm(requirements, rawKey, rpcUrlOverride, e
158
158
  const rpc = deps.createSolanaRpc(rpcUrl);
159
159
  const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();
160
160
  const instructions = [
161
- deps.getSetComputeUnitLimitInstruction({ units: 150_000 }),
161
+ // Compute-unit limit must stay under the facilitator's fee-payer cap. PayAI
162
+ // rejects anything above ~60,000 CU as `compute_limit_too_high` (it pays the
163
+ // fee, so it bounds the budget). 50,000 is comfortably under that cap and far
164
+ // above the ~7,000 CU an SPL TransferChecked + compute-budget ixs consume.
165
+ // (Verified against PayAI /verify 2026-06-17: 150,000 was rejected outright.)
166
+ deps.getSetComputeUnitLimitInstruction({ units: computeUnitLimitOverride ?? 50_000 }),
162
167
  deps.getSetComputeUnitPriceInstruction({ microLamports: 1000n }),
163
168
  deps.getTransferCheckedInstruction({
164
169
  source: sourceAta,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mpp32-mcp-server",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "mcpName": "io.github.MPP32/mpp32-mcp-server",
5
5
  "description": "Payment layer for AI agents. One MCP, five protocols, thousands of paid APIs your agent can call.",
6
6
  "type": "module",
@@ -73,7 +73,8 @@
73
73
  "node": ">=20.10.0"
74
74
  },
75
75
  "publishConfig": {
76
- "access": "public"
76
+ "access": "public",
77
+ "provenance": true
77
78
  },
78
79
  "dependencies": {
79
80
  "@modelcontextprotocol/sdk": "1.29.0",
@@ -81,17 +82,10 @@
81
82
  "@solana-program/compute-budget": "0.15.0",
82
83
  "@solana-program/token": "0.13.0",
83
84
  "@solana/kit": "6.9.0",
85
+ "mppx": "0.4.12",
84
86
  "viem": "2.52.2",
85
87
  "zod": "3.25.76"
86
88
  },
87
- "peerDependencies": {
88
- "mppx": ">=0.4.0"
89
- },
90
- "peerDependenciesMeta": {
91
- "mppx": {
92
- "optional": true
93
- }
94
- },
95
89
  "devDependencies": {
96
90
  "@types/node": "22.19.18",
97
91
  "typescript": "5.9.3"