Skip to main content
Barndoor uses a policy-based access control system to define what MCP tools and resources each agent can access. This guide covers how to manage policies programmatically via the API.

Policy Structure

Policy Hierarchy

Policies follow a hierarchical structure:
Policy TypeFormatDescription
Server-level (base)resource.{server_id}.vdefaultApplies to ALL agents
Agent-scopedresource.{server_id}.vdefault/{agent_id}Applies to specific agent only
Agent-scoped policies override their parent server-level policy. If an agent has a scoped policy with EFFECT_ALLOW, it will be allowed even if the base policy is EFFECT_DENY.

Action Format

Actions follow the MCP convention:
tools/call:{tool_name}    # For tool invocations
resources/read:{resource} # For resource reads  
*                         # Wildcard - all actions
Examples:
  • tools/call:chat_postMessage - Slack’s post message tool
  • tools/call:get_accounts - Salesforce accounts tool
  • * - All tools and resources

Common Operations

Turn Main Toggle ON (Allow All)

To enable all tools for an agent on a server:
curl -X POST "$BASE_URL/api/policy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "policies": [{
      "apiVersion": "api.cerbos.dev/v1",
      "resourcePolicy": {
        "resource": "SERVER_ID",
        "version": "default",
        "scope": "AGENT_ID",
        "rules": [{
          "name": "allow_all",
          "effect": "EFFECT_ALLOW",
          "actions": ["*"],
          "roles": ["*"]
        }]
      }
    }]
  }'

Turn Main Toggle OFF (Deny All)

To disable all tools:
curl -X POST "$BASE_URL/api/policy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "policies": [{
      "apiVersion": "api.cerbos.dev/v1",
      "resourcePolicy": {
        "resource": "SERVER_ID",
        "version": "default", 
        "scope": "AGENT_ID",
        "rules": [{
          "name": "allow_all",
          "effect": "EFFECT_DENY",
          "actions": ["*"],
          "roles": ["*"]
        }]
      }
    }]
  }'

Deny a Specific Tool

To allow everything except a specific tool:
curl -X POST "$BASE_URL/api/policy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "policies": [{
      "apiVersion": "api.cerbos.dev/v1",
      "resourcePolicy": {
        "resource": "SERVER_ID",
        "version": "default",
        "scope": "AGENT_ID",
        "rules": [
          {
            "name": "allow_all",
            "effect": "EFFECT_ALLOW",
            "actions": ["*"],
            "roles": ["*"]
          },
          {
            "name": "chat_postMessage",
            "effect": "EFFECT_DENY",
            "actions": ["tools/call:chat_postMessage"],
            "roles": ["*"]
          }
        ]
      }
    }]
  }'

Add a Restriction with Condition

Restrictions let you apply fine-grained conditions:
curl -X POST "$BASE_URL/api/policy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "policies": [{
      "apiVersion": "api.cerbos.dev/v1",
      "resourcePolicy": {
        "resource": "SERVER_ID",
        "version": "default",
        "scope": "AGENT_ID",
        "rules": [
          {
            "name": "allow_all",
            "effect": "EFFECT_ALLOW",
            "actions": ["*"],
            "roles": ["*"]
          },
          {
            "name": "block_general_channel",
            "effect": "EFFECT_DENY",
            "actions": ["tools/call:chat_postMessage"],
            "roles": ["*"],
            "condition": {
              "match": {
                "all": {
                  "of": [
                    { "expr": "request.resource.attr.channel == \"general\"" }
                  ]
                }
              }
            }
          }
        ]
      }
    }]
  }'

Toggle a Restriction ON/OFF

To toggle a restriction, change its effect between EFFECT_DENY (active) and EFFECT_ALLOW (inactive): Turn restriction OFF (keep the rule but make it allow):
{
  "name": "block_general_channel",
  "effect": "EFFECT_ALLOW",  // Changed from EFFECT_DENY
  "actions": ["tools/call:chat_postMessage"],
  "roles": ["*"],
  "condition": { ... }
}
Turn restriction ON (set effect back to deny):
{
  "name": "block_general_channel", 
  "effect": "EFFECT_DENY",  // Active - blocking
  "actions": ["tools/call:chat_postMessage"],
  "roles": ["*"],
  "condition": { ... }
}

Reading Policies

Get Policy by ID

# URL-encode the policy ID (especially the / character)
POLICY_ID="resource.SERVER_ID.vdefault/AGENT_ID"
ENCODED_ID=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$POLICY_ID', safe=''))")

curl -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/policy?id=$ENCODED_ID"

List Policies for an Agent

curl -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/policies?agent_id=AGENT_ID"

List Policies for a Server

curl -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/policies?server_id=SERVER_ID"

Policy Enable/Disable (API-level)

The enable/disable endpoints affect the entire policy at the engine level. This is different from toggling individual rules via EFFECT_ALLOW/EFFECT_DENY.

Disable a Policy

POLICY_ID="resource.SERVER_ID.vdefault/AGENT_ID"
ENCODED_ID=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$POLICY_ID', safe=''))")

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/policy/disable?id=$ENCODED_ID"

Enable a Policy

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/policy/enable?id=$ENCODED_ID"
You cannot disable a server-level (base) policy if agent-scoped policies depend on it. This would break the policy inheritance chain. Disable child policies first.

Best Practices

  1. Use scoped policies for agent-specific rules - Server-level policies affect all agents
  2. Name rules descriptively - Use allow_all, tool names, or descriptive restriction names
  3. Toggle restrictions via effect - Change EFFECT_DENYEFFECT_ALLOW rather than deleting rules
  4. Always include allow_all as first rule - Other rules modify this baseline
  5. URL-encode policy IDs - The / in scoped policy IDs must be encoded as %2F