DEV Community

LemonCake
LemonCake

Posted on

How to Monetize Your MCP Server with Pay-Per-Call USDC Payments

How to Monetize Your MCP Server with Pay-Per-Call USDC Payments

If you've built an MCP server, you've probably wondered: how do I actually charge for this?


The Monetization Gap in the MCP Ecosystem

The MCP ecosystem is exploding. Thousands of servers listed on registries, npm, Glama, Smithery. But look closely at the pricing model for almost all of them:

Free.

Not "freemium." Just free. With a GitHub Sponsors link buried at the bottom that nobody clicks.

This makes sense for early adoption — you want distribution. But it's not a business. And the obvious alternatives don't fit agentic workflows:

Model Problem
Monthly subscription AI agents don't have credit cards. Who signs up?
API key + quota Rate limits = agent blocking at 3am. Friction.
Per-seat SaaS Makes sense for humans, not for 100 parallel agents

There's a mismatch. MCP tools are called programmatically, at scale, in automated pipelines. The payment model should match.

That's the gap I wanted to fill.


The Pay Token Pattern

Here's the insight: treat every tool call like an API call with a receipt.

An agent that can call search_markets() or place_order() should be able to pay for those calls — automatically, with no human approval per call, within pre-set limits.

The pattern looks like this:

User (human)                    MCP Client            MCP Server (your tool)
     │                               │                        │
     ├─ Top up $20 USDC once ───────>│                        │
     ├─ Set daily cap $5 ───────────>│                        │
     │                               │                        │
     │ (agent runs autonomously)     │                        │
     │                               ├─ call_tool(args) ─────>│
     │                               │   + LEMONCAKE_PAY_TOKEN │
     │                               │                        ├─ charge $0.01
     │                               │<─ result + receipt ────┤
     │                               │                        │
Enter fullscreen mode Exit fullscreen mode

The key element is the Pay Token — a short-lived, scoped JWT that:

  • Carries a spend limit the agent cannot exceed
  • Can be revoked instantly (kill switch)
  • Doesn't expose your wallet or API key to the MCP server
  • Produces a machine-readable receipt on every successful charge

The Safety Mechanic: Spend Caps the Agent Can't Override

This is what took the most thought to get right.

The obvious approach is trusting the agent to "spend responsibly." This doesn't work. An injected prompt, a hallucinated loop, or a misconfigured instruction can rack up charges before you notice.

The safer design: the cap is enforced server-side, outside the agent's call graph.

// alpaca-guard-mcp: preflight before every order
async function guarded_place_order(args: PlaceOrderArgs) {
  // 1. Resolve notional cost
  const notional = args.qty * (args.limitPrice ?? await get_latest_quote(args.symbol));

  // 2. Preflight against cap.json — BEFORE any Alpaca call
  const cap = await readCap(); // { dailyLimitUsd: 50, todayUsedUsd: 12.50 }
  const remaining = cap.dailyLimitUsd - cap.todayUsedUsd;

  if (notional > remaining) {
    return {
      allowed: false,
      status: "BUDGET_EXCEEDED",
      hint: `This order would cost ~$${notional} but only $${remaining} remains under today's $${cap.dailyLimitUsd} cap.`
    };
  }

  // 3. Only then: call Alpaca
  const order = await alpaca.placeOrder(args);

  // 4. Record the charge
  await recordCharge(notional);
  return order;
}
Enter fullscreen mode Exit fullscreen mode

The agent sees the BUDGET_EXCEEDED structured response and can explain it to the user. It cannot retry past the cap. There's no agent-side override.


Adding Billing to Your Own MCP Server

If you've built an MCP server and want to add pay-per-call billing, it's three lines:

npm install @lemon-cake/mcp-sdk
Enter fullscreen mode Exit fullscreen mode
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createLemonCakeSDK } from "@lemon-cake/mcp-sdk";

const server = new McpServer({ name: "my-server", version: "1.0.0" });
const lc = createLemonCakeSDK({ sellerKey: process.env.LEMONCAKE_SELLER_KEY });

server.tool(
  "my_paid_tool",
  { query: z.string() },
  // Wrap your handler with lc.charge()
  lc.charge({ price: 0.05 })(async ({ query }) => {
    const result = await doExpensiveOperation(query);
    return { content: [{ type: "text", text: result }] };
  })
);
Enter fullscreen mode Exit fullscreen mode

Demo Mode: if LEMONCAKE_SELLER_KEY is absent, lc.charge() is a no-op. Your tool runs, charges are logged to stderr, no real billing. Safe for local dev.

Live Mode: set LEMONCAKE_SELLER_KEY in your server env. Every successful tool call deducts from the caller's Pay Token balance and returns a receipt.


The Full Flow for a Paid Tool Call

What actually happens when an agent calls a billed tool:

  1. Agent calls tool → MCP client injects LEMONCAKE_PAY_TOKEN from its env
  2. SDK validates token → checks signature, expiry, remaining balance
  3. Handler executes → your actual logic runs
  4. SDK charges token → atomic debit from Pay Token balance
  5. Receipt returnedx402Receipt appended to tool result
  6. Agent gets result + receipt → can log, display, or ignore

If the token is expired, exhausted, or revoked at step 2, the tool returns a structured error — the agent never calls your downstream API.


Real MCPs Using This Pattern

I've shipped several MCP servers using this model:

agent-payment-mcp — pays for calls to 10+ APIs (Serper, Hunter, Jina, Firecrawl, Slack). Free demo mode, no signup.

alpaca-guard-mcp — wraps Alpaca trading API with a hard daily USD cap. Paper trading default.

polymarket-guard-mcp — Polymarket prediction markets with USDC billing. Read-only free.

xstocks-mcp — tokenized US stocks on Solana via Jupiter DEX. $0.10/trade.

All use the same pattern: free read tools, charged write tools, spend caps enforced before any destructive operation.


The x402 Connection

If you've been following the x402 protocol — HTTP-native machine payments — this is the same idea applied to MCP.

agent-payment-mcp speaks x402: every successful charge returns an x402Receipt, and upstream 402 challenges from APIs are parsed and handled automatically. Agent code written for on-chain x402 works unmodified.

The eventual goal is for the cap ledger to live on a server-side API rather than a local file — same daily cap mechanic, but shared across MCP clients and auditable. That's the Phase B roadmap item.


Getting Started

As a user (call billed tools):

  1. Sign up at lemoncake.xyz
  2. Top up $5+ USDC
  3. Copy your Buyer JWT
  4. Add LEMON_CAKE_BUYER_JWT to any of the MCPs above

As a developer (add billing to your MCP server):

  1. npm install @lemon-cake/mcp-sdk
  2. Wrap handlers with lc.charge({ price: 0.01 })(handler)
  3. Apply to lemoncake.xyz to list in the marketplace

Demo mode works immediately with no signup. You can ship a billed tool today and test the full flow before going live.


Questions? Drop them below or find me at @evidai. The spec for the Pay Token format and x402 compatibility is in the agent-payment-mcp README.


Tags: mcp, ai, agents, payments, usdc, claude, typescript

Top comments (0)