Skip to main content
Glama
policy-rules-specification.md10.5 kB
# Policy Rules Specification **Version:** 1.0 **Status:** Desired End State **Purpose:** Define expected policy evaluation logic for agent-mcp-gateway ## Overview Gateway policies control which agents can access which MCP servers and tools. Rules follow a hierarchical model: server access is granted first, then tool access is evaluated. The key principle: **granting server access implicitly grants all tools unless explicitly restricted**. ## Configuration Structure ```json { "agents": { "agent-name": { "allow": { "servers": ["server1", "server2", "*"], "tools": { "server1": ["tool1", "tool2", "*"], "server2": ["pattern_*", "exact_name"] } }, "deny": { "servers": ["excluded-server"], "tools": { "server1": ["dangerous_tool", "drop_*"] } } } }, "defaults": { "deny_on_missing_agent": false } } ``` ## Hierarchy of Access Control ### Level 1: Server Access **Rule:** Agent must have server access before any tool access is evaluated. **Evaluation:** 1. If server in `deny.servers` → **deny** (explicit or wildcard) 2. If server in `allow.servers` → **allow** (explicit or wildcard) 3. Otherwise → **deny** **Implicit Behavior:** - `"servers": ["*"]` grants access to ALL configured servers - `"servers": ["playwright"]` grants access to playwright server only ### Level 2: Tool Access (Conditional on Server Access) **Rule:** If agent has server access, evaluate tool permissions. **Key Principle - Implicit Tool Grant:** - If server in `allow.servers` AND no `allow.tools` entry for that server → **implicitly grant all tools** (equivalent to `["*"]`) - If `allow.tools` specifies rules for the server → **only grant specified tools** (narrow from implicit all) - If `deny.tools` specifies rules for the server → **remove specified tools** (filter from granted set) **CRITICAL: Implicit grant is triggered ONLY by absence of `allow.tools` entry, NOT by absence of both allow and deny rules.** Example: ```json { "allow": {"servers": ["playwright"]}, // No allow.tools entry "deny": {"tools": {"playwright": ["browser_type"]}} // Deny rules present } ``` Result: Implicit grant applies. All 21 playwright tools granted, then "browser_type" is filtered out by deny rule → 20 tools accessible. ## Evaluation Precedence Order Tool access follows strict precedence with **short-circuit evaluation** (DO NOT CHANGE): **Critical Principle:** Deny rules ALWAYS override allow rules. All denies checked before any allows. 1. **Explicit deny rules** - specific tool names in `deny.tools.{server}` → if match, DENY and STOP 2. **Wildcard deny rules** - patterns like `drop_*` in `deny.tools.{server}` → if match, DENY and STOP 3. **Explicit allow rules** - specific tool names in `allow.tools.{server}` → if match, ALLOW and STOP 4. **Wildcard allow rules** - patterns like `get_*` or `*` in `allow.tools.{server}` → if match, ALLOW and STOP 5. **Implicit grant** - if server allowed but no `allow.tools.{server}` entry → ALLOW and STOP 6. **Default deny** - if no rules matched → DENY Each rule is checked in order. As soon as a match is found, that decision is returned and evaluation stops. ## Wildcard Support ### Server-Level Wildcards **Supported in both `allow.servers` and `deny.servers`:** - `"*"` - matches all servers - `"browser_*"` - matches servers starting with "browser_" - Patterns use glob-style matching (fnmatch) ### Tool-Level Wildcards **Supported in both `allow.tools.{server}` and `deny.tools.{server}`:** - `"*"` - matches all tools - `"get_*"` - matches tools starting with "get_" - `"*_query"` - matches tools ending with "_query" - `"drop_*"` - matches tools starting with "drop_" - Patterns use glob-style matching (fnmatch) ## Behavioral Examples ### Example 1: Admin with Full Access ```json { "admin": { "allow": { "servers": ["*"] } } } ``` **Behavior:** - Server access: ALL servers ✓ - Tool access: ALL tools from ALL servers ✓ (implicit grant) - No need to specify tools for each server ### Example 2: Admin with One Server Restricted ```json { "admin": { "allow": { "servers": ["*"], "tools": { "brave-search": ["brave_web_search"] } } } } ``` **Behavior:** - Server access: ALL servers ✓ - Tool access for `brave-search`: ONLY `brave_web_search` ✓ (explicit restriction) - Tool access for other servers: ALL tools ✓ (implicit grant) ### Example 3: Admin with Mixed Access Patterns ```json { "admin": { "allow": { "servers": ["*"], "tools": { "brave-search": ["brave_web_search"] } }, "deny": { "servers": ["notion"], "tools": { "playwright": ["browser_type"] } } } } ``` **Evaluation walkthrough:** **notion server:** - Server level: "notion" in `deny.servers` → **SERVER DENIED** ✗ - Tools never evaluated (server blocked) **playwright server (21 tools):** - Server level: "*" in `allow.servers`, "notion" ≠ "playwright" → **SERVER ALLOWED** ✓ - Tool "browser_type": Step 1 explicit deny → **DENIED** ✗ - Tool "browser_navigate": Steps 1-2 no deny match → Step 5 implicit grant (`allow.tools` has no playwright entry) → **ALLOWED** ✓ - Other 19 tools: Same as browser_navigate → **ALLOWED** ✓ - **Result: 20/21 tools accessible** **brave-search server:** - Server level: "*" in `allow.servers` → **SERVER ALLOWED** ✓ - Tool "brave_web_search": Step 3 explicit allow → **ALLOWED** ✓ - Tool "brave_local_search": No matches → Step 5 implicit grant fails (allow_tools exists) → Step 6 default deny → **DENIED** ✗ - **Result: 1 tool accessible (only brave_web_search)** **github server (no tool rules):** - Server level: "*" in `allow.servers` → **SERVER ALLOWED** ✓ - Any tool: Steps 1-4 no matches → Step 5 implicit grant (no `allow.tools` entry) → **ALLOWED** ✓ - **Result: ALL tools accessible** **Summary:** - notion: 0 servers, 0 tools (server blocked) - playwright: 1 server, 20/21 tools (implicit grant with 1 tool denied) - brave-search: 1 server, 1/N tools (explicit restriction) - github (and others): 1 server each, all tools (implicit grant) ### Example 4: Dangerous Tools Denied with Wildcards ```json { "admin": { "allow": { "servers": ["*"] }, "deny": { "tools": { "playwright": ["browser_type"], "postgres": ["drop_*", "delete_*"] } } } } ``` **Behavior:** - Server access: ALL servers ✓ - Tool access for `playwright`: ALL tools EXCEPT `browser_type` ✓ - Tool access for `postgres`: ALL tools EXCEPT those matching `drop_*` or `delete_*` ✓ - Tool access for other servers: ALL tools ✓ (implicit grant) ### Example 5: Default Agent with Limited Access ```json { "default": { "allow": { "servers": ["context7"] } } } ``` **Behavior:** - Server access: ONLY `context7` ✓ - Tool access for `context7`: ALL tools from context7 ✓ (implicit grant) - Access to other servers: DENIED ✗ ### Example 6: Backend Agent with Narrow Permissions ```json { "backend": { "allow": { "servers": ["postgres", "filesystem"], "tools": { "postgres": ["query", "list_*"], "filesystem": ["read_*", "list_*"] } }, "deny": { "tools": { "postgres": ["drop_*", "delete_*"], "filesystem": ["write_*", "delete_*"] } } } } ``` **Behavior:** - Server access: `postgres` and `filesystem` ✓ - Tool access for `postgres`: ONLY `query` and tools matching `list_*` ✓ (explicit restriction) - Tool access for `filesystem`: ONLY tools matching `read_*` or `list_*` ✓ (explicit restriction) - Deny rules are redundant here (already narrowed by allow rules) but serve as safety net ### Example 7: Precedence - Deny Always Overrides Allow ```json { "agent": { "allow": { "servers": ["db"], "tools": { "db": ["delete_user", "delete_data", "get_user"] } }, "deny": { "tools": { "db": ["delete_*"] } } } } ``` **Behavior:** - `delete_user`: DENIED ✗ (matches wildcard deny - deny overrides explicit allow) - `delete_data`: DENIED ✗ (matches wildcard deny - deny overrides explicit allow) - `delete_anything_else`: DENIED ✗ (not in explicit allow, matches wildcard deny) - `get_user`: ALLOWED ✓ (explicit allow, no deny rules match) - `insert_user`: DENIED ✗ (not in explicit allow list) **Key Insight:** Even though `delete_user` and `delete_data` are explicitly allowed, the wildcard deny `delete_*` is checked first and blocks access. Deny rules always win. ## Semantic Meaning ### Allow Rules **`allow.servers`:** "Agent CAN access these servers" **`allow.tools`:** "Agent can ONLY access these specific tools (narrowing from implicit all)" ### Deny Rules **`deny.servers`:** "Agent CANNOT access these servers (even if in allow.servers)" **`deny.tools`:** "Agent CANNOT access these specific tools (filtering from granted set)" ## Key Differences from Current Implementation **Current (v0.1.5):** Server access does NOT grant tool access. Tools must be explicitly specified. **Desired (this spec):** Server access DOES grant all tools by default. Explicit tool rules narrow/filter access. **Why Change:** - Better UX: `"servers": ["*"]` should mean "all servers, all tools" - Less verbose config: No need to add `"tools": {"server": ["*"]}` for every server - Clearer semantics: `allow.tools` becomes opt-in restriction, not requirement - Maintains security: Deny rules and explicit tool lists still provide fine-grained control ## Edge Cases **Empty allow.tools for server:** Implicit grant (all tools) **Empty deny.tools for server:** No tools denied **Server in both allow and deny:** Deny wins (deny-before-allow) **Tool in both allow and deny:** Deny always wins (all denies checked before any allows) **Unknown agent_id:** Follow `deny_on_missing_agent` default **Server allowed, but downstream unavailable:** Return appropriate error (not policy issue) ## Migration Path Existing configs following explicit-grant model will continue to work: - If `allow.tools` is already specified → behavior unchanged - If `allow.tools` is omitted → now grants all tools (new behavior) Users wanting to maintain strict deny-by-default can: - Add explicit `allow.tools` entries for each server - Or use `deny.tools` to block all except specific patterns

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/roddutra/agent-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server