Ask an agent to “go through every open ticket and tag the stale ones,” and a well-behaved tool will make a few hundred calls in well under a minute. That’s not a bug — it’s exactly what you asked for. But nothing in the MCP spec says what happens when the next request after that is the ten-thousandth one of the day, or when a model gets stuck in a loop calling the same tool over and over because the result never satisfies whatever it’s checking for. MCP defines how a tool call is shaped. It has nothing to say about how many of them a server should accept, which means rate limiting is left entirely to whoever builds the server — and most people building one skip it.
Why the protocol stays silent on this
Every tool call rides over JSON-RPC, covered in the JSON-RPC post, and JSON-RPC has no concept of a request budget either. A client can send one call or a thousand in the same second; the only limits that exist are whatever the transport, the server’s own code, or something sitting in front of it chooses to enforce. That’s a deliberate gap, not an oversight — a protocol spec that tried to mandate a specific numeric limit would be wrong for almost everyone who implements it. A read-only documentation server and a server that calls a metered third-party API per request have completely different tolerances for burst traffic.
The practical effect is that “does this MCP server rate limit itself” is a question you have to go answer for every server you connect, the same way you’d check for command injection or SSRF in a tool’s implementation. It won’t be in the tool description, because a rate limit is an operational property of the server, not part of its public schema.
Two different problems that both look like “too many calls”
It helps to separate what you’re actually defending against, because the fixes aren’t the same.
- A legitimate agent doing a lot of normal work. A bulk operation, a scheduled job, an agent re-checking a slow-to-settle state. This is the “burstiness is normal” point from anomaly detection in MCP traffic — the volume is real and intended, and the risk is cost or hitting an upstream API’s own limit, not malice.
- A model stuck in a retry or reasoning loop. A tool whose result never clearly confirms success can get called again and again by a model trying to resolve its own uncertainty, which is part of why idempotent tool design matters so much for write operations — a loop against a non-idempotent tool doesn’t just waste calls, it repeats the side effect every time.
A flat per-minute cap addresses both the same way, which is part of why it’s the default reach-for tool even though it’s a blunt one.
Where a limit can actually live
There are three places to put this, and they catch different things.
- Inside the tool’s own code. The server tracks calls per caller and returns a normal tool result with
isError: trueand a clear message when a threshold is hit — the same channel covered in MCP tool error handling, so the model gets something it can act on (back off, tell the user, stop retrying) instead of a connection just dropping. - At the underlying API the tool wraps. Plenty of MCP servers are thin wrappers over a REST API that already rate limits by key. That protects the upstream service, but the failure still has to surface back through the tool result in a way the model can understand — a raw
429bubbling up as an opaque error isn’t much better than no limit at all. - In front of the server, at a gateway. A limit enforced where every client’s calls to every server already pass through is the only place that can cap total load per workspace, not just per tool, and apply the same rule regardless of whether the server author thought to add one.
Why this isn’t the same as access control
It’s tempting to treat a rate limit as another row next to the allow, ask, and block rules described in what to look for in a gateway, but it answers a different question. Access control decides whether a client is allowed to call a tool at all. Rate limiting decides how much of an allowed tool a client can use in a window. A client can be fully authorized for a destructive tool and still need its call volume capped, the same way a person with full admin rights to a database still benefits from a connection pool limit. Treating the two as one control tends to produce rules that are either too strict to let real bulk work through, or too loose to catch a loop.
What to check before you connect a server
For anyone adding a new server rather than building one, there isn’t a reliable way to tell from the outside whether it rate limits itself — the tool list and descriptions won’t say. A few practical steps:
- Check the server’s own documentation or source, if it’s open, for any mention of a request limit, queue, or backoff behavior.
- If the server wraps a paid or metered third-party API, assume that API’s limit is the real ceiling and ask what happens to the tool call when it’s hit.
- Run it once through a security scan and a manual test with the MCP Inspector to see what an error response actually looks like, rather than assuming it’s graceful.
- If you can’t verify either way, put the limit in front of it yourself rather than trusting the server to have one.
The bottom line
MCP leaves rate limiting out on purpose, which means it only exists where a server author, an upstream API, or something in front of the connection decided to add it. Before you connect a server that can run up real cost or touch a write tool at volume, it’s worth finding out which of those three it actually has — and if the answer is none of them, that’s worth treating as a gap to close rather than something to discover the first time an agent runs longer than expected.