An MCP server hands your credentials to a caller that can be talked into anything. This is the checklist we run before one ships — auth, token scoping, input validation, secrets, and audit logging.
An MCP server is a security problem wearing an integration's clothes. It looks like an API adapter, so people secure it like one — add auth, ship it — and then it does something an API never does: it hands your credentials to a probabilistic agent that decides, turn by turn, what to call, based partly on text a stranger wrote. The threat model is not "a bad user hits my endpoint." It is "a well-meaning assistant gets talked into using my authority against me." Security researchers have spent 2026 warning that MCP is a genuine attack surface, and the reason is exactly this gap between how the thing looks and how it behaves.
This is the checklist we run before an MCP server touches anything real. It is deliberately practical and deliberately boring — the incidents come from the boring parts, not from cracked cryptography. If you are deciding whether to build one at all, start with how to add an MCP server to your SaaS; if you want the war stories behind these rules, the MCP server security mistakes nobody warns you about covers the failure modes we hit in production. What follows is the list to check items off against.
The MCP spec has moved toward OAuth 2.1 with PKCE as the expected way to authenticate, and for good reason — a static API key baked into a client is a credential that leaks, never rotates, and carries no user identity. PKCE (Proof Key for Code Exchange) closes the interception window on the authorization flow so a stolen authorization code is useless without the matching verifier.
Treat OAuth 2.1 + PKCE as the direction the spec and the ecosystem now expect, not a box that makes you done. Auth is table stakes and it fails silently — most real MCP incidents happen downstream of a correctly authenticated request.
This is the single most important item on the list, and the most commonly skipped. The classic break: your server authenticates the human with OAuth, then calls the downstream API with one shared service-account key that can read every tenant's data. A prompt injection convinces the agent to fetch customer 4417's records, your server obliges, and the service account sees everything, so nothing stops it. You have built an exfiltration path and called it an integration.
The arguments to a tool call are attacker-influenced by default — the agent constructs them from context that may include a malicious web page, a Jira comment, or an uploaded PDF. Validate them like you would validate a request from the open internet, because functionally that is what they are.
You cannot make the model immune to being manipulated, so you contain what a manipulated model can do. The rule is that no single agent turn should be allowed to both ingest untrusted content and fire a high-privilege write without a human or a policy gate in between.
Two leaks live here. The first is your own secrets. The second is data the tool returns, which crosses a trust boundary into a model you do not control and usually into a vendor's servers.
When something goes wrong with an agent in the loop, you need to reconstruct what it called, on whose behalf, with what arguments, and what came back. Without that record, an incident is unknowable. And because agents loop, you need limits that stop a confused session before it becomes a bill or an outage.
Before an MCP server ships, verify: OAuth 2.1 with PKCE and short-lived tokens; downstream credentials scoped to the calling user, never a shared superuser key; strict input schemas validated server-side on every call; destructive actions behind a confirmation gate and unable to fire in the turn that ingested untrusted content; secrets in a manager and outputs constrained to an explicit schema; and audit logging plus rate limits and timeouts on every tool.
None of this is exotic. It is the API hygiene you already know, applied on the assumption that the caller is a well-meaning agent that can be talked into anything. The mistakes that get you owned are almost never clever — they are a skipped scope, a raw object return, or a description built from user input.
If you are building an MCP server that touches real customer data and want the threat model reviewed — or built right the first time — get in touch. It is what we do.
The spec and the surrounding ecosystem have moved toward OAuth 2.1 with PKCE as the expected authentication approach, and it is the sound default. Treat it as the direction things are going rather than a single mandatory clause — the important point is that a static, long-lived API key is not adequate, because it never rotates, carries no user identity, and leaks permanently.
Using a single shared service-account credential for the downstream calls. The server authenticates the human correctly, then reaches the backend with a superuser key that can see every tenant's data, so a prompt injection can steer the agent into reading records the user should never access. Scoping the downstream credential to the calling user, per request, is the fix.
No. The agent constructs tool arguments from context that can include content written by an attacker — a web page, a support ticket, an uploaded file — and it can be talked into misusing your authority. You cannot make the model immune, so the defense is containment: least-privilege scoping, input validation, and gating destructive actions so a manipulated model has a small blast radius.
Yes, whenever the agent can read content from outside your team. If a tool summarizes tickets, reads emails, or ingests documents, that text reaches the model as potential instruction. An internal deployment narrows who can inject, but any untrusted input flowing into the agent is a path, so the same output-treatment and gating rules apply.
Yes. We build MCP servers in front of internal databases, billing systems, and third-party APIs, and we can review an existing server's threat model or build one with you from the start. Scope, effort, and cost depend on how many capabilities you expose and how sensitive the data behind them is — reach out and we'll talk specifics.
A software studio that ships and maintains its own products — KeepChats, Gwora and Cairn — and builds the same way for clients. Founded and led by codewithumar.
Talk to the studio →Send the problem. You get one fixed number and a plan back within a business day.
We build software worth keeping — for clients, and for ourselves.
Founded & led by codewithumar