@cryptoapis-io/mcp-x402-pay 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Crypto APIs, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @cryptoapis-io/mcp-x402-pay
2
+
3
+ > **This is the BUYER side of x402** — the tool an agent uses to *spend* (pay for a resource). Merchants
4
+ > who want to *charge* for an API use the middleware SDK (`@cryptoapis-io/x402-merchant-sdk`), not an MCP tool.
5
+
6
+ An MCP server that lets an AI agent **pay x402-gated HTTP endpoints**. One tool, `x402_pay`: it fetches a
7
+ URL and, if the server returns `402 Payment Required`, it authorizes the payment via the CryptoAPIs buyer
8
+ service, **signs locally**, retries, and returns the paid response.
9
+
10
+ **Non-custodial:** the private key is passed per request and never leaves the process (no HTTP server —
11
+ stdio only).
12
+
13
+ **Supported today:** EVM (`eip712`, e.g. Base USDC) and Solana. Tron, Bitcoin/UTXO, XRP and Kaspa are
14
+ **upcoming** — wired but not yet enabled; paying on them returns a clear `family_not_yet_supported`
15
+ ("coming soon") result.
16
+
17
+ ## Run
18
+
19
+ ```bash
20
+ node dist/cli.js # stdio MCP server (no --api-key at startup; keys are per-tool-call)
21
+ ```
22
+
23
+ ## Tool: `x402_pay`
24
+
25
+ | Input | Required | Description |
26
+ |---|---|---|
27
+ | `url` | ✓ | the (possibly paywalled) resource |
28
+ | `apiKey` | ✓ | your CryptoAPIs key (X402_BUYER feature) — only used to call the buyer `/authorize` |
29
+ | `walletId` | ✓ | the agent wallet the buyer service pays from |
30
+ | `privateKey` | ✓ | the wallet's EVM key — **signs locally, never sent anywhere** |
31
+ | `method`/`body`/`headers` | | the request to make |
32
+ | `allowedNetworks` | | restrict which CAIP-2 networks to pay on |
33
+ | `maxAmount` | | safety cap — refuse if the required atomic-unit amount exceeds it |
34
+
35
+ Returns `{ status, paid, body, settlement? }`. On a 402 with no acceptable option (or over `maxAmount`),
36
+ `paid:false` with a `reason` — nothing is signed or paid.
37
+
38
+ ## Flow
39
+
40
+ 1. `fetch(url)`. Not 402 → return it.
41
+ 2. 402 → pick an `accepts` entry (allowlist-aware), authorize via buyer `/authorize` → the signing artifact.
42
+ 3. Sign locally (`@cryptoapis-io/mcp-signer` `evm_sign` typed-data) → build the x402 `PaymentPayload`
43
+ (**wire scheme is always `exact`**; the family is in `network`).
44
+ 4. Retry with the base64 `X-PAYMENT` header; return the paid response + the `X-PAYMENT-RESPONSE` settlement.
45
+
46
+ ## Security
47
+
48
+ The private key is a tool parameter and **may be logged by MCP clients or stored in conversation
49
+ history** — use only in trusted local environments. This mirrors `@cryptoapis-io/mcp-signer`.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,9 @@
1
+ import { startX402Server } from "./server.js";
2
+ async function main() {
3
+ await startX402Server();
4
+ }
5
+ main().catch((err) => {
6
+ console.error(err);
7
+ process.exit(1);
8
+ });
9
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,UAAU,IAAI;IACf,MAAM,eAAe,EAAE,CAAC;AAC5B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { startX402Server } from "./server.js";
2
+ export { tools } from "./tools/index.js";
3
+ export { x402Pay } from "./tools/x402-pay/index.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { startX402Server } from "./server.js";
2
+ export { tools } from "./tools/index.js";
3
+ export { x402Pay } from "./tools/x402-pay/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Build and run the x402 MCP server. Stdio-only (no HTTP) for security: the buyer's
3
+ * private key is passed per request and no network server is exposed.
4
+ */
5
+ export declare function startX402Server(): Promise<void>;
6
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAuBrD"}
package/dist/server.js ADDED
@@ -0,0 +1,37 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { McpLogger } from "@cryptoapis-io/mcp-shared";
4
+ import { tools } from "./tools/index.js";
5
+ const CRYPTOAPIS_SERVER_INFO = {
6
+ name: "mcp-x402-pay",
7
+ version: "0.1.0",
8
+ title: "MCP x402 — pay paywalled HTTP endpoints",
9
+ websiteUrl: "https://developers.cryptoapis.io",
10
+ icons: [
11
+ { src: "https://cryptoapis.io/cryptoapis/images/logo.svg", mimeType: "image/svg+xml", sizes: ["any"], theme: "light" },
12
+ { src: "https://cryptoapis.io/cryptoapis/images/logo-black.svg", mimeType: "image/svg+xml", sizes: ["any"], theme: "dark" },
13
+ ],
14
+ };
15
+ /**
16
+ * Build and run the x402 MCP server. Stdio-only (no HTTP) for security: the buyer's
17
+ * private key is passed per request and no network server is exposed.
18
+ */
19
+ export async function startX402Server() {
20
+ const server = new McpServer(CRYPTOAPIS_SERVER_INFO);
21
+ const logger = new McpLogger((params) => server.sendLoggingMessage(params), CRYPTOAPIS_SERVER_INFO.name);
22
+ for (const t of tools) {
23
+ server.registerTool(t.name, { description: t.description, inputSchema: t.inputSchema }, async (input) => {
24
+ logger.logDebug({ tool: t.name, event: "tool_call" });
25
+ const result = await t.handler(input)
26
+ .catch((err) => {
27
+ logger.logError(err instanceof Error ? err.message : String(err), { tool: t.name });
28
+ throw err;
29
+ });
30
+ logger.logInfo({ tool: t.name });
31
+ return result;
32
+ });
33
+ }
34
+ await server.connect(new StdioServerTransport());
35
+ logger.logInfo("mcp-x402-pay running (stdio only, no HTTP)");
36
+ }
37
+ //# 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,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,sBAAsB,GAAG;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,yCAAyC;IAChD,UAAU,EAAE,kCAAkC;IAC9C,KAAK,EAAE;QACH,EAAE,GAAG,EAAE,kDAAkD,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAgB,EAAE;QAC/H,EAAE,GAAG,EAAE,wDAAwD,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAe,EAAE;KACvI;CACJ,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACjC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,sBAAsB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAEzG,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACpB,MAAM,CAAC,YAAY,CACf,CAAC,CAAC,IAAI,EACN,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,EAC1D,KAAK,EAAE,KAAc,EAAE,EAAE;YACrB,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,MAAO,CAAC,CAAC,OAAsF,CAAC,KAAK,CAAC;iBAChH,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBACpB,MAAM,CAAC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACpF,MAAM,GAAG,CAAC;YACd,CAAC,CAAC,CAAC;YACP,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACjC,OAAO,MAAM,CAAC;QAClB,CAAC,CACJ,CAAC;IACN,CAAC;IAED,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,50 @@
1
+ export declare const tools: readonly [import("./types.js").McpX402ToolDef<import("zod").ZodObject<{
2
+ url: import("zod").ZodString;
3
+ method: import("zod").ZodOptional<import("zod").ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
4
+ body: import("zod").ZodOptional<import("zod").ZodString>;
5
+ headers: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>>;
6
+ apiKey: import("zod").ZodOptional<import("zod").ZodString>;
7
+ walletId: import("zod").ZodOptional<import("zod").ZodString>;
8
+ privateKey: import("zod").ZodOptional<import("zod").ZodString>;
9
+ tronKey: import("zod").ZodOptional<import("zod").ZodString>;
10
+ svmSecret: import("zod").ZodOptional<import("zod").ZodString>;
11
+ utxoWif: import("zod").ZodOptional<import("zod").ZodString>;
12
+ kaspaKey: import("zod").ZodOptional<import("zod").ZodString>;
13
+ xrpSeed: import("zod").ZodOptional<import("zod").ZodString>;
14
+ allowedNetworks: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
15
+ buyerBaseUrl: import("zod").ZodOptional<import("zod").ZodString>;
16
+ maxAmount: import("zod").ZodOptional<import("zod").ZodString>;
17
+ }, "strip", import("zod").ZodTypeAny, {
18
+ url: string;
19
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | undefined;
20
+ body?: string | undefined;
21
+ headers?: Record<string, string> | undefined;
22
+ apiKey?: string | undefined;
23
+ walletId?: string | undefined;
24
+ privateKey?: string | undefined;
25
+ tronKey?: string | undefined;
26
+ svmSecret?: string | undefined;
27
+ utxoWif?: string | undefined;
28
+ kaspaKey?: string | undefined;
29
+ xrpSeed?: string | undefined;
30
+ allowedNetworks?: string[] | undefined;
31
+ buyerBaseUrl?: string | undefined;
32
+ maxAmount?: string | undefined;
33
+ }, {
34
+ url: string;
35
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | undefined;
36
+ body?: string | undefined;
37
+ headers?: Record<string, string> | undefined;
38
+ apiKey?: string | undefined;
39
+ walletId?: string | undefined;
40
+ privateKey?: string | undefined;
41
+ tronKey?: string | undefined;
42
+ svmSecret?: string | undefined;
43
+ utxoWif?: string | undefined;
44
+ kaspaKey?: string | undefined;
45
+ xrpSeed?: string | undefined;
46
+ allowedNetworks?: string[] | undefined;
47
+ buyerBaseUrl?: string | undefined;
48
+ maxAmount?: string | undefined;
49
+ }>>];
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAyB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { x402PayTool } from "./x402-pay/index.js";
2
+ export const tools = [x402PayTool];
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,WAAW,CAAU,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type * as z from "zod";
2
+ /** Tool definition for the x402 MCP (local orchestration; no shared HTTP client). */
3
+ export type McpX402ToolDef<TSchema extends z.ZodTypeAny> = {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: TSchema;
7
+ handler: (input: z.infer<TSchema>) => Promise<{
8
+ content: {
9
+ type: "text";
10
+ text: string;
11
+ }[];
12
+ }>;
13
+ };
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC;AAE9B,qFAAqF;AACrF,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,CAAC,CAAC,UAAU,IAAI;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC,CAAC;CAChG,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import type { X402PayInput } from "./schema.js";
2
+ import { X402PaySchema } from "./schema.js";
3
+ import type { McpX402ToolDef } from "../types.js";
4
+ /**
5
+ * Fetch a URL and auto-pay a 402 with x402 (EVM eip712 path).
6
+ *
7
+ * @param input the tool input
8
+ * @return the final (paid) response summary
9
+ */
10
+ export declare function x402Pay(input: X402PayInput): Promise<{
11
+ status: number;
12
+ paid: boolean;
13
+ body: string;
14
+ settlement?: unknown;
15
+ reason?: string;
16
+ }>;
17
+ export declare const x402PayTool: McpX402ToolDef<typeof X402PaySchema>;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/x402-pay/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA+ClD;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;IACxD,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACtF,CAAC,CA4KD;AAED,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,OAAO,aAAa,CAS5D,CAAC"}
@@ -0,0 +1,228 @@
1
+ import { evmSignTypedData, svmPartialSign, tronSignFromDetails, utxoSignFromDetails, kaspaSignFromDetails, xrpSignFromDetails, } from "@cryptoapis-io/mcp-signer";
2
+ import { X402PaySchema } from "./schema.js";
3
+ const DEFAULT_BUYER_BASE_URL = "https://ai.cryptoapis.io/x402/buyer";
4
+ const X402_VERSION = 2;
5
+ /** The WIRE payment scheme is ALWAYS "exact" — the facilitator's parseEnvelope rejects
6
+ * anything else and derives the family from `network`. The buyer /authorize "scheme"
7
+ * (eip712/…) is the ARTIFACT type (how to sign), NOT this. */
8
+ const SCHEME_EXACT = "exact";
9
+ /** Artifact schemes that are LIVE-VERIFIED end-to-end and enabled today. EVM (eip712) and
10
+ * Solana (svm-transaction) are supported; Tron/UTXO/XRP/Kaspa are wired but not yet
11
+ * live-verified, so they are gated OFF ("coming soon") until each is exercised in prod.
12
+ * Enabling a family once verified = add its scheme here. */
13
+ const SUPPORTED_SCHEMES = new Set(["eip712", "svm-transaction"]);
14
+ /** UTXO CAIP-2 network id → the {blockchain, network} the mcp-signer utxo-sign needs
15
+ * (a bare CAIP-2 doesn't carry the chain name). Only UTXO signing needs this pair. */
16
+ const UTXO_CAIP2 = {
17
+ "bip122:000000000019d6689c085ae165831e93": { blockchain: "bitcoin", network: "mainnet" },
18
+ "bip122:000000000933ea01ad0ee984209779ba": { blockchain: "bitcoin", network: "testnet" },
19
+ "bip122:12a765e31ffd4059bada1e25190f6e98": { blockchain: "litecoin", network: "mainnet" },
20
+ "bip122:4966625a4b2851d9fdee139e56211a0d": { blockchain: "litecoin", network: "testnet" },
21
+ "bip122:1a91e3dace36e2be3bf030a65679fe82": { blockchain: "dogecoin", network: "mainnet" },
22
+ "bip122:bb0a78264637406b6360aad926284d54": { blockchain: "dogecoin", network: "testnet" },
23
+ "bip122:00000ffd590b1485b3caadc19b22e637": { blockchain: "dash", network: "mainnet" },
24
+ "bip122:00000bafbc94add76cb75e2ec92894837": { blockchain: "dash", network: "testnet" },
25
+ "bip122:000000000000000000651ef99cb9fcbe": { blockchain: "bitcoin-cash", network: "mainnet" },
26
+ "bip122:00000000dfd5d65c9d8561b4b8f60a63": { blockchain: "bitcoin-cash", network: "testnet" },
27
+ "bip122:0007104ccda289427919efc39dc9e4d4": { blockchain: "zcash", network: "mainnet" },
28
+ "bip122:05a60a92d99d85997cce3b87616c089f": { blockchain: "zcash", network: "testnet" },
29
+ };
30
+ /** Pick which offered requirement to pay (allowlist-aware; else the first). */
31
+ function selectRequirements(accepts, allowed) {
32
+ if (accepts.length === 0)
33
+ return null;
34
+ if (Array.isArray(allowed) && allowed.length > 0) {
35
+ return accepts.find((r) => allowed.includes(r.network)) ?? null;
36
+ }
37
+ return accepts[0] ?? null;
38
+ }
39
+ /**
40
+ * Fetch a URL and auto-pay a 402 with x402 (EVM eip712 path).
41
+ *
42
+ * @param input the tool input
43
+ * @return the final (paid) response summary
44
+ */
45
+ export async function x402Pay(input) {
46
+ // Credentials: prefer the per-call params, else fall back to env (set once in the
47
+ // MCP config so the agent only ever passes `url` — and the key stays out of logs).
48
+ // apiKey + walletId are always needed (to call /authorize); the SIGNING key is
49
+ // resolved per-family at the dispatch below (each chain uses its own key form).
50
+ const apiKey = input.apiKey ?? process.env.CRYPTOAPIS_API_KEY;
51
+ const walletId = input.walletId ?? process.env.X402_WALLET_ID;
52
+ if (!apiKey || !walletId) {
53
+ const missing = [!apiKey && "apiKey/CRYPTOAPIS_API_KEY", !walletId && "walletId/X402_WALLET_ID"].filter(Boolean).join(", ");
54
+ return { status: 0, paid: false, reason: `missing credentials: ${missing} (pass as params or set the env vars)`, body: "" };
55
+ }
56
+ // Per-family signing keys (param → family env → EVM fallback where the curve allows).
57
+ const evmKey = input.privateKey ?? process.env.X402_PRIVATE_KEY;
58
+ const keys = {
59
+ evm: evmKey,
60
+ tron: input.tronKey ?? process.env.X402_TRON_KEY ?? evmKey,
61
+ svm: input.svmSecret ?? process.env.X402_SVM_SECRET,
62
+ utxo: input.utxoWif ?? process.env.X402_UTXO_WIF,
63
+ kaspa: input.kaspaKey ?? process.env.X402_KASPA_KEY,
64
+ xrp: input.xrpSeed ?? process.env.X402_XRP_SEED,
65
+ };
66
+ const method = input.method ?? "GET";
67
+ const baseInit = {
68
+ method,
69
+ headers: { ...(input.headers ?? {}) },
70
+ ...(input.body != null ? { body: input.body } : {}),
71
+ };
72
+ const first = await fetch(input.url, baseInit);
73
+ if (first.status !== 402) {
74
+ return { status: first.status, paid: false, body: await first.text() };
75
+ }
76
+ const body402 = await first.json().catch(() => null);
77
+ const accepts = Array.isArray(body402?.accepts) ? body402.accepts : [];
78
+ const requirements = selectRequirements(accepts, input.allowedNetworks);
79
+ if (!requirements) {
80
+ return { status: 402, paid: false, reason: "no acceptable payment option", body: JSON.stringify(body402) };
81
+ }
82
+ if (input.maxAmount != null && BigInt(requirements.amount) > BigInt(input.maxAmount)) {
83
+ return { status: 402, paid: false, reason: `required amount ${requirements.amount} exceeds maxAmount ${input.maxAmount}`, body: "" };
84
+ }
85
+ // 1. Authorize via the buyer service → the artifact to sign.
86
+ const root = (input.buyerBaseUrl ?? DEFAULT_BUYER_BASE_URL).replace(/\/$/, "");
87
+ const authRes = await fetch(`${root}/authorize`, {
88
+ method: "POST",
89
+ headers: { "content-type": "application/json", "x-api-key": apiKey },
90
+ body: JSON.stringify({ paymentRequirements: requirements, walletId: walletId }),
91
+ });
92
+ if (!authRes.ok) {
93
+ return { status: 402, paid: false, reason: `buyer /authorize failed: ${authRes.status} ${await authRes.text()}`.trim(), body: "" };
94
+ }
95
+ const auth = await authRes.json();
96
+ if (auth.authorized === false) {
97
+ return { status: 402, paid: false, reason: `authorize refused: ${auth.reason ?? "unknown"}`, body: "" };
98
+ }
99
+ // 2. Sign LOCALLY + build the PaymentPayload. The WIRE scheme is ALWAYS "exact"
100
+ // (family carried by `network`); the /authorize `scheme` says HOW to sign. Every
101
+ // family's facilitator parsePayload reads `payload.transaction` first — so the
102
+ // non-EVM families use a uniform `payload:{transaction}` wrapper, with the
103
+ // per-family value the facilitator expects (SVM base64, UTXO/XRP hex, Kaspa JSON,
104
+ // Tron the structured {txID, raw_data_hex, raw_data, signature[]} object).
105
+ const network = requirements.network;
106
+ // Gate off families that are wired but not yet live-verified (Tron/UTXO/XRP/Kaspa).
107
+ // EVM + Solana are supported today; the rest are on the roadmap ("coming soon").
108
+ if (!auth.scheme || !SUPPORTED_SCHEMES.has(auth.scheme)) {
109
+ return {
110
+ status: 402,
111
+ paid: false,
112
+ reason: `family_not_yet_supported: the "${auth.scheme}" family is coming soon — only EVM (eip712) and Solana (svm-transaction) are supported today`,
113
+ body: "",
114
+ };
115
+ }
116
+ const sp = auth.signingPayload ?? {};
117
+ let payload;
118
+ /** Guard: a family whose signing key wasn't configured errors cleanly (never mis-signs). */
119
+ const needKey = (key, envName) => (key ? null : `no signing key for ${auth.scheme} — set ${envName} (or the matching param)`);
120
+ if (auth.scheme === "eip712") {
121
+ const missing = needKey(keys.evm, "X402_PRIVATE_KEY");
122
+ if (missing)
123
+ return { status: 402, paid: false, reason: missing, body: "" };
124
+ const td = sp;
125
+ const { signature } = await evmSignTypedData({
126
+ action: "sign-typed-data",
127
+ privateKey: keys.evm,
128
+ domain: td.domain,
129
+ types: td.types,
130
+ primaryType: td.primaryType,
131
+ message: td.message,
132
+ });
133
+ payload = { signature, authorization: td.message };
134
+ }
135
+ else if (auth.scheme === "svm-transaction") {
136
+ const missing = needKey(keys.svm, "X402_SVM_SECRET");
137
+ if (missing)
138
+ return { status: 402, paid: false, reason: missing, body: "" };
139
+ const { transaction } = svmPartialSign({
140
+ action: "partial-sign",
141
+ secretKeyBase58: keys.svm,
142
+ transaction: sp.transaction,
143
+ });
144
+ payload = { transaction };
145
+ }
146
+ else if (auth.scheme === "tron-transaction") {
147
+ const missing = needKey(keys.tron, "X402_TRON_KEY");
148
+ if (missing)
149
+ return { status: 402, paid: false, reason: missing, body: "" };
150
+ const { signedTransaction } = tronSignFromDetails({
151
+ action: "sign-from-details",
152
+ privateKey: keys.tron,
153
+ transaction: sp.transaction,
154
+ });
155
+ // Tron's facilitator wants the structured {txID, raw_data_hex, raw_data, signature[]}.
156
+ payload = { transaction: signedTransaction };
157
+ }
158
+ else if (auth.scheme === "utxo-transaction") {
159
+ const missing = needKey(keys.utxo, "X402_UTXO_WIF");
160
+ if (missing)
161
+ return { status: 402, paid: false, reason: missing, body: "" };
162
+ const chain = UTXO_CAIP2[network];
163
+ if (!chain)
164
+ return { status: 402, paid: false, reason: `unknown UTXO network ${network}`, body: "" };
165
+ const { signedTransactionHex } = utxoSignFromDetails({
166
+ action: "sign-from-details",
167
+ blockchain: chain.blockchain,
168
+ network: chain.network,
169
+ privateKeys: [keys.utxo],
170
+ preparedTransaction: sp.preparedTransaction,
171
+ });
172
+ payload = { transaction: signedTransactionHex };
173
+ }
174
+ else if (auth.scheme === "kaspa-transaction") {
175
+ const missing = needKey(keys.kaspa, "X402_KASPA_KEY");
176
+ if (missing)
177
+ return { status: 402, paid: false, reason: missing, body: "" };
178
+ const { signedTransaction } = kaspaSignFromDetails({
179
+ action: "sign-from-details",
180
+ privateKeys: [keys.kaspa],
181
+ preparedTransaction: sp.preparedTransaction,
182
+ });
183
+ payload = { transaction: signedTransaction };
184
+ }
185
+ else if (auth.scheme === "xrp-transaction") {
186
+ const missing = needKey(keys.xrp, "X402_XRP_SEED");
187
+ if (missing)
188
+ return { status: 402, paid: false, reason: missing, body: "" };
189
+ const { signedTransactionHex } = await xrpSignFromDetails({
190
+ action: "sign-from-details",
191
+ secret: keys.xrp,
192
+ transaction: sp.transaction,
193
+ });
194
+ payload = { transaction: signedTransactionHex };
195
+ }
196
+ else {
197
+ return { status: 402, paid: false, reason: `unsupported_scheme: ${auth.scheme}`, body: "" };
198
+ }
199
+ const paymentPayload = {
200
+ x402Version: X402_VERSION,
201
+ scheme: SCHEME_EXACT,
202
+ network: network,
203
+ payload: payload,
204
+ };
205
+ // 3. Retry the ORIGINAL request with the X-PAYMENT header.
206
+ const xPayment = Buffer.from(JSON.stringify(paymentPayload), "utf8").toString("base64");
207
+ const paid = await fetch(input.url, {
208
+ ...baseInit,
209
+ headers: { ...baseInit.headers, "x-payment": xPayment },
210
+ });
211
+ const paymentResponse = paid.headers.get("x-payment-response");
212
+ return {
213
+ status: paid.status,
214
+ paid: paid.status >= 200 && paid.status < 300,
215
+ body: await paid.text(),
216
+ settlement: paymentResponse ? JSON.parse(Buffer.from(paymentResponse, "base64").toString("utf8")) : undefined,
217
+ };
218
+ }
219
+ export const x402PayTool = {
220
+ name: "x402_pay",
221
+ description: "Fetch an HTTP resource and, if it returns 402 Payment Required, pay it automatically with x402 and return the paid response. On a 402 it: parses the merchant's price, authorizes via the CryptoAPIs buyer /authorize, signs the payment LOCALLY (non-custodial — the key never leaves this process), and retries with the X-PAYMENT header. Returns { status, paid, body, settlement? }. Supported today: EVM (eip712, e.g. Base USDC) and Solana. Tron, UTXO (bitcoin/ltc/doge/dash/bch/zcash), Kaspa and XRP are UPCOMING — wired but not yet enabled, and paying on them returns a clear coming-soon (family_not_yet_supported) result. Set CRYPTOAPIS_API_KEY + X402_WALLET_ID once, plus the signing key(s) for the chain(s) you pay on: X402_PRIVATE_KEY (EVM hex), X402_SVM_SECRET (base58). A scheme with no configured key errors cleanly (never mis-signs). Env vars keep keys OUT of tool-call logs. Use allowedNetworks to restrict, maxAmount as a safety cap. SECURITY: use only in trusted local environments.",
222
+ inputSchema: X402PaySchema,
223
+ handler: async (input) => {
224
+ const result = await x402Pay(input);
225
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
226
+ },
227
+ };
228
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/x402-pay/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Fetch an HTTP resource and, if it responds 402 Payment Required, pay it with x402:
4
+ * authorize via the CryptoAPIs buyer service, sign LOCALLY, retry. Non-custodial —
5
+ * the private key is passed per request and never leaves this process.
6
+ *
7
+ * Supports all six x402 families. Each family signs with ITS OWN key form — a
8
+ * single hex key can't sign a Solana (base58), UTXO (WIF) or XRP (seed) payment,
9
+ * so those take their own optional key/env. An agent only sets the key(s) for the
10
+ * chain(s) it actually pays on; a scheme with no configured key errors cleanly
11
+ * rather than mis-signing.
12
+ */
13
+ export declare const X402PaySchema: z.ZodObject<{
14
+ url: z.ZodString;
15
+ method: z.ZodOptional<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
16
+ body: z.ZodOptional<z.ZodString>;
17
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
18
+ apiKey: z.ZodOptional<z.ZodString>;
19
+ walletId: z.ZodOptional<z.ZodString>;
20
+ privateKey: z.ZodOptional<z.ZodString>;
21
+ tronKey: z.ZodOptional<z.ZodString>;
22
+ svmSecret: z.ZodOptional<z.ZodString>;
23
+ utxoWif: z.ZodOptional<z.ZodString>;
24
+ kaspaKey: z.ZodOptional<z.ZodString>;
25
+ xrpSeed: z.ZodOptional<z.ZodString>;
26
+ allowedNetworks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
27
+ buyerBaseUrl: z.ZodOptional<z.ZodString>;
28
+ maxAmount: z.ZodOptional<z.ZodString>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ url: string;
31
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | undefined;
32
+ body?: string | undefined;
33
+ headers?: Record<string, string> | undefined;
34
+ apiKey?: string | undefined;
35
+ walletId?: string | undefined;
36
+ privateKey?: string | undefined;
37
+ tronKey?: string | undefined;
38
+ svmSecret?: string | undefined;
39
+ utxoWif?: string | undefined;
40
+ kaspaKey?: string | undefined;
41
+ xrpSeed?: string | undefined;
42
+ allowedNetworks?: string[] | undefined;
43
+ buyerBaseUrl?: string | undefined;
44
+ maxAmount?: string | undefined;
45
+ }, {
46
+ url: string;
47
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | undefined;
48
+ body?: string | undefined;
49
+ headers?: Record<string, string> | undefined;
50
+ apiKey?: string | undefined;
51
+ walletId?: string | undefined;
52
+ privateKey?: string | undefined;
53
+ tronKey?: string | undefined;
54
+ svmSecret?: string | undefined;
55
+ utxoWif?: string | undefined;
56
+ kaspaKey?: string | undefined;
57
+ xrpSeed?: string | undefined;
58
+ allowedNetworks?: string[] | undefined;
59
+ buyerBaseUrl?: string | undefined;
60
+ maxAmount?: string | undefined;
61
+ }>;
62
+ export type X402PayInput = z.infer<typeof X402PaySchema>;
63
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/tools/x402-pay/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBxB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
@@ -0,0 +1,33 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Fetch an HTTP resource and, if it responds 402 Payment Required, pay it with x402:
4
+ * authorize via the CryptoAPIs buyer service, sign LOCALLY, retry. Non-custodial —
5
+ * the private key is passed per request and never leaves this process.
6
+ *
7
+ * Supports all six x402 families. Each family signs with ITS OWN key form — a
8
+ * single hex key can't sign a Solana (base58), UTXO (WIF) or XRP (seed) payment,
9
+ * so those take their own optional key/env. An agent only sets the key(s) for the
10
+ * chain(s) it actually pays on; a scheme with no configured key errors cleanly
11
+ * rather than mis-signing.
12
+ */
13
+ export const X402PaySchema = z.object({
14
+ url: z.string().url().describe("The (possibly paywalled) resource URL to fetch"),
15
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).optional().describe("HTTP method (default GET)"),
16
+ body: z.string().optional().describe("Request body (string; set content-type via headers if needed)"),
17
+ headers: z.record(z.string(), z.string()).optional().describe("Extra request headers"),
18
+ apiKey: z.string().optional().describe("Your CryptoAPIs API key with the X402_BUYER feature (used only to call the buyer /authorize). Falls back to the CRYPTOAPIS_API_KEY env var — set it once and omit this."),
19
+ walletId: z.string().optional().describe("The CryptoAPIs agent wallet id to pay from. Falls back to the X402_WALLET_ID env var."),
20
+ // Per-family signing keys — pass only the one(s) for the chain(s) you pay on.
21
+ // All SIGN LOCALLY and are never sent anywhere; each falls back to its env var
22
+ // (PREFERRED — keeps the key out of tool-call logs).
23
+ privateKey: z.string().optional().describe("EVM private key (hex, 0x optional) — signs the eip712 (EVM) payment, and Tron by default. Falls back to X402_PRIVATE_KEY. SECURITY: trusted local environments only."),
24
+ tronKey: z.string().optional().describe("Tron private key (hex). Falls back to X402_TRON_KEY, then to privateKey/X402_PRIVATE_KEY (same secp256k1 curve)."),
25
+ svmSecret: z.string().optional().describe("Solana secret key, base58-encoded (64-byte keypair secret) — signs svm-transaction payments. Falls back to X402_SVM_SECRET."),
26
+ utxoWif: z.string().optional().describe("UTXO private key in WIF format — signs utxo-transaction payments (bitcoin/ltc/doge/dash/bch/zcash). Falls back to X402_UTXO_WIF."),
27
+ kaspaKey: z.string().optional().describe("Kaspa private key (hex, 32 bytes) — signs kaspa-transaction payments. Falls back to X402_KASPA_KEY."),
28
+ xrpSeed: z.string().optional().describe("XRP secret/seed (base58, e.g. s...) — signs xrp-transaction payments. Falls back to X402_XRP_SEED."),
29
+ allowedNetworks: z.array(z.string()).optional().describe("Restrict which CAIP-2 networks to pay on (e.g. [\"eip155:8453\"])"),
30
+ buyerBaseUrl: z.string().url().optional().describe("Override the buyer service base URL (default https://ai.cryptoapis.io/x402/buyer)"),
31
+ maxAmount: z.string().optional().describe("Optional safety cap: refuse to pay if the required atomic-unit amount exceeds this"),
32
+ });
33
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/tools/x402-pay/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;IAChF,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IAC1G,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;IACrG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IAEtF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yKAAyK,CAAC;IACjN,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;IAEjI,8EAA8E;IAC9E,+EAA+E;IAC/E,qDAAqD;IACrD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sKAAsK,CAAC;IAClN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kHAAkH,CAAC;IAC3J,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6HAA6H,CAAC;IACxK,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kIAAkI,CAAC;IAC3K,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qGAAqG,CAAC;IAC/I,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oGAAoG,CAAC;IAE7I,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;IAC7H,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mFAAmF,CAAC;IACvI,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;CAClI,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@cryptoapis-io/mcp-x402-pay",
3
+ "mcpName": "io.github.CryptoAPIs-io/mcp-x402-pay",
4
+ "version": "0.1.0",
5
+ "description": "MCP server that pays x402-gated HTTP endpoints — one x402_pay tool that fetches, and on a 402 authorizes via the CryptoAPIs buyer service, signs LOCALLY, and retries.",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "cryptoapis-mcp-x402-pay": "dist/cli.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "server.json",
16
+ "LICENSE"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.27.1",
23
+ "ethers": "^6.13.0",
24
+ "zod": "^3.25.0",
25
+ "@cryptoapis-io/mcp-shared": "0.3.0",
26
+ "@cryptoapis-io/mcp-signer": "0.4.0"
27
+ },
28
+ "devDependencies": {
29
+ "rimraf": "^5.0.0",
30
+ "tsx": "^4.0.0"
31
+ },
32
+ "scripts": {
33
+ "dev": "tsc -w",
34
+ "build": "tsc",
35
+ "typecheck": "tsc --noEmit",
36
+ "lint": "node -e \"console.log('lint: add eslint if you want')\"",
37
+ "test": "node -e \"console.log('test: add later')\"",
38
+ "test:x402-pay": "tsx scripts/test-x402-pay.ts",
39
+ "clean": "rimraf dist",
40
+ "test:x402-pay-families": "tsx scripts/test-x402-pay-families.ts"
41
+ }
42
+ }
package/server.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.CryptoAPIs-io/mcp-x402-pay",
4
+ "description": "MCP server that pays x402-gated HTTP endpoints — fetch, and on a 402 authorize, sign, retry",
5
+ "repository": {
6
+ "url": "https://github.com/CryptoAPIs-io/cryptoapis-mcp-x402-pay",
7
+ "source": "github"
8
+ },
9
+ "version": "0.1.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "@cryptoapis-io/mcp-x402-pay",
14
+ "version": "0.1.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ]
20
+ }