You built an MCP server. It works. Agents call your tools, get results, everybody's happy — except you're paying for compute and API calls out of pocket.
You want to charge for it. But now you're looking at building: payment verification, usage tracking, API key management, subscription tiers, credit balances, revenue splits, Stripe integration, webhook handling. That's 2–4 weeks of work that has nothing to do with the tool you actually built.
This is the billing problem every MCP server operator hits. You can build tools in a weekend, but monetizing them takes weeks. Most operators choose "not monetizing" and either burn money or shut down.
mcp-billing-gateway solves this. It's a reverse proxy that sits in front of your MCP server and handles all billing — Stripe subscriptions, per-call credits, and x402 crypto payments. Your server stays unchanged. You register it, set pricing, and start earning.
Architecture: How It Works
AI Agent (caller)
│
├─ Authorization: Bearer cgwcl_...
│
▼
┌──────────────────────────┐
│ mcp-billing-gateway │
│ │
│ 1. Authenticate caller │
│ 2. Check credits/sub │
│ 3. Debit payment │
│ 4. Forward JSON-RPC │
│ 5. Record usage │
│ 6. Return response │
└──────────┬───────────────┘
│
▼
┌──────────────────────────┐
│ Your MCP Server │
│ (unchanged, untouched) │
└──────────────────────────┘
Your MCP server never sees billing logic. The gateway proxies JSON-RPC requests, handling authentication, payment verification, and usage metering transparently. If a caller doesn't have credits or a valid subscription, they get a 402 Payment Required before your server is even contacted.
Step 1: Register as an Operator
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/register \
-H "Content-Type: application/json" \
-d '{
"email": "you@yourcompany.com",
"name": "Your Company"
}'
Response:
{
"operator_id": "op_01jvz...",
"api_key": "cgwop_abcd1234...",
"stripe_onboard_url": "https://connect.stripe.com/setup/abc123..."
}
Save that API key — it's shown once. Visit the stripe_onboard_url to connect your Stripe account (business info + bank account for payouts). This uses Stripe Connect Express, so you get a managed account without handling PCI compliance yourself.
Step 2: Register Your MCP Server
Point the gateway at your upstream server:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/servers \
-H "Authorization: Bearer cgwop_abcd1234..." \
-H "Content-Type: application/json" \
-d '{
"name": "Weather MCP",
"description": "Real-time weather data for AI agents",
"upstream_url": "https://your-mcp-server.com/mcp",
"proxy_slug": "weather",
"auth_mode": "header",
"upstream_auth_token": "your-server-secret",
"transport": "http",
"is_public": true
}'
Your server is now proxied at:
https://mcp-billing-gateway-production.up.railway.app/proxy/weather
The auth_mode field controls how the gateway authenticates to your upstream: header injects a Bearer token, query appends it as a query parameter, none sends requests unauthenticated. The upstream_auth_token is your server's own auth — callers never see it.
Step 3: Set Pricing
The gateway supports three billing models. You can have multiple plans per server.
Per-call (pay-as-you-go):
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/servers/srv_01jvz.../plans \
-H "Authorization: Bearer cgwop_abcd1234..." \
-H "Content-Type: application/json" \
-d '{
"name": "Pay-as-you-go",
"billing_model": "per_call",
"price_per_call_usd_micro": 10000,
"free_calls_per_month": 100,
"is_default": true
}'
That's $0.01 per call (prices are in micro-units: 10,000 micro = $0.01) with 100 free calls per month. The free tier resets monthly.
Monthly subscription:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/servers/srv_01jvz.../plans \
-H "Authorization: Bearer cgwop_abcd1234..." \
-H "Content-Type: application/json" \
-d '{
"name": "Pro",
"billing_model": "subscription",
"subscription_price_usd_cents": 999,
"subscription_interval": "monthly",
"subscription_call_limit": 10000,
"is_default": false
}'
$9.99/month for up to 10,000 calls. Managed via Stripe, with automatic period tracking and cancellation handling.
Tiered pricing:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/servers/srv_01jvz.../plans \
-H "Authorization: Bearer cgwop_abcd1234..." \
-H "Content-Type: application/json" \
-d '{
"name": "Volume",
"billing_model": "tiered",
"tiers": [
{"up_to": 1000, "price_usd_micro": 0},
{"up_to": 10000, "price_usd_micro": 5000},
{"up_to": null, "price_usd_micro": 10000}
],
"is_default": false
}'
First 1,000 calls free, next 9,000 at $0.005 each, everything above at $0.01.
Step 4: Callers Start Using Your Server
From the caller's perspective, the integration is straightforward. Using the TypeScript SDK:
import { GatewayCallerSDK } from '@mcp-billing-gateway/caller-sdk';
const client = new GatewayCallerSDK({
baseUrl: 'https://mcp-billing-gateway-production.up.railway.app'
});
// Register (one-time)
const { api_key } = await client.register('bot@myapp.com', 'My Agent');
client.setApiKey(api_key);
// Add credits ($10.00)
await client.topupCredits(1000, 'pm_stripe_payment_method_id');
// Call your tool — billing happens automatically
const result = await client.callTool('weather', 'get_weather', {
city: 'Berlin'
});
console.log(result);
Or with plain curl:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/proxy/weather \
-H "Authorization: Bearer cgwcl_caller_key..." \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "req-1",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {"city": "Berlin"}
}
}'
The gateway authenticates the caller, checks their credit balance, debits the call cost, forwards the JSON-RPC request to your server, and returns the response. If the upstream returns an error, credits are automatically refunded.
x402 Crypto Payments
For agent-to-agent transactions where callers have crypto wallets, the gateway supports x402 payments — USDC on Base chain. No API key needed. The caller sends a payment claim header:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/proxy/weather \
-H "X-402-Payment: <base64-encoded-payment-claim>" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "req-1",
"method": "tools/call",
"params": {"name": "get_weather", "arguments": {"city": "Berlin"}}
}'
If a caller sends a request without valid payment, they get a structured 402 response with pricing info:
{
"jsonrpc": "2.0",
"id": "req-1",
"error": {
"code": 402,
"message": "Payment Required",
"data": {
"price_usd_micro": 10000,
"x402_address": "0x...",
"chain": "base"
}
}
}
This means your single server can accept both fiat (Stripe) and crypto (USDC) payments simultaneously, depending on what the caller supports.
Revenue and Analytics
Track how your server is being used and how much you're earning:
# Usage analytics
curl "https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/servers/srv_01jvz.../usage?from=2026-04-01&to=2026-04-15" \
-H "Authorization: Bearer cgwop_abcd1234..."
The response includes usage broken down by day, by tool name, by billing rail (fiat vs. x402), and top callers. You see exactly which tools are popular and which pricing model callers prefer.
# Revenue and payouts
curl https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/revenue \
-H "Authorization: Bearer cgwop_abcd1234..."
The default revenue split is 85/15 — you keep 85% of each call's revenue, the platform takes 15%. When you're ready to collect:
curl -X POST https://mcp-billing-gateway-production.up.railway.app/api/v1/operator/payouts/request \
-H "Authorization: Bearer cgwop_abcd1234..."
Funds transfer to your linked Stripe account within 1–2 business days. Minimum payout: $1.00.
Self-Hosting
The gateway is open for self-hosting if you want full control:
docker run -p 3000:3000 \
-e DB_PATH=/data/billing.db \
-e STRIPE_SECRET_KEY=sk_test_... \
-e STRIPE_WEBHOOK_SECRET=whsec_... \
-e PLATFORM_URL=https://your-domain.com \
-v billing-data:/data \
mcp-billing-gateway
SQLite for storage (no Postgres dependency), Stripe for payment processing, and the full operator + caller API available at your own domain. Set DEFAULT_TAKE_RATE_BPS to adjust the revenue split (default 1500 = 15%).
What You Don't Have to Build
Here's what the gateway handles so you don't have to:
| Concern | Without Gateway | With Gateway |
|---|---|---|
| API key management | Build auth system | Built-in (hashed, scoped, revocable) |
| Payment processing | Integrate Stripe SDK | Pre-integrated via Stripe Connect |
| Usage metering | Build tracking system | Per-call metering with breakdown |
| Subscription management | Handle Stripe webhooks | Automatic period tracking + cancellation |
| Credit system | Build ledger + balance tracking | Prepaid credits with auto-refund on errors |
| x402 crypto payments | Implement payment verification | Built-in x402 validation + anti-replay |
| Revenue analytics | Build dashboard | Usage by day, tool, billing rail, caller |
| Payouts | Manual Stripe transfers | One API call, automatic splits |
Getting Started
- Register as an operator (30 seconds)
- Complete Stripe onboarding (2 minutes)
- Register your server with a proxy slug (1 minute)
- Create a pricing plan (1 minute)
- Share the proxy URL with your users
Your MCP server is now monetized. No code changes to your server, no new dependencies, no payment infrastructure to maintain.
Live gateway: mcp-billing-gateway-production.up.railway.app
SDK docs: sapph1re/mcp-billing-gateway-sdk
Glama listing: glama.ai/mcp/servers/sapph1re/mcp-billing-gateway-sdk
Top comments (0)