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 +31 -0
- package/README.md +14 -7
- package/dist/index.js +59 -28
- package/dist/x402-signers.d.ts +1 -1
- package/dist/x402-signers.js +7 -2
- package/package.json +4 -10
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 |
|
|
21
|
-
|
|
|
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
|
|
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
|
-
##
|
|
26
|
+
## Free Tier: 10 calls/day, no wallet required
|
|
26
27
|
|
|
27
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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`" :
|
|
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.
|
|
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
|
|
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).
|
|
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(
|
|
922
|
-
paymentHeaders["Authorization"] =
|
|
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(
|
|
948
|
-
paymentHeaders["Authorization"] =
|
|
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(
|
|
1258
|
-
paymentHeaders["Authorization"] =
|
|
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(
|
|
1274
|
-
paymentHeaders["Authorization"] =
|
|
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
|
|
1402
|
-
|
|
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
|
|
1426
|
-
|
|
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
|
-
|
|
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.
|
|
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)}`);
|
package/dist/x402-signers.d.ts
CHANGED
|
@@ -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;
|
package/dist/x402-signers.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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"
|