DEV Community

Zeke
Zeke

Posted on

My MCP Server Got Rate-Limited After Auth. Here's the 5-Line Fix.

A Sentry MCP user reported it on March 18: "all API calls being rate-limited within a few minutes of auth." The OAuth handshake works fine. It's the calls after auth that quietly burn the budget, one runaway automation loop already cost a team $47,000 in eight hours.

If you run an MCP server today, that's the bill you wake up to. Not a security breach. Not a leaked key. Just a polite agent doing what it was told, hammering your paid backend at machine speed because the token said it could.

OAuth answers the wrong question

The MCP spec settled on OAuth 2.1 for auth. That's fine for "is this caller allowed to talk to me." It is silent on "how often, how fast, how much per call." Sentry MCP issue #844 is the canonical example. A user spins up Cursor Automations against the Sentry MCP server, hits 60 req/60s on the underlying Sentry API in seconds, and every subsequent call returns rate-limit errors. The token is valid. The caps under it are not the token's job.

You can't fix this with a tighter scope on the OAuth grant. Scopes say what the caller can touch, not how often. You can't fix it with a static API key for the same reason. The MCP spec leaves billing, throttling, and abuse mitigation entirely to the operator. So the operator has to bring something else.

The missing layer is per-call friction

There are two kinds of friction that work for an agent-to-server path:

  • Compute. The caller spends CPU time on a proof-of-work puzzle for every call. Free in dollars, costs seconds. Caps the throughput of a runaway loop without billing anyone.
  • Sats. The caller pays a Lightning invoice for every call. A few sats per call, settled in under two seconds, no account, no credit card.

Either one slows a runaway loop to a walk. Both work for autonomous agents because neither needs an email address or a confirmation link. The agent just spends something it has, then keeps going.

This is the layer that's missing from the MCP spec, and it's where the $47K bill gets stopped.

The 5-line fix

npm install @powforge/captcha-mcp
Enter fullscreen mode Exit fullscreen mode
{
  "mcpServers": {
    "captcha": { "command": "npx", "args": ["-y", "@powforge/captcha-mcp"] }
  }
}
Enter fullscreen mode Exit fullscreen mode

That's it. Five lines including the install command. The server runs over stdio, exposes three tools (challenge, verify, status), and your agent now has to either solve a PoW puzzle or pay 3 sats over Lightning before it gets a token your backend will accept.

How it works in 30 seconds

The agent calls challenge. Server returns {id, salt, difficulty, signature}. Default difficulty is 14 leading zero bits of SHA-256, which costs the agent about 5 to 10 seconds of CPU on a normal box.

If the agent does not want to spend the seconds, it asks for the L402 path instead. Server returns a bolt11 invoice in the standard WWW-Authenticate header. Agent pays the invoice from any Lightning wallet, gets a payment hash back, and submits that to verify instead of a PoW nonce.

Either path returns the same shape: a 5-minute HMAC-signed token. Your backend calls POST /api/token/verify against the captcha service, gets {valid: true, method, issued_at, expires_at} or {valid: false, reason}, and proceeds.

The cost balance is what makes it work. PoW is free in dollars but caps you to one call every few seconds per CPU. Lightning is 3 sats per call but settles fast. A polite human caller solves PoW once and moves on. A runaway agent grinds to a halt at the speed of compute or burns sats it has to actually have on hand. Either way, your API budget stops bleeding.

Why no accounts

Agents do not have email addresses. They don't click confirmation links. They don't fill out OAuth consent screens. Every existing auth pattern was built for humans and bolted onto agents later, which is why the token-issued-then-hammer pattern is so common. PoW and Lightning both work because neither asks the caller to be a person.

You also don't take on a billing dependency. No Stripe, no metered API key vendor, no per-month minimums. The captcha-mcp server is stdlib-only Node, runs in 80 lines, and the L402 path settles directly to your own LNBits or LND node.

Try it

If you ship an MCP server and you've been losing sleep over what happens after the OAuth handshake, install it tonight. Five lines. Three tools. Your runaway-agent bill stops at the puzzle or the invoice.

Zeke

Top comments (0)