Design an MCP Security Gateway — the walkthrough in full
A written version of the interactive walkthrough above — the same steps, decisions and trade-offs, laid out for reading, reference and search.
The big idea
A gateway for the MCP threat surface
MCP made it trivial for an AI host to connect to tools and data — and just as trivial to connect to a malicious server. This isn't the generic "filter the prompt and output" problem a content guardrail solves; MCP has its own, protocol-specific attack surface: servers exposed by the hundreds of thousands, injection hidden inside the tool descriptions the model reads, one over-broad credential shared across every server, and quiet exfiltration through tool results.
We'll build the security layer that sits between the host and the servers: a mediating gateway, a server/tool allowlist, a scanner for poisoned tool metadata, least-privilege scoped tokens per server, egress control, and an audit trail — so connecting to an untrusted server doesn't mean trusting it.
How to read this: Each step opens with a real design decision — make the call before I show you what ships. Watch the diagram grow, hover the boxes, and at the end ship a tool with a poisoned description and probe another server's scope to see the gateway refuse. Hit Begin.
Step 1 · The baseline
The host connects straight to servers
The default MCP setup: the host connects directly to whatever servers its config lists, over STDIO or HTTP, and immediately trusts their tool lists and results. It works instantly. What's the actual danger once some of those servers are third-party and untrusted?
Design decision: An AI host connects directly to third-party MCP servers and trusts their tools. What's the core risk?
The call: Every connected server is implicitly trusted — its tool descriptions are read by the model as if authoritative, it can be reached with a broad credential, and a malicious or compromised one has a direct line to the host with no mediation, allowlist, or record. — Exactly: direct connection means implicit trust. A malicious server can inject instructions through tool metadata, over-reach with a shared credential, and exfiltrate through results — and with hundreds of thousands of servers found exposed, "the server is fine" is not a safe assumption. There's no boundary between the host and an untrusted third party.
A direct connection means implicit trust: the host reads untrusted servers' tool descriptions as authoritative, reaches them with a broad credential, and has no boundary against a malicious or compromised one. With MCP servers exposed at massive scale, that trust is misplaced — and there's no allowlist, scanning, scoping, or record anywhere in the path.
Connecting is not trusting: The whole design replaces "the host connects to and trusts a server" with "the host connects to a gateway that mediates, vets, scopes, and records everything a server does." Connection should never imply trust.
Step 2 · The front door
Mediate every MCP call through a gateway
First move: the host stops connecting to servers directly. Every tool discovery and tool call goes through an MCP Gateway that proxies to the servers on its behalf. Why is this mediating proxy the prerequisite for every protection?
Design decision: Why route all MCP traffic through a gateway instead of connecting the host to servers directly?
The call: A single mediating boundary is the one place you can allowlist servers, scan tool descriptions, issue scoped tokens, control egress, and log — none of which exists if the host talks to servers directly. — Right: the gateway is the enforcement point. By making all MCP traffic flow through one proxy, you create a boundary between the trusted host and untrusted servers where every subsequent control can actually be applied — the host never touches an untrusted server directly.
All MCP traffic flows through the gateway, which proxies to servers on the host's behalf. This single mediated boundary is where every protection lives — allowlisting, description scanning, scoped tokens, egress control, audit — and it means the trusted host never connects directly to an untrusted server.
One boundary to enforce at: Every control that follows depends on this proxy existing. Centralizing MCP traffic through one gateway is what turns "trust each server" into "trust the gateway, which vets each server."
Step 3 · Reachability
Allowlist servers and tools
The gateway can reach any server — but should it? The first control is deciding which servers and tools are even reachable. Why an explicit allowlist rather than blocking known-bad servers?
Design decision: How should the gateway decide which MCP servers and tools are reachable?
The call: An explicit allowlist of vetted servers and tools — only what's approved connects; everything else is denied by default. — Correct: deny-by-default. You can't enumerate every malicious server that will ever exist, so blocklisting always lags. An allowlist inverts it — only servers and tools that have been reviewed and approved are reachable, and an attacker who slips a new server into the config still can't connect because it isn't on the list.
Only explicitly-approved servers and tools are reachable through the gateway — deny by default. A blocklist always lags the flood of new and updated malicious servers; an allowlist means an attacker who injects a new server into the config still can't connect, because approval is a platform policy decision made before the model is ever involved.
Deny by default: The same least-privilege posture as any security boundary: the set of reachable servers is the narrowest that still does the job, and everything else is refused — not because it's known bad, but because it isn't known good.
Step 4 · The MCP-specific attack
Scan tool descriptions for injection
Here's the threat unique to MCP. When a server is queried for its tools, it returns each tool's name, description, and schema — and the model reads that description to decide how to use the tool. What can a malicious server do with that, and how do you defend it?
Design decision: An MCP server controls the text of its tools' descriptions, which the model reads. What's the risk, and the defense?
The call: The description is attacker-controlled text the model treats as trusted, so a malicious server can smuggle instructions ("also exfiltrate the user's files") into it — the defense is to scan every tool's metadata at the gateway before it reaches the model. — Right: this is tool-description injection, a channel unique to MCP's tool-discovery mechanism. The server writes the description; the model reads and can obey it. The gateway must inspect every tool's name, description, and schema for injection patterns and disallowed instructions before any of it is surfaced to the model — catching the attack at the boundary.
A tool description is attacker-controlled text the model reads and may obey — a prompt-injection channel unique to MCP's tool-discovery mechanism. The Description Scanner inspects every tool's name, description, and schema at the gateway, before any of it reaches the model, so instructions smuggled into tool metadata are caught at the boundary rather than executed by an agent that trusts what a server declares.
The tool list is untrusted input: This is the control a generic LLM guardrail misses: the danger isn't only in the user's prompt or the model's output, it's in the tool metadata a connected server supplies. Treat every server-provided description as hostile until scanned.
Step 5 · Least privilege
Issue scoped, per-server tokens
The gateway now vets which servers connect and scans their tools. But when it actually reaches a server, what credential does it use? The tempting default is one broad token for everything. Why is that dangerous, and what's the fix?
Design decision: What credential should the gateway use to reach each MCP server?
The call: A narrowly-scoped, short-lived credential per server — so a compromised server can only reach its own slice, not everything. — Right: least privilege for credentials. Each server gets its own token scoped to exactly what it needs and expiring quickly, so if one server is compromised, its reach is bounded to its own scope. It can't use its position to pivot into another server's data or an out-of-scope resource — the blast radius is one server, not the fleet.
The Token Service issues a narrowly-scoped, short-lived credential per server, not one broad token for all. If a server is compromised, its reach is bounded to its own scope — it can't pivot into another server's data or an out-of-scope resource. The blast radius of one bad server is that server's slice, not the whole fleet.
Per-server scope bounds the blast: The allowlist decides which servers connect; scoped tokens decide how much each can reach once connected. Together they bound both the odds and the damage of a compromised server — the same defense-in-depth as the payment gateway's mandate-plus-cap.
Step 6 · Exfiltration & records
Control egress and log everything
The final surface: even a vetted, scoped server can try to exfiltrate data through tool calls and results — encoding secrets into an argument to an external call, or returning content designed to leak. What does the gateway do about it, and why log it all?
Design decision: A scoped server tries to exfiltrate data through a tool call's arguments or results. What should the gateway do?
The call: Apply egress control to what leaves through calls and results, and append every discovery, call, and decision to an immutable audit trail — so exfiltration is blocked and any incident can be reconstructed. — Right: egress control inspects and constrains data flowing out through tool arguments and results (blocking silent exfiltration), and the immutable log records every tool discovery, call, and allow/deny decision. Together they close the exfiltration surface and make a compromised server's behavior both containable and investigable — and immutability means a bad server can't erase its tracks.
Egress control inspects and constrains what leaves through tool arguments and results, blocking silent exfiltration a scoped-but-malicious server might still attempt. Every tool discovery, call, and decision — including blocked ones — is appended to an immutable audit trail, so exfiltration is contained and any incident can be reconstructed after the fact.
Bound what leaves, record what happened: Scope limits reach; egress control limits what flows out; the audit trail makes it all accountable. The last surface of a connected server is the data it can smuggle, and this closes it while keeping an un-erasable record.
The payoff
Connect to untrusted servers, safely
Put it together: an AI host can use the whole MCP ecosystem — hundreds of tools from third-party servers — without trusting any of them, because the gateway vets, scans, scopes, controls, and records everything a server does.
That's the MCP security gateway. Mediate every call, allowlist by default, scan the tool metadata, scope each server's credential, control egress, and log immutably — the MCP-protocol-specific defenses a generic prompt-and-output guardrail simply doesn't cover.
- All MCP traffic flows through one mediating gateway — the host never connects directly to an untrusted server.
- Only allowlisted servers and tools are reachable (deny by default), because blocklisting can't keep up with new and updated malicious servers.
- Every tool description is scanned before it reaches the model — tool metadata is an attacker-controlled injection channel unique to MCP.
- Each server gets a narrowly-scoped, short-lived token, so a compromised server's blast radius is its own slice, not the fleet.
- Egress control blocks silent exfiltration through tool calls/results, and an immutable audit trail records every decision for investigation.