Octelium documentation · Latest
Plugins
MCP plugins apply controls and mutations on a per-request basis. Every plugin requires a unique name and a Condition:
isDisabled turns a plugin off without removing it. condition is evaluated against the request context even for a response plugin. The response itself is not available to a condition.
The MCP-specific guardrail plugin always runs in the POST_AUTH phase. Setting phase: PRE_AUTH for it is rejected. Generic HTTP plugins use POST_AUTH by default and can explicitly use PRE_AUTH.
Guardrail
An MCP guardrail inspects the content exchanged with an MCP server. It addresses two common boundaries:
Tool arguments are downstream-controlled content sent to a server and can leak credentials or personal information.
Tool results, resources, prompts and tool definitions are server-controlled content sent to an agent and can carry indirect prompt injection or tool poisoning.
A guardrail is a content control. Policies continue to govern the identity, method and target of a request, while protocol and limits govern its shape.
Request Guardrail
The following plugin denies detected credentials and strips email addresses from tool arguments:
REQUEST is the default leg. Its default scope is TOOL_ARGUMENTS.
Response Guardrail
The following plugin withholds server content that contains a prompt-injection phrase:
A response streamed as SSE is withheld in full until it ends and passes inspection. This guarantees that matched content cannot reach the client, but delays the first event by the duration of the upstream stream.
Both Legs
BOTH inspects both request and response scopes with the same deny patterns:
A scope that does not belong to the current leg is a no-op. This lets one BOTH guardrail carry scopes for each leg.
Scopes
The available scopes are:
TOOL_ARGUMENTSfor the arguments in atools/callrequest.TOOL_RESULTSfor content blocks and structured content in its result.RESOURCE_CONTENTSfor aresources/readresult.PROMPT_MESSAGESfor messages in aprompts/getresult.TOOL_DEFINITIONSfor names, descriptions and JSON Schemas in atools/listresult.ALLfor every scope.
TOOL_DEFINITIONS is inspect-only because it is structured content. Use a dedicated MCP server or a generic mutation plugin when definitions must be rewritten.
Pattern Types
Patterns are shared with the LLM mode. An RE2 expression matches custom text:
Built-in deterministic personal-information detectors are also available:
The secrets detector recognizes API keys, tokens, private keys and connection strings from hundreds of providers:
excludeRules disables known false-positive rules by case-insensitive identifier. Unknown identifiers are ignored.
Actions
The request leg supports:
DENY, which is the default, rejects the JSON-RPC request.REDACTreplaces a matched span with a detector-specific placeholder.STRIPremoves the matched span.REPLACEcomputes replacement content.
A replacement can be static:
Or it can use CEL or OPA:
The response leg and TOOL_DEFINITIONS only support DENY. A BOTH guardrail is also limited to deny actions because it includes the response leg. An evaluation or inspection error rejects the exchange rather than bypassing the control.
Lua
Lua can inspect and intentionally rewrite the JSON-RPC request or response (read more here):
After a request-body mutation, Octelium parses and validates it again so later processing sees the updated MCP context.
If Lua changes a version, method or target that was also supplied in a reserved MCP header, it must update the header as well. The same applies to Mcp-Session-Id. An upstream server rejects inconsistent headers and bodies.
ExtProc
An Envoy-compatible external processing server can receive selected headers and bodies (read more here):
The external processor can alternatively run as a managed container. It has the same responsibility as Lua for keeping reserved MCP headers consistent with a rewritten message.
Request Rate Limit
The HTTP rate-limit plugin bounds request frequency with a global sliding window backed by the Cluster Redis store:
The default key is per Session. It can be explicitly set to perSession, perUser or a CEL result:
JSON Schema
The jsonSchema plugin validates the complete JSON-RPC request body:
Direct Response
direct answers without invoking the upstream. Its body must be a valid JSON-RPC response or error for the MCP client:
The response identifier is static, so use Lua or ExtProc instead when it must echo the request identifier.
Path
The path plugin conditionally removes and adds upstream prefixes:
Use the path in upstream.url when every request goes to the same server endpoint. The configuration-level mcp.path applies to every request served by that configuration.
Plugin Boundary
Generic HTTP plugins run before MCP guardrails on the request and after them on the response. Lua, ExtProc or Direct can therefore create response content that no guardrail has inspected. A generic plugin used to carry MCP content must inspect that content itself where necessary.
A generic plugin whose condition cannot be evaluated is skipped, following HTTP behavior. An MCP guardrail whose condition cannot be evaluated rejects the request to prevent a silent security-control bypass.
The HTTP cache plugin is not supported because it understands neither MCP authorization scope nor MCP cache invalidation semantics.