Supplemental: MCP Governance Policies¶
This guide moves one layer outward to Model Context Protocol (MCP), where agents discover and call tools exposed by external servers.
What you'll learn:
| Section | Topic |
|---|---|
| Introduction | Why MCP needs governance |
| The MCP Proxy | How @microsoft/agentmesh-mcp-proxy intercepts tool calls |
| Policy YAML format | How proxy policies are structured |
| Built-in policies | Minimal, standard, strict, enterprise |
| Writing custom rules | Path filters, regex filters, and rate limits |
| OWASP alignment | How rules map to ASI-01 through ASI-10 |
| Trust-gated MCP access | DID- and trust-based access gates |
| Next steps | Where to go from here |
Introduction¶
MCP is the protocol that lets an agent connect to tools such as filesystems, databases, GitHub APIs, or custom business services:
agent -> MCP client -> MCP server -> tool
By default, MCP does not decide whether a tool call is safe. If an agent has a handle to run_shell, query_database, or read_file, a prompt injection or over-permissive workflow can turn that into code execution, data exfiltration, or runaway automation. Governance answers which tools and arguments are allowed and what gets logged for audit.
The MCP Proxy¶
@microsoft/agentmesh-mcp-proxy sits between the agent and the original MCP server. The proxy intercepts requests and either forwards or blocks the call.
The proxy only intercepts tools/call messages. Other MCP traffic passes through unchanged. For every tool call, it:
- Sanitizes inputs for dangerous patterns.
- Applies a CLI rate limit if you passed
--rate-limit. - Evaluates policy rules.
- Audits the decision and either forwards or denies.
Run it like this:
npx @microsoft/agentmesh-mcp-proxy protect --policy standard @anthropic/mcp-server-filesystem /workspace
That makes the proxy the enforcement point in front of the MCP server.
Policy YAML format¶
Use standard.yaml as the reference shape. Proxy policies are intentionally small: a header, a list of rules, and optional schema fields for rate limiting.
version: "1.0"
mode: enforce
rules:
- tool: "run_shell"
action: deny
reason: "Shell execution not permitted"
- tool: "read_file"
action: allow
conditions:
- path_not_contains: [".env", ".secret", "credentials"]
- tool: "http_request"
action: allow
rate_limit:
requests: 30
per: minute
- tool: "*"
action: allow
rate_limits:
global:
requests: 100
per: minute
The important pieces are mode, ordered rules, and per-rule conditions. The schema also supports per-rule rate_limit and top-level rate_limits, and the proxy also accepts a global --rate-limit CLI option.
Two details matter in practice: first match wins, and an explicit * rule keeps your intent obvious during review.
In the current code, rate limiting exists both in the policy shape and in the proxy runtime path. If you want an explicit global limit from the CLI, use --rate-limit.
For the built-in minimal tier, the policy is effectively just:
Useful for demos and auditing, but not for containment.
Built-in policies¶
The proxy ships with four policy tiers:
| Tier | Best for | Behavior |
|---|---|---|
minimal | Demos and visibility-first testing | Allow everything |
standard | Development and staging | Block obviously dangerous tools, allow most others |
strict | High-security environments | Allowlist-only behavior with explicit read-focused rules |
enterprise | Production starting point | Denials, path filters, regex guards, and stronger database/file constraints |
standard is the balanced default. strict flips to allowlist-only behavior. enterprise adds stronger patterns for tools like query_database.
Writing custom rules¶
The schema gives you four practical levers:
- Deny dangerous tools such as shell or eval.
- Scope file access by path.
- Reject suspicious argument patterns such as destructive SQL.
- Add rate limits for expensive or sensitive tools.
Here is a copy-paste-ready example with OWASP annotations as YAML comments:
version: "1.0"
mode: enforce
rules:
# ASI-02, ASI-05
- tool: "run_shell"
action: deny
reason: "Shell access is blocked"
- tool: "eval"
action: deny
reason: "Dynamic evaluation is blocked"
# ASI-02, ASI-06
- tool: "read_file"
action: allow
conditions:
- path_starts_with: "C:\\workspace\\docs\\"
- path_not_contains: [".env", ".pem", "secrets", "credentials"]
rate_limit:
requests: 30
per: minute
# ASI-02, ASI-06
- tool: "query_database"
action: allow
conditions:
- argument_not_matches:
query: "(?i)\\b(DROP|DELETE|TRUNCATE|ALTER)\\b"
rate_limit:
requests: 10
per: minute
# ASI-10
- tool: "*"
action: deny
reason: "Tool not approved for this agent"
rate_limits:
global:
requests: 60
per: minute
This one file says: no shell, no eval, no secrets, and no destructive SQL. It also shows how to declare rate limits in the policy file, while --rate-limit remains useful when you want an explicit global CLI limit.
OWASP alignment¶
The detailed evidence lives in docs/compliance/owasp-llm-top10-mapping.md and docs/OWASP-COMPLIANCE.md. For MCP governance, the practical alignment looks like this:
| OWASP risk | How proxy policies help |
|---|---|
| ASI-01 Agent Goal Hijack | Allow/deny rules stop hijacked prompts from reaching unapproved tools |
| ASI-02 Tool Misuse & Exploitation | Tool allowlists, denylists, path filters, and argument regexes constrain tool behavior |
| ASI-03 Identity & Privilege Abuse | Pair proxy rules with DID-based trust checks so access is tied to agent identity |
| ASI-04 Supply Chain Vulnerabilities | Reviewable built-in tiers and checked-in YAML reduce surprise exposure from third-party MCP tools |
| ASI-05 Unexpected Code Execution | Deny run_shell, execute_command, eval, and spawn_process |
| ASI-06 Memory & Context Poisoning | Secret-path blocking and argument filtering prevent poisoned context from turning into exfiltration |
| ASI-07 Insecure Inter-Agent Communication | Trust-gated MCP endpoints add authentication and trust checks before agents collaborate |
| ASI-08 Cascading Failures | CLI rate limits and deny rules reduce runaway call chains |
| ASI-09 Human-Agent Trust Exploitation | Audit visibility helps, and this guide naturally leads into approval workflows for sensitive actions |
| ASI-10 Rogue Agents | Catch-all deny rules and rate caps confine agents that drift out of scope |
The important pattern is enforcement, not just detection. A good policy blocks risky tool calls before they reach the server.
Trust-gated MCP access¶
For some environments, allow/deny rules are not enough. You also want to know who is asking. This repo has two related Python packages:
mcp-trust-proxyis the inline trust-gating layer.mcp-trust-serveris an MCP server that exposes trust-management tools such ascheck_trust,get_trust_score,establish_handshake, andverify_delegation.
If you want a trust proxy, use mcp-trust-proxy. If you want an MCP surface that lets clients query and manage trust, use mcp-trust-server.
from mcp_trust_proxy import TrustProxy, ToolPolicy
proxy = TrustProxy(
default_min_trust=300,
tool_policies={
"file_write": ToolPolicy(min_trust=800, required_capabilities=["fs_write"]),
"shell_exec": ToolPolicy(min_trust=900, blocked=True),
},
)
result = proxy.authorize(
agent_did="did:agentmesh:agent-1",
agent_trust_score=600,
agent_capabilities=["fs_read", "search"],
tool_name="file_read",
)
assert result.allowed
Use mcp-trust-server alongside that when you want trust operations over MCP. Policy decides what can happen; trust helps decide who gets to ask.
Next steps¶
- Read
enterprise.yaml. - Review
docs/compliance/owasp-llm-top10-mapping.mdanddocs/OWASP-COMPLIANCE.md. - Start with
standard, then move tostrictor custom rules.
Some actions are too risky to decide with automation alone. In the main series, the next planned topic is approval workflows.
Previous: Chapter 3 — Rate Limiting Next: Chapter 5 — Approval Workflows