@nuwa-ai/x402
v0.6.0
Published
Small helpers to add x402 payments to: - MCP servers: mark tools as paid and verify/settle before running (tracks the original x402 MCP specification) - HTTP/LLM proxies: gate endpoints with x402 and settle automatically (currently via a naive flat-price
Readme
@nuwa-ai/x402
Small helpers to add x402 payments to:
- MCP servers: mark tools as paid and verify/settle before running (tracks the original x402 MCP specification)
- HTTP/LLM proxies: gate endpoints with x402 and settle automatically (currently via a naive flat-price flow while v2
uptoschema support is in progress)
Status
mcp– aligned with the original x402 MCP spec used by x402-compatible clients today.llm– implements flat-price payments only; full v2uptoschema-based payments are under active development.
Exports
mcp–createPaidMcpHandler(serverInit, serverOptions, { recipient, network, facilitator })for Nextjs, referred to vercel's x402-mcp.llm–X402LlmPaymentsand helpers (createPaymentPlugin,logPaymentResponseHeader,decodePaymentResponseHeader)- Common types re-exported from
x402/types
Install
- In this monorepo it is consumed via workspace. For external projects:
pnpm add @nuwa-ai/x402 x402 @modelcontextprotocol/sdk viem zod mcp-handler.
MCP: Paid Tools
import { privateKeyToAccount } from "viem/accounts";
import z from "zod";
import { createPaidMcpHandler, type FacilitatorConfig } from "@nuwa-ai/x402/mcp";
import { facilitator } from "@coinbase/x402"; // FacilitatorConfig implementation
const seller = privateKeyToAccount(process.env.SERVICE_PRIVATE_KEY as `0x${string}`);
const network = (process.env.NETWORK as "base" | "base-sepolia") ?? "base-sepolia";
export const handler = createPaidMcpHandler(
(server) => {
// Paid tool – requires a valid _meta["x402/payment"] from the client
server.paidTool(
"add",
"Add two numbers",
{ price: 0.001 }, // USD
{ a: z.number().int(), b: z.number().int() },
{},
async (args) => ({ content: [{ type: "text", text: String(args.a + args.b) }] }),
);
// Free tool – works like a normal MCP tool
server.tool(
"hello",
"Say hello",
{ name: z.string() },
async (args) => ({ content: [{ type: "text", text: `Hello ${args.name}` }] }),
);
},
{ serverInfo: { name: "example-mcp", version: "0.0.1" } },
{ recipient: seller.address, facilitator: facilitator as unknown as FacilitatorConfig, network },
);Behavior
- If the client does not supply
_meta["x402/payment"], the server returns an error with anacceptsarray describing acceptable payment requirements. - On success, the tool callback runs. Settlement is attempted afterward; if successful,
_meta["x402/payment-response"]is attached to the result. - On the client side (xNUWA), the MCP client will automatically handle the payment and extract payment info.
HTTP/LLM: Payment-Gated Endpoints
import type { NextRequest } from "next/server";
import { X402LlmPayments, type EnsurePaymentConfig } from "@nuwa-ai/x402/llm";
import { privateKeyToAccount } from "viem/accounts";
const seller = privateKeyToAccount(process.env.SERVICE_PRIVATE_KEY as `0x${string}`);
const payments = new X402LlmPayments(); // or pass a FacilitatorConfig
export async function POST(request: NextRequest) {
const config: EnsurePaymentConfig = {
payTo: seller.address,
price: 0.01, // USD
network: "base-sepolia",
config: { description: "My paid API", mimeType: "application/json" },
};
return payments.gateWithX402Payment(request, config, async () => {
// Your upstream work here (call model provider, etc.)
return new Response(JSON.stringify({ ok: true }), { status: 200, headers: { "Content-Type": "application/json" } });
});
}Behavior
- Without an
X-PAYMENTheader the handler returns402and a JSON body describingaccepts(requirements). - With a valid payment: verifies first, runs your handler, then settles before returning. On success, adds
X-PAYMENT-RESPONSEheader with settlement details. - Pricing today is fixed per endpoint invocation; v2
uptoschema-driven pricing is forthcoming.
Facilitator
- The library uses
x402/verifyunder the hood. You can pass aFacilitatorConfigto both MCP and LLM helpers. - With Coinbase’s facilitator, provide
CDP_API_KEY_ID,CDP_API_KEY_SECRET, andCDP_WALLET_SECRET, or importfacilitatorfrom@coinbase/x402and pass it through.
Configuration Notes
priceis in USD. The helpers compute the on-chain amount automatically for the selectednetworkand USDC asset.- Supported networks:
base-sepolia(default) andbase. - For HTTP endpoints you can customize error messages, input/output schemas, and timeouts via
config(PaymentMiddlewareConfig).
Utilities
logPaymentResponseHeader(response)– logs decodedX-PAYMENT-RESPONSE.decodePaymentResponseHeader(responseOrHeaders)– parse the header programmatically.
See Also
- End-to-end usage in examples/nextjs (OpenRouter proxy and paid MCP server). You can exercise a hosted build at https://xnuwa.app.
