Skip to content

MCP Shield

Tool calls and tool results, checked at the edge.

MCP Shield reads the JSON-RPC between AI clients and your own MCP server. It applies method and tool allowlists, inspects tool arguments and tool results for prompt injection and leaked credentials, and limits requests per token. Opt-in per endpoint, and it starts in log mode.

Put your MCP server behind it
OPENWAFMCP Shield

Your MCP server behind the edge, one endpoint at a time

Add an endpoint with kind: mcp to a site. From then on, every JSON-RPC message to it is checked against your method and tool lists and the injection and credential detectors.

How it works

Eight steps between the client and your server

An MCP endpoint is an entry of the site’s Bots and AI agents endpoints with kind: mcp. The site’s Bots and AI agents policy applies first, as to any request; then, for the first endpoint whose path prefix and HTTP methods match:

  1. 1

    Endpoint

    The request matches the path prefix of your MCP server, for example /mcp, and one of its HTTP methods: POST, GET or DELETE.

  2. 2

    Rate

    With a per-token limit, the request counts per minute first against a per-IP bucket (a /64 in IPv6) of 10 × the limit, then against the normalised Authorization header, or the client IP when there is none.

  3. 3

    Size

    The POST body is read up to max_request_kb, 256 KiB by default.

  4. 4

    JSON-RPC

    The body must be one JSON-RPC 2.0 message or a non-empty batch of them.

  5. 5

    Policy

    Each client message with a method is checked against the allowed methods, and each tools/call against the denied and allowed tools.

  6. 6

    Request inspection

    Tool arguments, resources/read parameters and prompt arguments go through the detectors.

  7. 7

    Your server

    The request goes on unchanged, except that Accept-Encoding is removed so the response arrives readable.

  8. 8

    Response inspection

    JSON responses are checked whole; SSE streams event by event, each event forwarded as soon as it has been checked.

Never changed: Mcp-Session-Id, MCP-Protocol-Version, Last-Event-ID, SSE event ids, DELETE requests, the framing of GET streams and 202 answers. MCP Shield does not authenticate anyone: your server still checks its tokens.

Policy

Method and tool allowlists

