Content Controls
Content controls decide whether an already-permitted call holds up given what it carries. They are PolicyRule documents with role: control. Control rules apply to all traffic that reaches APF, MCP tool calls and plain HTTP requests alike. Their permits never grant a tool call. Their forbids deny any request they match.
A First Example
The demo bundle’s security-content-gate denies MCP tool calls that carry a secret, and replaces the body of plain HTTP requests that carry one:
The rule reads two signals produced by annotators, secret_detected and pii_detected. Annotators do the inspection, Cedar decides, and effects carry out the rewrite.
How a Control Rule Works
Building Blocks
Detection Signals
Read annotations with context.annotations.<name>. Bool annotations are always present. Guard string and integer annotations with has:
Refer to Annotators.
Traffic Type
context.has_tool_name is true for MCP tool calls and false for plain HTTP requests. Use it to treat the two differently in one rule, as the demo does.
Request Target
context.target_host, context.target_method, context.target_path, and context.target_scheme describe the destination. They are present when the request has a target, which is always the case on the OpenShell middleware path.
Tool Arguments
context.args carries MCP tool arguments, with _len and _num fields derived for string arguments. Refer to Capability Grants.
Choosing a Response
Fail-Closed Rewrites
A rewrite that cannot be applied denies the request, because forwarding the original would drop a mandated change.
- A body patch requires a JSON body. A patch on a non-JSON body denies the request.
- A
replaceorremovepatch on a path the body does not contain denies the request. The demo’sredact-pii-bodyeffect replaces/text, so a plain HTTP request that contains PII but has no top-leveltextfield is denied. - An effect that reads an annotation with
sourcedenies the request if that annotation was not produced.
Prefer a whole-body replacement when you cannot predict the body’s shape.
Scope
Content controls see the request only. APF binds the supervisor middleware’s request operation, so it does not inspect responses or WebSocket messages, and it never sees credentials, which OpenShell injects after APF decides. Refer to Enforcement Coverage and Limitations.
Next Steps
- To write the detectors these rules read, refer to Annotators.
- To define rewrites and findings, refer to Effects and Findings.
- To try these controls end to end, refer to Protect Sensitive Data.