npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@feldmannn/x402-mcp

v0.1.1

Published

Paywall any MCP tool with an x402 v2 payment scheme. Scheme-agnostic: works with webcash (x402-webcash), USDC (exact), or any future x402 scheme.

Downloads

259

Readme

@feldmannn/x402-mcp

Paywall any MCP tool with an x402 v2 payment scheme.

Scheme-agnostic. Works with webcash (via x402-webcash), exact/USDC, or any future x402 scheme — you supply a Settler.

Note on naming: the unscoped x402-mcp package on npm is a separate, EVM-only / x402-v1 implementation by Vercel. This package is independent: x402 v2, scheme-agnostic, no framework lock-in. The wire dialect (org.x402/payment request _meta, org.x402/challenge result _meta mirror) is intentionally distinct.

Install

npm install @feldmannn/x402-mcp

Peer-depends on @modelcontextprotocol/sdk ^1.29.0.

Use

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createPaywall } from "@feldmannn/x402-mcp";
import { Facilitator, decimalToWats, webcashSettler } from "x402-webcash";
import { z } from "zod";

const server = new McpServer({ name: "premium-search", version: "0.1.0" });
const facilitator = new Facilitator({ url: "http://localhost:4021" });

const paywall = createPaywall({
  settler: webcashSettler(facilitator),
  scheme: "webcash",
  asset: "webcash",
  network: "webcash:mainnet",
  payTo: "https://webcash.org",
  onSettled: (out) => myWallet.put(out.secret),
});

server.registerTool(
  "premium_search",
  { title: "Premium search", inputSchema: { query: z.string() } },
  paywall.gate(
    {
      amount: decimalToWats("0.01").toString(),
      resourceUrl: "mcp://premium-search/premium_search",
    },
    async ({ query }) => ({
      content: [{ type: "text", text: await actuallyDoTheSearch(query) }],
    }),
  ),
);

How it works

Two-call flow, no MCP spec change:

  1. Caller invokes the tool with no payment metadata. The wrapper returns an MCP error result whose content carries the x402 v2 PaymentRequired challenge as JSON. The same challenge is mirrored into the result's _meta under org.x402/challenge for clients that prefer the structured path.
  2. Caller re-invokes with the payment payload (base64-encoded x402 v2 PaymentPayload) in the request's _meta under org.x402/payment. The wrapper hands it to the configured Settler, persists the output via onSettled, then runs the wrapped handler.

Why _meta and not a tool arg

Two reasons, neither of them "it's secret-safe by default":

  1. The tool's input schema stays clean. tools/list does not surface a _payment field that LLM callers would otherwise be tempted to populate from prompt context. Payment is protocol-level, not domain-level.
  2. _meta is the canonical MCP extensibility channel — progress tokens, related-task IDs, and other non-domain fields already live there. Future MCP tooling will route around _meta correctly when the args-vs-metadata distinction matters.

_meta does not, by itself, keep payment proofs out of debug logs. Sellers and clients MUST scrub _meta["org.x402/payment"] from anything they ship to log aggregators. The improvement over args is real (cleaner schema, no LLM confusion) but log discipline remains the seller's responsibility.

Namespace keys (wire-protocol constants)

  • org.x402/payment — request _meta key carrying the payment payload (base64 JSON).
  • org.x402/challenge — result _meta key mirroring the PaymentRequired challenge on a 402 response.

DO NOT change these. They define the dialect.

Writing a Settler for a new scheme

A Settler is a function that takes an x402 PaymentPayload + PaymentRequirements and returns SettleResult<Output>. The Output is whatever the seller needs to persist (a new bearer secret for webcash, a tx receipt for an on-chain scheme, nothing for a scheme that settles directly to payTo).

const mySettler: Settler<MyPayload, MyOutput> = async (payload, requirements) => {
  // ... talk to your facilitator / chain / issuer ...
  if (!success) return { ok: false, reason: "...", retriable: false };
  return { ok: true, transaction: "...", output: { ... } };
};

The retriable flag matters: false means the caller MUST NOT submit a new payment for the same logical call (the input has moved or been definitively rejected); true means they can.

Operator security: the recovery log

If onSettled throws, the wrapper writes a [x402-mcp][CRITICAL] persistence_failure ... line to stderr containing the full scheme-specific settler output. This is the deliberate last-resort witness — without it, a transient disk error during persistence would silently destroy funds.

The output is whatever the settler returned. For x402-webcash, that is the new bearer secret in plaintext. Anyone who reads the log line can spend it.

Operator responsibilities:

  • Do NOT ship these lines to third-party log aggregators (Datadog, Loggly, Splunk Cloud, etc.) without redacting the output= field. Treat stderr from a paywalled seller process the same way you'd treat a .env file.
  • Provide an onSettledRecovery callback that writes to a sink independent of your primary persistence (e.g., an encrypted file on disk). If onSettledRecovery also fails, you can still recover from stderr — but a healthy operator should never need to.
  • Search by transaction id, not by secret: the error result returned to the caller embeds transaction=<id> so you can correlate the failed call with the stderr line without grepping for secret material.

License

MIT