MCP Server Security: An Engineer’s Audit Checklist

October 18, 2026

Before an MCP server touches production data, the review that matters covers four questions: which tokens the server accepts, whether tool definitions can change after approval, how consent is enforced when the server proxies a third-party API, and what every invocation writes to the audit log. The Model Context Protocol’s own security guidance is blunt on the first point: MCP servers must not accept any tokens that were not explicitly issued for the MCP server. The rest of this checklist exists to hold that boundary — and a few others — when the component deciding what to call is a language model rather than a developer. Token passthrough, where a server forwards client-issued tokens to downstream APIs without checking they were issued for the server itself, is explicitly forbidden by the MCP authorization specification because it breaks rate limiting, audit trails and trust boundaries in one move.

If you already run latency budgets for your LLM features as a fixed pre-production gate, treat MCP server security the same way: one checklist, executed identically every time, with evidence captured per item. The official security best practices document is the reference; this article turns it plus the OWASP material into a review you can finish in an afternoon.

Why MCP shifts the attack surface

In a conventional API integration, a developer writes every call by hand and code review sees each parameter. With MCP, the model chooses which tool to invoke, when, and with which arguments, based on tool descriptions that live inside its context window. That makes the description text part of the prompt: any string a server ships in its schema or returns from a call can steer model behavior. Tool schemas are injection surface, not documentation.

Two consequences follow. First, because the model sees tool descriptions from every connected server at once, a malicious server can try to shadow or manipulate tools belonging to a different, trusted server — isolation between servers has to be enforced by you, not by the protocol. Second, an MCP server typically runs with its own credentials, so every call it makes carries the server’s privileges rather than the requesting user’s; a weak consent design converts that into a classic confused deputy.

The pre-connection audit checklist

Run this before approving any new server, and re-run it whenever a server updates its tool catalog:

  1. Inventory the declared tools, resources and prompts, and diff them against what the actual use case needs. Anything unexplained gets removed or explained in writing.
  2. Read every tool description and parameter schema before approval. Imperative verbs aimed at the model (“ignore previous”, “send to”) are a rejection reason.
  3. Pin tool definitions with cryptographic hashes at discovery time so any post-approval change raises an alert instead of silently taking effect.
  4. Confirm remote OAuth flows use PKCE, and that tokens live in OS-native credential storage — never in plaintext config files or environment dumps.
  5. Verify the server validates token audience on every request and rejects tokens issued for other resources.
  6. Run local servers in a container or sandbox with restricted filesystem access and no network unless explicitly required — the same isolation discipline that makes self-hosting embeddings on CPU safe on shared hardware.
  7. Bind remote HTTP/SSE servers to specific interfaces rather than 0.0.0.0, and validate the Host header on every incoming request.
  8. Separate high-risk servers (payments, authentication, PII) from general-purpose ones, and never share credentials or OAuth tokens across servers.
  9. Require human confirmation for destructive, financial or data-sharing calls, with the full parameter payload displayed — not just the tool name.
  10. Log every invocation with parameters, caller identity and timestamp into central storage, with secrets and PII redacted before persistence.

Mapping OWASP risks to controls

The OWASP MCP Top 10 names the risk categories that dominate real incidents; the table below maps the ones a reviewer can act on directly to the control that addresses them.

RiskWhat it looks likeControl at review time
MCP01 Token mismanagementHard-coded credentials, long-lived tokens leaking into logs or model memoryScoped ephemeral tokens, OS credential store, log redaction
MCP02 Scope creepPermissions granted for one task expanding into standing broad accessMinimal initial scopes with step-up challenges per operation
MCP03 Tool poisoningMalicious or misleading context hidden in tool descriptions or outputsSchema review before approval, output sanitization, scanner tooling
MCP06 Prompt injectionContextual payloads steering the model through retrieved contentTreat tool outputs as data; strip instruction-like markup before context injection
MCP08 Missing audit trailNo telemetry on which tool ran, for whom, with what argumentsCentral structured logging of full invocation parameters
MCP09 Shadow serversUnapproved instances running with default credentials outside governanceApproved-server registry plus network egress policy

Tool poisoning — an adversary hiding malicious or misleading context in the tools, plugins or outputs a model depends on — is catalogued as MCP03 in the OWASP MCP Top 10, and it deserves the largest share of review time because the payload arrives through a channel teams instinctively trust: the tool contract itself. Budget your review hours accordingly.

Token handling: two hard rules

Rule one: the server only accepts tokens minted for it. The failure mode the specification calls out is a server that takes a client’s token and passes it through unmodified to a downstream API — the downstream logs then show the wrong identity, rate limits are bypassed, and a stolen token becomes a reusable skeleton key across services.

Rule two: consent is per client, and it happens before any third-party redirect. The canonical attack is the confused deputy against proxy servers: a proxy that combines a static client ID with dynamic client registration and a cached consent cookie can hand an attacker an authorization code without the user ever seeing a consent screen. The attacker registers a client, sends the victim a crafted link, and the third-party authorization server skips consent because the cookie from an earlier legitimate flow is still present. Verify three mechanics against the implementation: exact-string matching on redirect URIs, single-use OAuth state values set only after explicit consent, and a per-user registry of approved client IDs checked before any authorization flow starts.

Rug pulls and hash pinning

A rug pull is a server that alters its tool definitions after the user approved them — the same name and description at install time, a different behavior a week later. The defense is mechanical: pin each tool definition at discovery time by hashing the canonical JSON of its name, description and input schema with SHA-256, then re-hash and compare before every execution. A mismatch is a deployment mutation, not a curiosity: fail the call, alert, and re-run the consent flow with the new definitions shown to the user.

The OWASP MCP Security Cheat Sheet also recommends signing JSON-RPC messages at the application layer rather than trusting TLS alone, since a compromised proxy can rewrite payloads after transport decryption. Pair that with monitoring for cross-server data flows — credentials visible to server A appearing inside calls to server B — and re-prompting for consent whenever definitions change. None of this is exotic; it is the ordinary discipline of untrusted boundaries applied to a protocol where the caller is a model. Fold the checklist into the same review slot you use for your latency SLO worksheet and it stops being a special occasion.

Sources