Skip to main content

MCP Tool Control

This guide covers patterns for governing MCP (Model Context Protocol) tool access with Control Zero. Whether your agents run through Claude Code, Cline, Cursor, or a custom MCP client, these patterns apply.

Overview

MCP tools give AI agents powerful capabilities: file system access, database queries, shell execution, API calls, and more. Without governance, any agent can use any tool. Control Zero lets you define exactly which tools each agent can use.

Core Pattern

Every MCP tool call is a (action, resource) pair:

  • Action: Always mcp.tool.call
  • Resource: mcp://{server}/{tool}
cz.enforce(
action="mcp.tool.call",
resource="mcp://filesystem/read_file",
context={"agent_id": "my-agent"},
)

Common Governance Patterns

Read-Only Agent

Allow an agent to read but not write:

{
"name": "read-only-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool.call", "resource": "mcp://filesystem/read_file" },
{ "effect": "allow", "action": "mcp.tool.call", "resource": "mcp://filesystem/list_directory" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://filesystem/write_file" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://filesystem/delete_file" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://shell/execute" }
]
}

Database Query Agent

Allow SELECT queries but deny writes:

{
"name": "db-reader-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool.call", "resource": "mcp://database/read_query" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://database/write_query" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://database/execute_query" }
]
}

API-Only Agent

Allow external API calls but deny local resource access:

{
"name": "api-only-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool.call", "resource": "mcp://http/request" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://filesystem/*" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://shell/*" },
{ "effect": "deny", "action": "mcp.tool.call", "resource": "mcp://database/*" }
]
}

Implementing an MCP Gateway

For MCP-native tools (Claude Code, Cline, Cursor), you can build a Control Zero MCP server that acts as a policy gateway:

import controlzero
from typing import Any

cz = controlzero.ControlZero()
cz.initialize()


class PolicyGateway:
"""MCP gateway that enforces Control Zero policies on tool calls."""

def __init__(self, agent_id: str):
self.agent_id = agent_id

def call_tool(self, server: str, tool: str, arguments: dict) -> Any:
"""Call an MCP tool with policy enforcement."""

# Enforce the policy
cz.enforce(
action="mcp.tool.call",
resource=f"mcp://{server}/{tool}",
context={
"agent_id": self.agent_id,
"arguments": str(arguments),
},
)

# Policy passed -- forward to the actual MCP server
return self._forward_to_server(server, tool, arguments)

def check_tool(self, server: str, tool: str) -> bool:
"""Check if a tool call would be allowed (without enforcing)."""
decision = cz.check(
action="mcp.tool.call",
resource=f"mcp://{server}/{tool}",
context={"agent_id": self.agent_id},
)
return decision.allowed

def _forward_to_server(self, server, tool, arguments):
"""Forward the call to the actual MCP server."""
# Implementation depends on your MCP client library
pass

Batch Checking Available Tools

Before presenting available tools to an agent, filter by policy:

from controlzero import CheckRequest

available_tools = [
("filesystem", "read_file"),
("filesystem", "write_file"),
("filesystem", "delete_file"),
("database", "read_query"),
("database", "write_query"),
("shell", "execute"),
("http", "request"),
]

# Batch check which tools this agent can use
requests = [
CheckRequest(
action="mcp.tool.call",
resource=f"mcp://{server}/{tool}",
context={"agent_id": "my-agent"},
)
for server, tool in available_tools
]

decisions = cz.check_batch(requests)

# Build the allowed tool list
allowed_tools = [
tool
for tool, decision in zip(available_tools, decisions)
if decision.allowed
]

print("Allowed tools:", allowed_tools)

Next Steps