MCP Needs a Type System, Part 1: Six Incidents That Expose the Protocol's Blind Spot
Your AI agents are only as safe as the contracts they honor—and right now, MCP doesn't have any.
Your AI agents are only as safe as the contracts they honor—and right now, MCP doesn't have any.
The Model Context Protocol has achieved something remarkable in the AI landscape: genuine cross-vendor momentum. Microsoft integrated MCP into Copilot Studio and Azure AI Foundry. Anthropic, the protocol's creator, baked it into Claude Desktop. Auth0, Cloudflare, and Hugging Face published integration guides. Even enterprises historically allergic to emerging standards are rolling out MCP servers faster than their security teams can evaluate them.
And therein lies the problem.
By mid-2025, MCP-related security incidents were no longer theoretical exercises from academic papers. They were CVEs in production systems:
mcp-remote (437,000+ weekly downloads) that turned OAuth proxies into remote shells.A critical command injection vulnerability in mcp-remote (437,000+ weekly downloads) that turned OAuth proxies into remote shells. An attacker could craft a malicious authorization_endpoint that mcp-remote passed directly to the system shell—achieving arbitrary code execution on client machines.

Hidden prompts embedded in Word documents and emails hijacked Microsoft 365 Copilot, silently exfiltrating sensitive data with zero user interaction.

A malicious MCP server masquerading as a legitimate email integration quietly BCC'd all outbound emails to an attacker-controlled address. Discovery came only after 1,500 weekly users had been compromised.

A bug in Asana's MCP implementation allowed data belonging to one organization to be viewed by other organizations—a cross-tenant breach in a system designed for autonomous agent access.

These aren't edge cases exploited through exotic attack chains. They're fundamental design gaps exposed by predictable adversaries doing predictable things.
MCP's tooling does include an input validation mechanism: JSON Schema. Each tool definition can specify an inputSchema that describes expected parameters. Clients validate inputs before transmission. Servers revalidate before execution. On paper, this sounds rigorous.
In practice, JSON Schema provides structural validation without semantic enforcement. Consider this common pattern:

The schema validates that query is a string. It cannot validate that query is actually a SELECT statement. The description field amounts to a polite request that the LLM—which has no understanding of SQL semantics—please don't generate destructive queries.
This pattern repeats across the MCP ecosystem:
JSON Schema can check types. It can enforce required fields. It can pattern-match strings. But it cannot express domain-specific constraints like "this path must resolve within the workspace directory" or "this query must not modify data." The description field—where developers attempt to communicate these constraints—goes to the LLM, not to a validation engine.
What's more, different MCP clients interpret JSON Schema differently. Azure AI Foundry, for example, enforces a restricted subset of JSON Schema features. Keywords like anyOf and oneOf silently fail. A schema that validates perfectly in Claude Desktop may break in Foundry without explanation.
The result is a "type safety" layer that's neither type-safe nor semantically meaningful. Developers write descriptions hoping LLMs will behave. Security teams audit tools hoping the descriptions are accurate. Neither can verify the other.
The MCP security incidents of 2025 share a common pattern. None exploited JSON Schema validation bugs. All exploited the gap between what tools claim to do and what they actually permit.
Invariant Labs demonstrated that malicious MCP servers can inject hidden instructions into tool descriptions that AI assistants process without user awareness. By combining "tool poisoning" with legitimate servers in the same agent context, attackers silently exfiltrated a user's entire WhatsApp history.

The tool description—the unstructured natural language meant to guide the LLM—became the attack vector.
The GitHub MCP server breach worked differently. A malicious public GitHub issue contained prompt-injection content that hijacked an AI assistant. The assistant then used its legitimate MCP tools—with a single overly-permissive Personal Access Token—to pull data from private repositories and leak it to a public pull request.

The tools worked as designed. The authorization boundary between public and private content didn't exist.
The Postmark email incident illustrated supply-chain risk in the MCP registry. Getting a package listed requires only proof of GitHub repository or domain ownership—no code review, security audit, or malware scanning. A legitimate-looking server can establish trust over time, then turn malicious in a routine update.

The registry's implicit trust became the attack vector.
MCP proxy servers that use static client IDs to authenticate with third-party authorization servers create "confused deputy" vulnerabilities. Attackers can craft malicious authorization requests that exploit consent cookies from legitimate sessions, obtaining authorization codes without proper user approval.

The authorization delegation chain—not any individual tool—became the attack vector.
Six incidents. Six different attack surfaces. One recurring theme.

In each case, the tools worked exactly as designed. The vulnerability wasn't a bug in the traditional sense—it was the absence of a formal boundary that everyone assumed existed.
JSON Schema validates structure. It cannot validate intent. It cannot express "this SQL parameter must be SELECT-only" or "this file path must stay within the user's home directory" or "this OAuth scope applies only to public repositories."
The question isn't whether MCP needs guardrails. It's what those guardrails should look like.
In Part 2, we'll explore a different approach: treating MCP tool contracts not as documentation, but as code—with all the compile-time verification, type safety, and runtime enforcement that implies.