Allow only what your server implements and what this endpoint should offer. An endpoint needs only its type and path prefix; every other setting has a default.

  • Allowed methods

    1 to 64 JSON-RPC methods, exact or a prefix such as notifications/*. The default is the twelve standard MCP methods, from initialize and tools/call to logging/setLevel.

  • Allowed and denied tools

    Up to 200 names each, matched exactly against the name of tools/call. An empty allowed list means any tool that is not denied.

  • Size and rate

    A request body cap of 1 to 1024 KiB and an optional limit of requests per minute per token. Each edge node counts on its own, so with N nodes a token can reach N times the limit.

The same change works from the dashboard (AI Crawl Control → MCP Shield), the API and the ai_agents_settings tool of the OpenWAF MCP server. The endpoint list is replaced as a whole, and every change is a new, versioned configuration with its reason. Every field is in the settings reference.

Inspection

What is inspected, and what is not

Deterministic patterns, not a model. They stop known shapes of prompt injection and credential leaks; they do not prove a message is safe.

Inspected

  • inspect_requestsClient to server: the arguments of tools/call and prompts/get, and the parameters of resources/read.
  • inspect_responsesServer to client: every string in result and error of the responses to requests with an id, tool descriptions of tools/list included, and the params of the server’s own requests (sampling/createMessage, elicitation/create).

Detector families

  • pi.*Instruction overrides, system-prompt extraction, jailbreaks, forged system messages, tool calls and turns, approval bypass, orders in HTML comments or encoded text.
  • agent.*Destructive commands such as rm -rf / or DROP TABLE.
  • exfil.*Remote scripts piped to a shell, secret harvesting, exfiltration through a rendered image or link.
  • hidden.*Zero-width characters, Unicode tag characters, CSS-hidden text.
  • dlp.*AWS, GitHub, Stripe, Slack, SendGrid, Mailgun, OpenAI, Anthropic and OpenWAF keys, private keys and database URLs, stored redacted to their first four characters.
  • mcp.*Policy hits: method not allowed, tool denied or not allowed, rate, parse error, invalid request, too large.

The same 27 injection detectors as OpenWAF’s AI-endpoint protection, in English and Spanish. Each runs only when one of its keywords appears in the text.

Not inspected

  • Anything a pattern does not describe: paraphrases, other languages and encodings the detectors do not cover. There is no semantic classifier and no language model.
  • The content of notifications, in either direction. Client notifications still go through the allowed methods.
  • The client’s answers to sampling/createMessage and elicitation/create. The server’s requests themselves are inspected but only logged, never replaced.
  • JSON responses and SSE events over 2 MiB, and responses that still arrive compressed. They pass unchanged and are counted as uninspected.
  • Request bodies over max_request_kb in log mode (in enforce they get 413).
  • The parameters of other methods, such as completion/complete, logging/setLevel and the list methods.
  • Headers and query strings. Resource URIs and prompt names have no allow or deny list.
  • The token itself: MCP Shield never validates it, your server does.

Rollout

Log first, then enforce

The site’s Bots and AI agents mode decides whether the edge acts; each inspection setting, off, log or block, decides what to do with a detection. In log mode nothing is blocked, whatever the inspection settings say.

  1. 1

    Start in log

    Mode log and both inspections in log, the defaults. Send real traffic for a few days and read the report, the events and the uninspected count.

  2. 2

    Fit the policy

    Remove the methods your server does not implement, deny the tools this endpoint should not offer, and set a per-token limit above your legitimate peak.

  3. 3

    Check the bot policy

    In enforce it applies to the endpoint before MCP Shield. MCP clients built on Node.js or Python SDKs usually count as unverified_automation.

  4. 4

    Enforce the policy

    Switch the mode to enforce: methods, tools, size and rate are applied. Inspection in log keeps only recording.

  5. 5

    Block, if you choose

    Set inspection to block only after reviewing its events: a tool result that legitimately quotes attack text would be replaced by an error.

The OpenWAF MCP server, mcp.openwaf.dev, is the first endpoint behind MCP Shield. It went through these same steps: log first, then enforce for the method policy, with tool-result inspection kept in log and its events treated as alerts.

JSON-RPC errors

Blocks the client can show, without dropping the session

MCP clients treat an HTTP error as a transport failure. So policy and inspection blocks answer HTTP 200 with a JSON-RPC error carrying the id of the blocked request: the assistant shows it for that one call and the session goes on.

Every answer in enforce

  • 200 · -32601Method not in the allowed methods
  • 200 · -32602Tool denied, or missing from a non-empty allowed list
  • 200 · -32001Injection or credential in the request, with request inspection on block
  • -32001Injection or credential in the response, with response inspection on block: that message, or that SSE event, is replaced with the same id and your server’s status
  • 429 · -32000Over the per-token limit, with Retry-After
  • 413 · -32600Body over max_request_kb
  • 400 · -32700Body is not JSON (id null)
  • 400 · -32600JSON but not JSON-RPC 2.0, or an empty batch (id null)
  • 202A blocked notification, with an empty body

What the client receives

blocked by OpenWAF MCP Shield: followed by the detection ids. error.data.openwaf repeats the event kind and the ids, so a client can tell a shield block from an error of your server.

{"jsonrpc": "2.0", "id": 7,
 "error": {"code": -32602,
   "message": "blocked by OpenWAF MCP Shield: mcp.tool_denied",
   "data": {"openwaf": {"kind": "mcp_blocked_tool",
                        "detections": ["mcp.tool_denied"]}}}}

Batches: if any message is blocked, the edge answers the whole batch and nothing reaches your server. Blocked messages get their own error; every other request with an id gets -32600 batch rejected by OpenWAF MCP Shield.

In log mode none of these answers are sent: the message passes and its event is recorded with blocked: false. Every code and event kind is on the errors and events page.

Events and docs

See what it would block

Every policy hit and detection is an event and a counter, in log mode as in enforce.

Events and counters

  • Each event carries the JSON-RPC method, the tool, the detector ids and a token fingerprint: the first 8 bytes of an HMAC-SHA256 of Authorization with a per-zone key, never the token.
  • Counters per endpoint (messages, blocked, detections, uninspected) and per tool, for up to 50 tools.
  • Live security events under the rule name MCP Shield, and 30 days of history.
  • In the dashboard (AI Crawl Control → MCP Shield), the API, openwaf-cloud ctl ai mcp and the ai_agents_report MCP tool.

Put your MCP server behind the edge.

MCP Shield is part of Bots and AI agents in OpenWAF, free during early access. Add an MCP endpoint in log mode and see what it would block before it blocks anything.