The governing assumption
Design as though the AI will eventually be manipulated. Filtering helps; it is not a foundation. The defence that holds is tool scope — if a fully compromised agent still cannot exfiltrate, delete or spend, the attack has nowhere to go.
MCP servers sit between an AI model and your systems, which makes them a security boundary. These are the design decisions that determine whether that boundary holds.
The attack surface
| Attack | How it works | Primary defence |
|---|---|---|
| Prompt injection | Instructions hidden in retrieved content | Narrow tool scope; approval gates |
| Privilege escalation | Agent accessing data beyond the user's rights | Per-user permission mapping |
| Data exfiltration | Manipulating the agent into sending data out | No unrestricted outbound tools |
| Parameter injection | Malicious values passed to a tool | Strict input validation |
| Resource exhaustion | Agent looping, generating volume | Rate limits and spend caps |
| Confused deputy | Agent using its own broad rights on request | Act as the user, not as the service |
Prompt injection in practice
Your agent reads content authored outside your control — supplier emails, customer tickets, uploaded documents, web pages. Any of it can contain text designed to redirect the model.
The mistake is treating this as a filtering problem. Filters catch obvious attempts and miss creative ones. The reliable defence is architectural: if your tools cannot send data anywhere, cannot delete, and cannot spend without confirmation, then a successfully manipulated agent achieves nothing worth the attacker's effort.
Layered mitigations, in order of reliability:
- Tool scope — the agent simply cannot perform harmful operations. Most reliable.
- Approval gates — consequential actions require a human, who sees what is proposed.
- Structural separation — retrieved content clearly delimited from instructions in the prompt.
- Content filtering — detecting obvious injection patterns. Useful, insufficient alone.
- Output checking — verifying responses do not contain data that should not leave.
Tool design rules
- One tool, one operation. "Get order by ID", not "query orders".
- Never expose arbitrary execution — no raw SQL, no generic HTTP request tool, no shell access. These recreate the problem you built the server to solve.
- Validate every parameter against a schema. Type, format, range. An order ID must look like one.
- Constrain result size. A tool returning ten thousand records is an exfiltration vector and a cost problem.
- Return only necessary fields. If the assistant needs status, do not return the full customer record.
- Make tool descriptions precise. Vague descriptions cause wrong tool selection, which looks like unreliability.
Every convenience you add to a tool is capability an attacker inherits. The most secure tool is the narrowest one that still does the job.
Permission mapping
The single most important control, and the one most often skipped in early implementations:
- Resolve the requesting user's identity, not the service account's.
- Apply their permissions — the agent sees exactly what that person could see directly.
- Never use a shared privileged credential for all requests.
- Fail closed. If identity cannot be established, deny rather than defaulting to broad access.
- Re-check per call. Permissions change; a long session should not carry stale rights.
The test that validates your permission model: have two users with genuinely different access ask the same question through the assistant. If they get the same answer, your model is not working — the agent is using its own rights rather than theirs, which is the confused-deputy problem.
Approval gates, calibrated properly
| Action type | Reversible? | Gate |
|---|---|---|
| Read a record | N/A | Automatic |
| Search or summarise | N/A | Automatic |
| Create a draft | Yes | Automatic |
| Update a record | Usually | Confirm or log prominently |
| Send a message externally | No | Always confirm |
| Issue payment or refund | No | Always confirm |
| Delete data | No | Always confirm |
Gate by reversibility and blast radius rather than by a simple read/write split. An internal draft is a write and carries no risk; an outbound email is a write and cannot be recalled.
Operational controls
- Rate limits per user and per session — the primary defence against a looping agent.
- Spend caps on anything with a per-call cost.
- Timeouts so a stuck tool call does not hold resources indefinitely.
- Instant revocation — a documented way to disable access immediately, tested before you need it.
- Alerting on anomalies — unusual volume, repeated failures, access patterns outside the norm.
Audit logging that is actually useful
- Requesting user identity, tool name, parameters, result summary, timestamp, outcome.
- Retained long enough to investigate an incident discovered weeks later.
- Stored where the agent cannot modify them.
- Reviewed on a sample basis, with automated alerts on patterns.
Logging you never read provides evidence after an incident but prevents nothing. Periodic review is what turns it into a control.
Testing before deployment
- Injection testing — documents containing manipulation attempts in the corpus.
- Permission testing — different users, same question, verified different results.
- Parameter fuzzing — malformed and boundary inputs to every tool.
- Rate limit verification — confirm limits actually engage.
- Revocation drill — disable access and confirm it takes effect immediately.
Building an MCP server that has to pass security review? Tell us what systems it will front. See our MCP server service, secure enterprise data access, and guardrails to demand.