Capability Grants
A capability grant says which tool calls an agent may make and under which argument constraints. Grants are PolicyRule documents with role: capability. Every MCP tool call that reaches APF must be permitted by at least one grant, so a tool without a grant is denied by default.
A First Example
This rule permits only the github_repo_read tool. There is no permit for a write tool, so an MCP call to one is denied:
Naming the Action
A grant matches the Cedar action APF builds for the request.
The resource is APF::Tool::"<tool>", where the tool is the MCP tool name on the middleware path and resource.class on the Evaluate path. Write grants for the path your callers use.
Constraining Arguments
Tool arguments are available as context.args.<name>. For each string argument, APF also adds two derived fields, because Cedar has no string-length or numeric-coercion functions:
context.args.<name>_len: the length of the string in characters.context.args.<name>_num: the string’s integer value, present only when it parses as an integer.
Guard any attribute that may be absent with has. Reading a missing attribute is a Cedar evaluation error. A permit that errors grants nothing. A forbid that errors denies the request with the reason <rule>/<@id>: evaluation error: <detail>, so an unguarded forbid fails closed rather than silently stopping to protect you; guard it with has when it should not apply to requests that lack the attribute.
Keeping Tunable Values in Data
Put operator-tunable values, such as an approved channel or a size limit, in spec.data. Each rule sees only its own data as context.data, so a tool owner can change a value without editing Cedar:
spec.data must be a mapping. It does not influence the decision except through the conditions that read it.
Grants That Depend on Provider Facts
A grant can read facts that a policy information provider supplied in the Enrichment stage, such as a change request’s approval state, as context.<domain>.<claim>. Guard the read with has:
What happens when the provider cannot answer depends on its registration. With on_failure: degrade, context.change holds only its _meta record, with degraded set to true, so the guard keeps the grant off and the call is denied with no grant for <action>. With on_failure: fail_closed, the request is denied before any rule runs, with the reason pip_<status>:<provider>. The provider looks the change up by the repository the tool acts on, so the agent cannot choose which record gates its request. Refer to Policy Information Providers.
Type-Checking with a Schema
Add a Cedar schema in spec.schema to catch misspelled fields and type errors when the evaluator is built, before any request runs. When a schema is present, every policy in the rule is validated against it, so the schema must declare each context attribute the policies read.
Do not put the schema at the top of definition. APF rejects a definition that starts with a schema declaration and asks you to move it into spec.schema.
How Grants Combine
- Grants are evaluated in manifest order with the other rules. A grant whose statements do not match is skipped.
- One permit from any capability rule satisfies the grant requirement for a tool call.
- A
forbidin any rule, including a capability rule, stops evaluation and denies the request. - Grants are written against tool actions, so they normally match only tool calls. A request that is not a tool call needs no grant.
Deny Reasons
When a tool call gets no grant, APF returns one of two reasons:
An explicit forbid returns <rule>/<@id> instead, or the @id itself when it contains /, or <rule>/policyN when the statement has no @id. Use @id("<rule>/<label>") on every statement so deny reasons read clearly in audit records.
Authoring Checklist
- Use
role: capabilityfor tool grants androle: controlfor content policy. Any value other than exactlycontrol, including a misspelling orControl, is treated as a grant. - Name grant rules after the tools they cover. A rule name that contains the full tool name gets the more specific deny reason.
- Put tunable values in
spec.data. - Add
spec.schemafor any rule that readscontext.args. - Guard optional attributes and provider facts with
has. - Give every statement an
@id.
Next Steps
- To inspect and rewrite content on allowed calls, refer to Content Controls.
- To exercise grants without a live agent, refer to Validate and Test Policies.