A custom rule engine is a webhook on your own server that MCP Manager calls when a gateway rule using the Custom provider fires. Your server inspects the message and tells the gateway one of four things: pass it through, modify it, block it, or signal that it couldn’t decide. This page is the developer reference for that webhook — the full request/response contract, so you can stand up an engine in any stack. This is the build-it-yourself path. To register an engine in the UI and understand the surrounding settings — URL, HTTP method, headers, header forwarding, IP allowlisting, testing, and deletion — see Custom Rule Engines. For managed alternatives that need no code, see Amazon Bedrock and Lakera Guard.Documentation Index
Fetch the complete documentation index at: https://docs.mcpmanager.ai/llms.txt
Use this file to discover all available pages before exploring further.
How it works
- Register a rule engine under Rule Engines with Custom as the provider, point the URL at your webhook, and optionally add request headers (for example, a bearer token for your own auth).
- Attach that engine to a gateway rule by selecting it as the rule’s Detection method.
- When a tool message reaches the rule’s detection hook, the gateway POSTs the message (wrapped in a small metadata envelope) to your webhook. Your webhook returns one of four shapes. The gateway acts on that shape before forwarding the message.
The gateway calls your engine over HTTPS only, and URLs that resolve to private or loopback IP ranges are rejected up front — your engine must be reachable on a public network. See Only HTTPS, public endpoints.
The contract, as TypeScript types
Paste this block into your project verbatim. Every field below is exactly what the gateway sends and expects in return. If a coding agent is generating your webhook, this is the source of truth — feed it these types.webhook-types.ts
What the gateway sends
A single JSON object, posted withContent-Type: application/json plus any headers you configured. The HTTP method is whatever you set on the rule engine (defaults to POST). The shape is stable across all custom engines:
body is the tool call and the arguments live under body.params.arguments. On a response-direction rule, body is the tool result, shown above.
Variations you’ll see in body.result
MCP servers don’t all produce the same result shape. A response-direction engine should handle these:
error is present and result is missing, there’s usually nothing to inspect — the right move is to return pass, since blocking an error response just compounds the failure.
The four responses
Return one of these JSON shapes with HTTP200 OK.
pass — let the message through unchanged
comment lands in the rule_engine_comment column in your logs.
block — reject the message
comment short and human-readable — it’s what the alert renderer displays.
modify — rewrite the message
ThemodifiedPayload.body you return is what the gateway forwards in place of the original. It must be a complete, valid JSON-RPC response: jsonrpc: "2.0", the same id as the inbound request (echo metadata.requestId), and either a result or an error field.
"result": "Customer email: [REDACTED]" instead of the content envelope. To surface a tailored error to the client rather than the generic block message, return an error object in place of result:
modifiedPayload.body isn’t a valid JSON-RPC envelope — missing jsonrpc, missing id, or neither result nor error — the gateway treats it as malformed and falls through to the rule’s failure mode. Don’t include extra top-level fields beyond jsonrpc / id / result / error.
error — you can’t decide
What gets rejected as malformed
The gateway treats any of these as anerror outcome and routes through the rule’s failure mode:
- Response is not valid JSON
- HTTP status not in the 200–299 range (after retries are exhausted)
- Body missing the
typefield typenot one ofpass/block/modify/errortype: "modify"without amodifiedPayload.bodythat is a complete JSON-RPC response- Response body larger than 16 MiB
invalid_json, http_error, or connection_error) so you can debug from the dashboard. MCP Manager does not attempt to repair malformed JSON — quietly fixing a response that should have failed is treated as a security risk, so a broken response always falls through to the failure mode.
Operational notes
A few things worth knowing before you write your webhook:- Timeout. The gateway times out at 30 seconds per attempt. Your engine sits inline on tool traffic, so aim for sub-second latency in practice; the generous ceiling exists for engines that make their own downstream calls.
- Retries. Transient failures (timeouts, 5xx) are retried with exponential backoff, up to 3 attempts (1 initial + 2 retries). 4xx responses are deterministic and aren’t retried. Make your webhook idempotent — receiving the same envelope twice must produce the same result. Use
metadata.sessionIdas a dedupe key if you have side effects. - Concurrency. Multiple tool calls can be in flight at once; each fires an independent POST. Don’t assume one call at a time.
- TLS. All calls go over HTTPS. There’s no way to disable it, and self-signed certs aren’t supported — use a public CA.
- No streaming. The webhook is a single request/response — no SSE, no chunked streaming. The envelope arrives fully buffered.
- HTTP status codes. Return
200 OKfor every shape, includingblockanderror— those describe an outcome, not an HTTP failure. Reserve non-2xx for actual webhook failures (your service is down, the request was malformed).
Auth and headers
Anything you add in the Headers section of the rule engine is sent on every request, encrypted at rest until call time. Common patterns: a bearer token (Authorization: Bearer <your-token>), a custom API key (X-Api-Key: <your-key>), or a static signing secret you verify on your end. For defense in depth, you can also allowlist MCP Manager’s static IP. See Authenticating your engine.
Helpers — TypeScript
These helpers handle the body-shape variations above, so your route handler stays a clean four-branch switch.helpers.ts
End-to-end example: Express + TypeScript
A complete webhook covering all four response shapes. Drop into a Node 20+ project withexpress and @types/express installed.
server.ts
Common pitfalls
Returning block or error with a non-200 status
Returning block or error with a non-200 status
block and error are outcomes, not HTTP failures. Return 200 OK and put the outcome in the JSON type. A non-2xx status is treated as http_error and routed through the rule’s failure mode instead.Forgetting to echo metadata.requestId as the id in a modify response
Forgetting to echo metadata.requestId as the id in a modify response
MCP clients correlate requests to responses by
id. A mismatch makes the client wait forever and then time out. Always set modifiedPayload.body.id to the inbound metadata.requestId.Inserting extra fields into modifiedPayload.body
Inserting extra fields into modifiedPayload.body
Only
jsonrpc, id, result, and error are accepted. Anything else gets the response rejected as malformed and falls through to the failure mode.Side effects in the handler
Side effects in the handler
Retries mean the same envelope can arrive more than once. If you log to an immutable audit store, insert a billing row, or fire an alert from inside the handler, key it on
metadata.sessionId so a retry doesn’t double-count.When to use a custom engine vs a built-in provider
Use Custom when you want full control: your own classifier, your own retraining pipeline, your own audit trail. If you’d rather drop in a managed service, MCP Manager has built-in providers — Amazon Bedrock Guardrails and Lakera Guard — that translate to and from a specific vendor’s API for you. You pick those from the same provider dropdown and only configure auth (and, for Bedrock, a couple of identifying fields); MCP Manager handles the request/response translation.Further reading
Custom Rule Engines
Registering, testing, and managing the engine you build here.
Gateway Rules Overview
Detection methods, hooks, failure modes, actions, and rule ordering.
Amazon Bedrock Guardrails
A managed alternative to building your own engine.
Lakera Guard
A security-first managed alternative to a custom engine.
.png?fit=max&auto=format&n=gKqTvJPtsRi2bLNx&q=85&s=8abbce3efb590630de2102c43d32aadf)
.png?fit=max&auto=format&n=Dy9YsIECUbR9JZiT&q=85&s=a1f404cd7f7aeb1727c89d81137ae1ac)