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 ────┤
│ │ │
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;
}
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
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 }] };
})
);
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:
-
Agent calls tool → MCP client injects
LEMONCAKE_PAY_TOKENfrom its env - SDK validates token → checks signature, expiry, remaining balance
- Handler executes → your actual logic runs
- SDK charges token → atomic debit from Pay Token balance
-
Receipt returned →
x402Receiptappended to tool result - 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):
- Sign up at lemoncake.xyz
- Top up $5+ USDC
- Copy your Buyer JWT
- Add
LEMON_CAKE_BUYER_JWTto any of the MCPs above
As a developer (add billing to your MCP server):
npm install @lemon-cake/mcp-sdk- Wrap handlers with
lc.charge({ price: 0.01 })(handler) - 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)