Errors and events

Every JSON-RPC error code and HTTP status MCP Shield returns, why, and the event each one leaves.

On this page

In enforce mode MCP Shield answers some messages itself. This page lists every answer, why it has that shape, and the event each one leaves. In log mode none of these answers are sent: the message passes and only the event is recorded, with blocked: false.

Why most blocks are JSON-RPC errors

MCP clients treat an HTTP error status as a transport failure: the call in progress fails, and some clients drop or retry the whole session. A JSON-RPC error carrying the id of the request is delivered to that one pending call instead. The assistant shows “blocked by OpenWAF MCP Shield: …” for that tool call, and the session keeps working.

So policy and inspection blocks answer HTTP 200 with a JSON-RPC error. An HTTP error status is only used when there is no request id to answer (a body that cannot be parsed) or when the problem is the client as a whole (rate and size).

Every answer

Situation (enforce)HTTPJSON-RPC codeEvent kindDetection id
Over rate_per_token requests per minute429 with Retry-After-32000mcp_rate_limitedmcp.rate_limited
Body over max_request_kb413-32600mcp_invalidmcp.too_large
Body is not JSON400, id null-32700mcp_invalidmcp.parse_error
JSON but not JSON-RPC 2.0, or an empty batch400, id null-32600mcp_invalidmcp.invalid_request
Method not in methods_allowed200-32601mcp_blocked_methodmcp.method_not_allowed
Tool in tools_denied, or missing from a non-empty tools_allowed200-32602mcp_blocked_toolmcp.tool_denied, mcp.tool_not_allowed
Injection or credential in the request, inspect_requests: block200-32001mcp_injection_request, mcp_dlpThe detector ids
Injection or credential in the response, inspect_responses: blockYour server's status-32001, replacing that response message (same id; in a stream, that event)mcp_injection_response, mcp_dlpThe detector ids
A blocked notification202, empty body—mcp_blocked_methodmcp.method_not_allowed

Requests that the server sends to the client (sampling/createMessage, elicitation/create) are only logged, never replaced.

What the client receives

The message is blocked by OpenWAF MCP Shield: followed by the detection ids, separated by commas. error.data.openwaf repeats the event kind and the ids, so a client or an agent 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"]}}}}

A tool result replaced because of a detection looks the same, with code -32001, the id of the original request and the detector ids, for example blocked by OpenWAF MCP Shield: pi.override.en, exfil.markdown_image. The rate limit answers -32000 with the message rate limit exceeded (OpenWAF MCP Shield).

Batches

If any message of a batch is blocked, the edge answers the whole batch and nothing reaches your server. The answer is a 200 array: each blocked message gets its own error, and every other request with an id gets -32600 batch rejected by OpenWAF MCP Shield. A batch with no request ids (notifications only) gets 202.

Events

Each blocked or detected message leaves an event in the Bots and AI agents events, one per kind and message (sampled to at most 200 per site per minute):

KindWhen
mcp_blocked_methodA method outside methods_allowed
mcp_blocked_toolA tool denied or not allowed
mcp_injection_requestA prompt-injection detector matched the request
mcp_injection_responseA prompt-injection detector matched the response
mcp_dlpA credential pattern matched the request or the response
mcp_rate_limitedThe per-token limit was exceeded
mcp_invalidThe body was too large, not JSON or not JSON-RPC

Every event has the detections (id, label and a snippet of at most 160 bytes, redacted for credentials) and an mcp object:

FieldWhat it is
methodThe JSON-RPC method, empty when unknown (invalid body, GET stream)
toolThe tool name of tools/call, the URI of resources/read (shortened) or the prompt name
token_fpA fingerprint of the Authorization header: the first 8 bytes of its SHA-256, in hex. Never the token
blockedtrue when the edge answered or replaced the message, false when it was only logged

Each one is also a security event with the rule name MCP Shield, action block or log, in the live events view and in AI Crawl Control → MCP Shield. From the CLI:

openwaf-cloud ctl ai report example.com --view events --kind mcp_injection_response,mcp_dlp --limit 50

Counters

Per endpoint, the report counts the requests, the client JSON-RPC messages, the messages blocked (answered with a shield error, or responses replaced), the messages with at least one injection or credential detection, and the responses that passed uninspected (too large or still compressed). Per tool, it counts calls, blocks and detections, for up to 50 tools per endpoint; the rest are added up under *. Data is kept for 30 days.

Last updated:

↑↓ to navigate↵ to openesc to close