Configuration & Environment
MCP servers that issue elicitation requests without a rate limiter let a malicious or buggy LLM session spam the user with prompts, exhausting attention and creating click-fatigue conditions where the user approves a hostile request.
This is an improper-control-of-resource-consumption defect (CWE-799). Elicitation prompts are user-facing and require human attention — the MCP Elicitation Specification SHOULD-requires rate limits on the server to prevent prompt-flooding. Without one, an MCP tool whose handler runs in a loop, or one whose execution path is steered by a prompt-injection payload, can issue arbitrarily many elicitation calls per second.
Elicitation is the MCP equivalent of a permission dialog. Rate-limiting is what prevents the pattern from degrading into the click-through fatigue that erodes consent in any prompt-heavy UI: when prompts arrive faster than the user can read, they start dismissing without inspecting — at which point a single hostile prompt slips through. This is especially dangerous for destructive-action confirmations (file deletion, payment confirmation, irreversible API calls) and for elicitation flows that surface attacker-controlled text (a prompt-injection payload re-rendered to the user as a "Continue?" question).
from fastmcp import FastMCP, Context |
mcp = FastMCP("my-mcp") |
@mcp.tool() |
async def confirm_action(ctx: Context) -> str: |
# VULNERABLE: no rate limiter. A prompt-injection payload that loops |
# this tool floods the user with elicitation dialogs. |
return await ctx.elicit("Continue?", {"ok": "boolean"}) |
from slowapi import Limiter |
from slowapi.util import get_remote_address |
from fastmcp import FastMCP, Context |
limiter = Limiter(key_func=get_remote_address) |
mcp = FastMCP("my-mcp") |
@mcp.tool() |
@limiter.limit("5/minute") |
async def confirm_action(ctx: Context) -> str: |
return await ctx.elicit("Continue?", {"ok": "boolean"}) |
MCPSafe fires when the file registers MCP tools that call `elicit()` or `elicitInput()` and no rate-limit identifier is present file-wide. Allow-listed identifiers that silence the finding: `slowapi`, `RateLimiter`, `ratelimit`, `rate_limit`, `rateLimit`, `express-rate-limit`, `p-throttle`, `bottleneck`, `Limiter`, `throttle`, `Throttle`, and the `@RateLimit` decorator. The v1 detection is single-file: if the rate limiter is wired in a sibling middleware module, the rule will still fire — silence with `# nosem` after review or import the limiter symbol locally so the relationship is auditable in the rule file.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now