Validating every tool invocation in Model Context Protocol server deployments
MCP standardizes tool discovery and invocation. It doesn't govern what agents are authorized to call. Here's how to add policy enforcement at the MCP boundary.
Validating every tool invocation in Model Context Protocol server deployments
The Model Context Protocol gives agents a standardized way to discover and invoke tools hosted on external servers — turning tool-use from a framework-specific implementation detail into a shared, composable infrastructure layer. This is genuinely useful for building agents that can reach a growing ecosystem of MCP-compatible services.
What MCP does not provide is a governance layer. The protocol handles tool discovery, schema validation, and invocation mechanics. It does not address whether a given agent should be allowed to call a given tool, whether the parameters the agent has chosen are within policy, or whether the invocation should be logged for compliance review.
This post covers the governance gap in MCP deployments and shows how to add runtime policy enforcement at the MCP boundary without modifying your server implementations or agent logic.
| Capability | MCP Provides | MCP Doesn't Address |
|---|---|---|
| Tool discovery | ✅ Standardized schema listing | — |
| Schema validation | ✅ Input parameter types | Policy-level parameter constraints |
| Invocation mechanics | ✅ Standard call protocol | — |
| Access control | ❌ | Which agents may call which tools |
| Confidence scoring | ❌ | Certainty estimate before execution |
| Audit trail | ❌ | Structured compliance records |
| Escalation routing | ❌ | Human review for high-risk calls |
An MCP server that exposes write operations — file writes, API calls, database mutations — is accessible to any agent with a valid MCP client connection, unless access control is enforced at the governance layer. MCP's schema validation confirms parameter types; it cannot confirm authorization.
import { defineMcpPolicy } from "@agenttrust/sdk";
export const fileServerPolicy = defineMcpPolicy({
server: "filesystem-mcp-server",
tools: {
"read_file": { trustLevel: "standard", threshold: 0.75 },
"list_dir": { trustLevel: "standard", threshold: 0.75 },
"write_file": { trustLevel: "sensitive", threshold: 0.90 },
"delete_file": { trustLevel: "critical", blocked: true },
},
// Require approval for any write to paths matching /prod/*
parameterRules: [
{
tool: "write_file",
condition: (params) => params.path?.startsWith("/prod/"),
effect: "require_approval",
},
],
});import { Client } from "@modelcontextprotocol/sdk/client";
import { AgentTrustMcpAdapter } from "@agenttrust/sdk";
import { fileServerPolicy } from "./policy";
// Wrap the MCP client — no server changes required
const mcpClient = new Client({ name: "my-agent", version: "1.0.0" });
const governedClient = new AgentTrustMcpAdapter(mcpClient, {
policy: fileServerPolicy,
agentId: "research-agent-v1",
});
// Connect as normal
await governedClient.connect(transport);
// All tool calls through governedClient are policy-evaluated
const result = await governedClient.callTool({
name: "write_file",
arguments: { path: "/reports/summary.md", content: "..." },
});
// If score < threshold → escalate or block (per policy)
// Otherwise → execute and record in Trust Auditimport { TrustAudit } from "@agenttrust/sdk";
const audit = new TrustAudit();
// All governed MCP calls in the last 24 hours
const records = await audit.query({
source: "mcp",
agentId: "research-agent-v1",
from: new Date(Date.now() - 86_400_000).toISOString(),
});
// Each record includes:
// { server, tool, params, score, signals, route, agentId, timestamp }
// Filter for escalated or blocked calls
const flagged = records.filter(r => r.route !== "autonomous");Add Trust Runtime to your MCP client. Every tool invocation is validated before it reaches the server.
View MCP Integration →