MAQPNADocs

ToolPolicy

ToolPolicy (maqpna.com/v1alpha1): every field, type, default and validation rule, generated from the CRD schema.

ToolPolicy is enforced by the MAQPNA gateway on every MCP tool call.

At a glance#

Property Value
API version maqpna.com/v1alpha1
Kind ToolPolicy
Scope Namespaced
Plural toolpolicies
Short names tp
Categories maqpna
Status subresource yes
kubectl get toolpolicies -A
kubectl get tp <name> -o yaml
kubectl explain toolpolicies.spec

Columns in kubectl get#

Column Type From
Default string .spec.defaultAction
Enforcement string .spec.enforcement
Ready string .status.conditions[?(@.type=="Ready")].status
Age date .metadata.creationTimestamp

Example#

From config/samples/toolpolicy-coder.yaml:

apiVersion: maqpna.com/v1alpha1
kind: ToolPolicy
metadata:
  name: coder-policy
  namespace: team-a
spec:
  agents: ["coder", "coder-*"]
  defaultAction: deny
  rules:
  - name: github-read
    servers: [github]
    tools: ["get_*", "list_*", "search_*"]
    action: allow
    maxCallsPerMinute: 120
  - name: github-write-needs-approval
    servers: [github]
    tools: ["create_pull_request", "merge_pull_request"]
    action: require_approval
    reason: Writes to source control require human approval.
  - name: k8s-read
    servers: [kubernetes]
    tools: ["get", "list", "describe", "logs"]
    action: allow
    maxCallsPerMinute: 60
  - name: k8s-no-prod-mutations
    servers: [kubernetes]
    tools: ["apply", "delete", "scale", "patch"]
    argMatch:
      namespace: "prod-*"
    action: deny
    reason: Mutations in production namespaces are forbidden for agents.

From config/samples/toolpolicy-sre.yaml:

# ToolPolicy of the sre agent (agent-sre.yaml) for the gateway's built-in
# maqpna-k8s server: diagnose freely (rate-limited), change nothing without
# a human, never touch kube-system or production namespaces. The gateway
# additionally holds every applied write for approval
# (gateway.k8sOps.writes.approval: required) and the impersonated
# ServiceAccount's RBAC is read-only unless writes are opted in.
apiVersion: maqpna.com/v1alpha1
kind: ToolPolicy
metadata:
  name: sre-policy
  namespace: sre
spec:
  agents: ["sre"]
  defaultAction: deny
  rules:
  - name: no-system-or-prod-writes
    servers: [maqpna-k8s]
    tools: ["scale_workload", "rollout_restart", "delete_pod"]
    argMatch:
      namespace: "kube-*"
    action: deny
    reason: Agents never change system namespaces.
  - name: no-prod-writes
    servers: [maqpna-k8s]
    tools: ["scale_workload", "rollout_restart", "delete_pod"]
    argMatch:
      namespace: "prod-*"
    action: deny
    reason: Production changes go through the change process, not an agent.
  - name: diagnose
    servers: [maqpna-k8s]
    tools: ["list_resources", "get_resource", "describe_resource", "list_events", "get_resource_usage", "explain_failure", "get_pod_logs"]
    action: allow
    maxCallsPerMinute: 120
  - name: remediate-with-approval
    servers: [maqpna-k8s]
    tools: ["scale_workload", "rollout_restart", "delete_pod", "cordon_node", "uncordon_node"]
    action: require_approval
    maxCallsPerMinute: 10
    reason: Every cluster change needs an on-call engineer's approval.

Spec fields#

ToolPolicySpec governs which MCP tool calls agents may make.

