Skip to main content
Activation required. AI access management must be enabled for your tenant before you can use it. To get started, contact the C1 support team for a walkthrough.
Tool call hooks are interception points that run on every governed MCP tool call. They can observe a call, modify its inputs or outputs, or deny it outright. Use them to redact sensitive data, cap risky parameters, or enforce conditional access rules that see beyond the entitlement grant model.

How hooks work

Each hook fires on one of three events: Hooks run in priority order (lower priority numbers run first). Each hook is independently enabled or disabled and can be scoped to specific tools with a CEL filter expression. Multiple hooks can stack on the same call — input or output modifications from earlier hooks are passed to later ones, and any hook can short-circuit the chain by denying. Hooks are fail-closed. If a hook errors, times out, or its filter expression fails to evaluate, the call is denied. Custom function hooks have a 60-second invocation timeout. Every hook execution is recorded in the audit log with one of these statuses: ALLOWED, MUTATED, DENIED, ERROR, TIMEOUT, or FILTER_ERROR.

Configure a hook

Create hooks from the Hooks section under AI > Guardrails.
1
Go to AI > Guardrails, open the General tab, and find the Hooks section.
2
Click New hook.
3
Fill out the form:
4
If you selected Built-in pattern, choose the pattern and configure its options. If you selected Custom function, pick the function from the dropdown.
5
Click Save.

Filter variables by event

A filter expression only sees the variables available for its event. Referencing one that isn’t set for that event makes the expression fail to evaluate, which denies the call — see the fail-closed note above.
ctx.untrusted_class (a hook filter, comparing strings) and ctx.untrusted_content (a guardrail rule variable, comparing ordered levels) carry the same underlying risk score under two different names and two different types. In a pre-output hook filter write ctx.untrusted_class == "HIGH"; in a guardrail rule write ctx.untrusted_content == HIGH. Using the rule form in a hook filter fails to evaluate, and the call is denied.

Event and pattern must be compatible

Each built-in pattern is only valid for certain events, and C1 rejects a mismatch when you save the hook. The Event column in Built-in patterns is the authoritative list.
Custom function hooks cannot use the Pre-output event. Saving one is rejected. Only the Block output and Link filter built-in patterns run on that stage.

Managed by guardrails

Each hook has a Managed by guardrails toggle:
  • Off (default) — the hook always evaluates on every matching call.
  • On — the hook only evaluates when a guardrail rule explicitly selects it.
See Agent guardrails for how guardrail rules select hooks.

Built-in patterns

C1 ships eleven pre-built hook patterns. Each one is a self-contained handler with its own configuration; no function code is required.

Pattern configuration and defaults

Where a pattern takes a list, a value you configure replaces the default list — it does not extend it. If you add one field name to PII field redaction, the built-in field names stop applying unless you re-include them.
A Block output hook with no surfaces selected never fires. An empty surface list means no surface, not all of them — deliberately, so that forgetting to choose can’t silently apply the hook everywhere. The failure mode is a hook that looks configured and enabled but withholds nothing. Select Slack, Web, or both.

Custom function hooks

When the built-in patterns don’t fit, write a function and attach it to a hook. C1 invokes the function with a JSON payload describing the call and uses the return value to decide whether to allow, modify, or deny. See the Functions overview and Create a function for how to author and deploy a function.

Pre-tool-use payload

The function receives:
tool_source is builtin, connector, or claw. classification is the tool’s configured action class (READ, WRITE, DESTRUCTIVE, SENSITIVE, or DANGEROUS). caller identifies who made the call; token_id, mcp_client_id, and mcp_client_type are omitted when empty.
caller is for logging and call-shape decisions only — it is never an authorization input, because the grant decision is made before the hook runs. Identity-based scope belongs in access profiles, not hooks.

Post-tool-use payload

The function receives the same fields plus the call result:

Return value

In both events the function returns an object with any subset of these fields:
  • Set deny: true to block the call. The reason is recorded in the audit log and surfaced to the AI client as a denial.
  • Omit input (pre) or output (post) when you don’t need to modify the payload.
  • Returning an empty object {} is equivalent to allowing the call unchanged.
If the function throws, exceeds the 60-second timeout, or returns invalid JSON, the call is denied and the failure is recorded as ERROR or TIMEOUT in the audit log.