MCP is becoming connective tissue between agents and tools. That is useful, but it also creates a new runtime boundary: filesystem access, repository operations, internal services, and data stores can now be invoked through a common protocol.
The mistake is treating a tool catalog as a permission model. A model that can see a tool may still request unsafe inputs, reach outside the intended workspace, or combine legitimate tools into a harmful sequence.
CapFence fits as a policy proxy in front of MCP tools.
flowchart LR
Agent[Agent runtime] --> Request[MCP tool request]
Request --> Gate[CapFence policy gate]
Gate -->|allow| Tool[MCP server]
Gate -->|deny| Audit[Tamper-evident audit]
Gate -->|approval| Human[Human approval queue]The control is deliberately boring: map every MCP request to a capability, evaluate it against local policy, and record the decision. That keeps the tool ecosystem flexible while making high-risk execution deterministic.
event = ActionEvent.create(
actor="research-agent",
resource="mcp.filesystem",
action="read",
environment="production",
payload={"path": "../../secrets/api_keys.txt"},
)
verdict = runtime.execute(event)
assert verdict.authorized is FalseAgent frameworks will keep changing. The enforcement point should stay stable.