Field Type Required Description
agents []string agents this policy applies to (globs over agent names).
cedar string cedar is optional Cedar policy text (F-24) evaluated together with rules; the most restrictive decision wins and defaultAction applies only when neither a rule nor a Cedar policy is determining. Schema: config/cedar/maqpna.cedarschema. Gateways built without the Cedar adapter (-tags cedar) deny every call this policy applies to. Max length: 65536.
defaultAction string DefaultAction is the fallback verdict when no rule matches. One of: allow, deny. Default: "deny".
dryRunFallback string dryRunFallback: what a dryRun policy contributes: allow (default) or defaultAction. One of: allow, defaultAction.
enforcement string enforcement: enforce (default) or dryRun. A dryRun policy is evaluated and its would-be decisions are audited (ext.dryRun=true), but it only contributes dryRunFallback to the enforced decision. One of: enforce, dryRun.
rules []object Max items: 256.
rules[].action string yes PolicyAction is the gateway's verdict for a tool call. One of: allow, deny, require_approval.
rules[].approval object approval sets approval requirements (require_approval only).
rules[].approval.approverGroups []string approverGroups whose members may approve (globs). Max items: 16.
rules[].approval.minApprovers integer (int32) minApprovers distinct approvers required (default 1). Minimum: 1. Maximum: 10.
rules[].approval.userConfirmation string userConfirmation "ciba" requires the delegating end user's own confirmation on their device (OpenID CIBA to the customer IdP, F-30) instead of approver votes; approvers may still deny. When CIBA is unavailable the gateway falls back per its ciba.fallback setting. One of: ciba.
rules[].argMatch map[string]string argMatch maps argument JSON paths to glob/regex patterns.
rules[].maxCallsPerMinute integer (int32) maxCallsPerMinute caps the calls matching this rule per session over a sliding 60 s window; further calls are denied with reason rate_limited (0 = unlimited). Rate unit: calls (MCP tools/call, A2A messages; docs/api-conventions.md, "Rates"). Minimum: 0.
rules[].name string yes Min length: 1.
rules[].principals object principals restricts the rule to human principals (policy v2). Rule: at least one of users, groups, notUsers, notGroups is required.
rules[].principals.groups []string Max items: 64.
rules[].principals.notGroups []string Max items: 64.
rules[].principals.notUsers []string Max items: 64.
rules[].principals.users []string Max items: 64.
rules[].reason string
rules[].schedule object schedule restricts when the rule matches. Rule: windows or exceptWindows is required.
rules[].schedule.exceptWindows []string Max items: 32.
rules[].schedule.timezone string timezone is an IANA name (default UTC). Max length: 64.
rules[].schedule.windows []string Max items: 32.
rules[].scopes []string scopes the agent token must all hold (globs in granted scopes apply). Max items: 32.
rules[].servers []string servers (MCP server / tool names, globs allowed).
rules[].sessionTaints object sessionTaints matches the session's taint labels (F-13). Rule: any or all is required.
rules[].sessionTaints.all []string Max items: 16.
rules[].sessionTaints.any []string Max items: 16.
rules[].sinks []string sinks matches tools labelled as exfiltration sinks (toolLabels.sinks); globs allowed. Max items: 16.
rules[].substrate object substrate matches where the session runs, as the identity broker verified it before minting (token claim maqpna_substrate); a session no check ran for has isolation and attestation "none". Rule: substrate needs at least one of isolation, notIsolation, attestation, notAttestation, checks.
rules[].substrate.attestation []string attestation: the rule applies only to these levels. Max items: 3.
rules[].substrate.checks []string checks: the rule applies only to sessions verified by these identity checks (e.g. kosa8). Max items: 8.
rules[].substrate.isolation []string isolation: the rule applies only to these classes. Max items: 7.
rules[].substrate.notAttestation []string notAttestation: the rule does not apply to these levels. Max items: 3.
rules[].substrate.notIsolation []string notIsolation: the rule does not apply to these classes. Max items: 7.
rules[].tools []string tools (MCP tool names, globs allowed).
rules[].when []object when lists typed argument conditions; all must hold. Max items: 32.
rules[].when[].arg string yes arg is a top-level argument name or a dotted path (a.b.c). Min length: 1. Max length: 256.
rules[].when[].op string yes ConditionOperator is a typed argument operator. One of: eq, neq, glob, regex, in, nin, lt, lte, gt, gte, exists, absent, cidr, len_gt, len_lt.
rules[].when[].value string Max length: 1024.
rules[].when[].values []string Min items: 1. Max items: 256.
toolLabels []object toolLabels label tools as taint sources, exfiltration sinks or taint cleaners (F-13). Max items: 64.
toolLabels[].clearTaints []string Max items: 16.
toolLabels[].servers []string Max items: 64.
toolLabels[].sinks []string Max items: 16.
toolLabels[].taints []string Max items: 16.
toolLabels[].tools []string Max items: 256.
toolPins []object toolPins pin MCP tool definitions per server (F-04). Max items: 64.
toolPins[].allowUnpinned boolean allowUnpinned lets tools without a pin through in enforce mode.
toolPins[].mode string mode: off | learn (default: record and audit, never block) | enforce. One of: off, learn, enforce.
toolPins[].onChange string onChange in enforce mode: hide (default: drop from tools/list and deny calls) | approve (require approval) | alert (allow and audit). One of: hide, approve, alert.
toolPins[].pins map[string]string
toolPins[].server string yes server is the MCP server name (as in /mcp/{server}). Min length: 1. Max length: 63.
  • Rule on spec: dryRunFallback requires enforcement dryRun

Status fields#

ToolPolicyStatus is the observed state of a ToolPolicy.

The operator writes status; do not set it yourself.

Field Type Required Description
conditions []object
conditions[].lastTransitionTime string (date-time) yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
conditions[].message string yes message is a human readable message indicating details about the transition. This may be an empty string. Max length: 32768.
conditions[].observedGeneration integer (int64) observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. Minimum: 0.
conditions[].reason string yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. Min length: 1. Max length: 1024. Pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$.
conditions[].status string yes status of the condition, one of True, False, Unknown. One of: True, False, Unknown.
conditions[].type string yes type of condition in CamelCase or in foo.example.com/CamelCase. Max length: 316. Pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$.
observedGeneration integer (int64)