AI & MCP

Rate limits for an MCP server: window, quota and a useful 429

An MCP server handles bursts with a per-account counter, a declared window and a 429 with Retry-After. Here are the numbers and the trade-offs.

Key points

  • The MCP specification asks servers to rate limit tool invocations but leaves the mechanism open.
  • The counter needs the right key: account for an authenticated client, IP for anonymous traffic.
  • A useful 429 declares limit, plan and seconds to wait, so the client knows when to come back.

An MCP server handles bursts with a per-account counter, a declared window and a 429 response that says when to retry. The rest is instrumentation.

The key matters more than the number

A limit per IP address punishes an office behind a NAT and does not stop anyone rotating addresses. A limit per token follows the account: the team shares one quota, and a client cannot dodge it by changing network. That is what EneUI does: counter on the account id when a bearer token arrives, counter per IP when the call is anonymous.

Four plans, one declared ceiling

PlanRequests per minuteHourly ceilingCounter key
Anonymous (per IP)1207,200IP address
Free1207,200account
Pro60036,000account
Team, business, premium1,20072,000account

The hourly column is the per-minute limit multiplied by 60: a declared ceiling, not a second quota. A per-minute counter cannot stop a client spending everything in ten seconds, and that is the first trade-off to accept.

Fixed or sliding window

A fixed window costs a map and a timestamp: it resets every 60 seconds and keeps no history. The flaw is the edge: a client can send 600 requests at 12:00:59 and another 600 at 12:01:00, twice the limit in two seconds. If an edge burst breaks the backend, use a sliding window or a token bucket, and bring shared memory.

What a 429 must say

curl -si https://ui.eneawork.it/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | head -n 9

The command shows the status and headers of the response. When the counter is full you get 429, Retry-After: 60 and a JSON-RPC body with code -32002 that names the limit and the plan. A client reading that message knows whether to wait or ask for an upgrade; a client receiving a mute 429 retries at once and makes things worse.

The counter lives in memory

EneUI keeps its windows in a Map keyed by account. That is right for a single process and wrong for two instances: after a restart the count starts again at zero, and with two processes the real limit doubles. With more instances the counter belongs in Redis or the database, otherwise the number on the list page is a promise the system does not keep.

The limitation

The EneUI response carries no quota headers: a client discovers the limit only by hitting it. There is also no declared cost per request, so an agent cannot plan a budget before calling. A well-behaved client reads the 429, waits the seconds it names and reduces the number of exposed tools instead of increasing retries.

Where to continue

The authentication that makes a per-account count possible is in OAuth for an MCP server, and the shape of the tools that spend quota is in designing an MCP tool. For the protocol and its transports read what MCP is. The catalogue behind the server is 111,985 components and 1,556 blocks; a record with a declared MIT licence upstream is dqnamo agent dock.

Frequently asked questions

What limit should a new MCP server start with?

Start from a measurable, low number: EneUI exposes 120 requests per minute for anonymous traffic (IP gate), 120 on the free plan, 600 on pro and 1,200 on team, read in backend/mcp.js and backend/entitlements.js on 1 November 2026. Raise it when logs show accounts blocked mid-task, not when a client complains.

Should I send a 429 or a JSON-RPC error in the body?

Both: the HTTP 429 status tells the transport this is a limit, and the JSON-RPC body with code -32002 tells the client which limit and which plan. Add Retry-After with the seconds left, otherwise the client retries at once.

Do I count requests per IP or per token?

Per token when the client is authenticated, per IP when it is anonymous. The IP alone punishes people sharing a NAT and rewards rotating addresses. EneUI applies the IP gate only to traffic without credentials.

Fixed window or token bucket?

A fixed window costs one map and works for a single process. A token bucket smooths the edge burst but needs shared state, so Redis or a database once the server runs more than one instance.

Does the MCP protocol define a rate limit?

No, it does not fix the mechanism. The 2025-06-18 revision lists “Rate limit tool invocations” among server requirements on the Tools page, so the limit exists but the server implements it, with its own keys and responses.