MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Configuration & Environment

Elicitation Without Rate Limiting

MEDIUMCWE: CWE-799Rule: MCP-281

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.

What it is

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.

Why it matters for MCP

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).

Vulnerable example

example.py
1
from fastmcp import FastMCP, Context
2
3
mcp = FastMCP("my-mcp")
4
5
@mcp.tool()
6
async def confirm_action(ctx: Context) -> str:
7
    # VULNERABLE: no rate limiter. A prompt-injection payload that loops
8
    # this tool floods the user with elicitation dialogs.
9
    return await ctx.elicit("Continue?", {"ok": "boolean"})

Secure example

example.py
1
from slowapi import Limiter
2
from slowapi.util import get_remote_address
3
from fastmcp import FastMCP, Context
4
5
limiter = Limiter(key_func=get_remote_address)
6
mcp = FastMCP("my-mcp")
7
8
@mcp.tool()
9
@limiter.limit("5/minute")
10
async def confirm_action(ctx: Context) -> str:
11
    return await ctx.elicit("Continue?", {"ok": "boolean"})

How MCPSafe detects this

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.

Further reading

  • MCP Elicitation Specification
  • CWE-799: Improper Control of Interaction Frequency
  • OWASP — Denial of Service Cheat Sheet

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now