Skip to main content

Runtime policy authoring and rollout

Policies decide whether an authenticated agent may call an approved MCP tool. They run after identity, registry approval, schema validation, and request detection, and before any request reaches the upstream server.

The console's Policies screen is the complete operating surface:

  1. install environment rollout packs;
  2. start from a built-in template or create a custom rule;
  3. author selectors and conditions with server-side validation;
  4. test an unsaved draft with the gateway's real engine;
  5. save disabled, review the explanation, then enable;
  6. edit, duplicate, disable, or delete rules with audit evidence.

Decision semantics

Every enabled policy whose selector matches contributes a decision. Combination is Cedar-style forbid-overrides:

deny > step_up > require_approval > sanitize > redact > allow

Priority controls evaluation order and the explanation trail. It does not let a high-priority allow override a matching deny. If no rule matches, the gateway's secure default is deny.

EffectRuntime behavior
allowForward the validated call.
denyBlock the call.
require_approvalHold the exact argument-bound call for human approval.
step_upRequire stronger authentication before retry.
redactForward while redacting configured argument paths.
sanitizeForward and sanitize sensitive response content.

Detection and structural safety floors remain independent: an unapproved or quarantined tool, invalid schema, out-of-scope agent credential, or critical detection can still block a call that policy would otherwise allow.

Selector reference

The match object may contain any combination of these fields. Dimensions are ANDed; values within one list are ORed.

FieldValuesMeaning
serverIdsserver IDs or *Specific registered servers.
environmentslocal, development, staging, productionServer deployment environment.
toolIdstool IDs or *Specific registered tools.
toolNameone exact nameA case-sensitive exact tool-name match.
toolNameGlobsget_*, deploy_?Case-insensitive tool-name globs.
capabilitiesread, write, destructive, admin, unknownClassified capability.
riskTierslow, medium, high, criticalRegistry risk tier.
dataClassespublic, internal, confidential, pii, secrets, financial, source_code, production_dataData handled by the tool.
tagstag names or *Registry tags such as github, filesystem, or sql.

An empty match object is a valid global rule and matches every registered tool. The console highlights global enabled rules because their blast radius is large.

Condition reference

Conditions refine a matched rule. Failed authorization/allowlist conditions escalate the result to deny; insufficient assurance escalates to step_up.

FieldMeaning
requireScopesCaller must hold every listed scope.
requireAnyRoleCaller must hold at least one listed role.
minAuthLevelMinimum aal1, aal2, or aal3.
argumentAllowlistArgument dot-path to allowed glob values.
redactPathsArgument paths to remove from logs/forwarded content.
maxRiskScoreDetection score from 0–100; higher requests are denied.

Example:

{
"name": "Production deploys need approval",
"description": "Platform-owned deployment control",
"priority": 90,
"enabled": false,
"effect": "require_approval",
"match": {
"environments": ["production"],
"toolNameGlobs": ["deploy_*"],
"capabilities": ["write", "admin"]
},
"condition": {
"requireAnyRole": ["release-manager", "platform-admin"],
"minAuthLevel": "aal2",
"maxRiskScore": 60
}
}

Unknown fields, invalid enums, empty allowlist glob sets, out-of-range risk scores, and malformed names/priorities are rejected with HTTP 422; typos do not silently become ineffective policy.

Templates and rollout packs

Six built-in templates cover read baselines, destructive blocks, high-risk approval, secret sanitization, filesystem path allowlists, and production-data approval.

Packs materialize those templates with an environment selector:

PackIntended stage
pack-dev-observeDevelopment baseline while reviewing would-block events.
pack-stagingAdds approval for high/critical tools.
pack-productionAdds production-data assurance and filesystem controls.

Pack installation is idempotent per template and environment. Reinstalling the same pack does not create duplicates.

Draft simulation

While the editor is open, Policy Test sends the unsaved rule as a simulation override. You can combine it with active rules to see real forbid-overrides, or isolate it to understand the draft alone. Overrides are simulation-only and cannot change enforcement.

POST /v1/policies/simulate
{
"serverId": "srv_github",
"toolName": "delete_repo",
"arguments": { "repo": "acme/payments" },
"roles": ["developer"],
"authLevel": "aal1",
"draftPolicy": {
"name": "Preview destructive block",
"priority": 100,
"enabled": true,
"effect": "deny",
"match": { "capabilities": ["destructive"] }
},
"includeActivePolicies": true
}

The API passes the override to the gateway's internal simulator, which uses the same TypeScript engine and request detector as live traffic.

Propagation and audit

GATEWAY_CONTROL_PLANE=api is mandatory outside automated tests. After a successful mutation, the API requests an immediate gateway refresh; the gateway's normal refresh loop is the fallback if it is temporarily unavailable. The gateway fails readiness when it cannot obtain a current API snapshot.

Create, update, toggle, pack install, and delete operations require an admin, security, policy-admin, or tenant-admin identity. Every successful mutation emits a hash-chained policy_changed evidence event with actor and policy context.

  1. Install pack-dev-observe and keep the gateway in observe mode.
  2. Review Policy Test explanations, Sessions, Detections, and Approvals.
  3. Author custom rules disabled; simulate representative calls and identities.
  4. Enable the rule in development, then install the staging pack.
  5. Promote to production only after expected allow/deny/approval evidence is stable.
  6. Disable first when responding to a policy incident; delete only after review.

See Govern, API reference, and Detections for adjacent runtime controls.