Skip to content
AdminKit

How to secure an MCP server: auth, tool allowlists and prompt injection

AdminKit's guide to securing an MCP server covers three layers: require OAuth authorization per the MCP specification, limit which tools a client can call with an allowlist, and treat every tool response as untrusted input that could carry prompt-injection content — not just lock the front door and assume the rest is safe.

By AdminKit team, Netbase JSC · Updated

Why MCP servers end up exposed and unprotected

Model Context Protocol (MCP) servers give an AI agent the ability to call real tools — reading files, querying a database, hitting an internal API — which is exactly what makes an unprotected one dangerous. According to the Model Context Protocol specification, “the protocol intentionally limits server visibility into prompts” and places a strong emphasis on user consent for tool invocation and data access, but authorization itself is explicitly optional in the spec — implementations using an HTTP-based transport “SHOULD” support it, not “MUST.” That gap between “should” and a hard requirement is exactly where many real-world MCP servers end up: built quickly during a prototype, left reachable on the public internet, with no authentication layer added before anyone noticed.

Step 1: find out what you’ve actually exposed

Before hardening anything, check your current state. AdminKit’s MCP endpoint check tests whether an MCP endpoint is reachable and whether it demands authentication, which answers the most urgent question first: is this server callable by anyone who finds it right now — see how to read an MCP endpoint check result for what each finding means. If it’s meant to be internal-only, confirm it isn’t reachable from the public internet at all before worrying about anything further down this list.

Step 2: implement authorization per the spec, not an ad-hoc scheme

The MCP Authorization specification defines a complete OAuth-based flow for HTTP-transport MCP servers, built on existing, well-reviewed standards rather than a custom scheme:

  • Your MCP server acts as an OAuth 2.1 resource server, validating bearer tokens on every request.
  • It must implement OAuth 2.0 Protected Resource Metadata (RFC 9728) so clients can discover which authorization server to use.
  • For the Streamable HTTP transport specifically, the spec also requires validating the Origin header on every connection to prevent DNS rebinding attacks, and recommends binding to localhost rather than all interfaces for a server that’s only meant to run locally — see transport security (MCP) for how these requirements differ between HTTP and stdio transports. This is a separate control from the OAuth flow below; a server can get authorization right and still skip Origin validation.
  • The authorization server itself must publish OAuth 2.0 Authorization Server Metadata (RFC 8414).
  • Servers should support Dynamic Client Registration (RFC 7591) so clients can obtain credentials without manual, per-client setup — important for MCP specifically, since a client may encounter servers it has no prior relationship with.
  • On an invalid or missing token, the server must return HTTP 401 with a WWW-Authenticate header pointing to its resource metadata — this is how a well-behaved client discovers how to authenticate in the first place.
  • Tokens must be validated for audience (that they were actually issued for this server) — the spec is explicit that a server “MUST NOT accept or transit any other tokens,” specifically to prevent a stolen or misdirected token issued for one service being replayed against another.

This is more involved than typical API-key auth, but reusing standard OAuth 2.1 flows (described in RFC 6749 and refined since) means you can lean on existing, well-tested OAuth libraries rather than building token validation from scratch.

Step 3: add a tool allowlist, separate from authentication

Authentication answers “who is this caller.” A tool allowlist answers a different question: “which of my tools should this caller be able to invoke at all.” These are not the same control, and skipping the second one is a common gap even on servers that do authenticate properly:

  • Enumerate every tool your server exposes and explicitly decide whether it should be callable by external clients at all — development or debug tools are frequently left callable by accident. Pin and diff each tool’s description on every connection too, not just its name: see tool poisoning for how a changed description can manipulate the agent reading it without the tool’s actual function changing at all, and how to check for MCP tool poisoning for reading a server’s tool list before you connect an agent to it.
  • Give the same scrutiny to any resource template your server declares, not just its tools — a single parameterized template like file:///{path} can stand in for an entire directory tree, so a review that only scans resource names by label can miss how much it actually exposes.
  • Give the same review to any prompts your server exposes — a prompt is user-triggered rather than model-invoked, but its underlying template can still embed the same kind of unreviewed instructions a malicious tool description would carry.
  • Confine any tool that touches the filesystem to whatever directories the client has advertised as roots — the specification treats this as an advisory boundary, not an enforced sandbox, so a well-behaved server still has to honor it voluntarily rather than relying on it as a guarantee.
  • Where your MCP framework supports scoped tokens, tie specific tools to specific OAuth scopes, so a token issued for read-only access literally cannot invoke a tool that writes data.
  • Log every tool call (who, which tool, when, and the outcome) — this is what makes it possible to notice misuse after the fact, not just block it in the moment.

Step 4: treat tool responses as untrusted input

This is the step most MCP deployments miss entirely. The OWASP Top 10 for LLM Applications lists prompt injection as its top risk (LLM01), and tool responses are a direct, realistic injection path: if a tool fetches content from an external, untrusted source (a webpage, a user-submitted file, a third-party API) and that content contains text crafted to look like instructions, a model reading that response as part of its context can be manipulated into acting on those embedded instructions instead of the user’s original request.

Practical mitigations, used together rather than any one alone:

  • Never treat tool output as trusted instructions. Structure prompts so the model is told tool results are data to evaluate, not commands to follow, since a tool response shares the same context window as the model’s trusted instructions with nothing in the window itself marking which is which. This applies to a tool’s structured content too — a structuredContent field conforming to a declared schema is still attacker-reachable data from an untrusted source, not a safety guarantee on its own.
  • Validate any URL a tool is about to fetch on the model’s behalf, not just the content that comes back — a tool that fetches arbitrary URLs is a server-side request forgery (SSRF) risk if an attacker can steer it toward an internal address instead of the intended one.
  • Filter or flag suspicious patterns in tool responses before they reach the model — text that resembles system-prompt-style instructions embedded in otherwise ordinary data is a common red flag.
  • Require explicit confirmation for consequential actions. The MCP specification’s own security principles state that “Hosts must obtain explicit user consent before invoking any tool” — extend that same caution to acting on anything a tool response suggests doing next, not just the initial call, and the same specification requires it again before a server’s sampling request reaches the client’s model, not only before a tool call does.
  • Keep an audit trail of tool calls and responses so an unusual pattern can be investigated after the fact.

Step 5: re-check regularly, not just once

An MCP server’s exposure can change without anyone touching its code — a network change, a new deployment, or a forgotten debug build can all reintroduce the same gap you just closed. Re-run MCP endpoint check periodically, and if you’re exposing TLS (which you should be, for any server reachable outside a trusted network), confirm your certificate setup with SSL/TLS check too. To catch a regression automatically instead of relying on remembering to re-check, AdminKit’s free GitHub Action connector, which Netbase shares on request, runs this same probe on every push or a weekly schedule — see scan an MCP endpoint in CI.

Where AdminKit fits

If you’d rather not build and maintain all of the above yourself, Netbase deploys and runs the MCP & Agent Gateway in front of your MCP server as a custom engagement, applying OAuth enforcement, tool allowlists, per-caller rate limits and response filtering, with an audit log of every call — talk to our team about it. The Agent Trust API addresses the other side of the same problem: one GET request scores an unfamiliar MCP endpoint 0-100 with a verdict and the evidence behind it, so an agent can check before calling instead of calling first and finding out later. See our AI agent builders page for the free checks and services for teams building on MCP.

Audience binding (Step 2’s token-validation requirement) exists specifically to stop one attack pattern — see the MCP confused-deputy problem and token passthrough, explained and the glossary entry for the confused deputy problem for why a gateway must validate tokens itself rather than passing them through.

If you’re building the agent side instead of the server side — calling tools rather than exposing them — see connect an AI agent to AdminKit’s MCP server for how to self-host AdminKit’s own free, open-source MCP server connector, and which of its tools return real results.

This guide is general information, not a security audit of your specific network — see our disclaimer for what AdminKit's guidance does and does not commit to.

Frequently asked questions

Is authentication mandatory for MCP servers?

No — the MCP specification makes authorization optional and leaves it to implementers, recommending it for HTTP-based transports while noting STDIO transports should rely on environment-level credentials instead. That means an unauthenticated public MCP server is spec-compliant, which is exactly why so many are deployed that way.

What's the simplest first step if I've done nothing yet?

Check whether your server is even reachable and whether it demands authentication, using a tool like AdminKit's MCP endpoint check. If it's reachable with no auth and wasn't meant to be public, restricting network access or adding authentication is the first fix, before anything more advanced.

Is a tool allowlist different from authentication?

Yes — authentication controls who can connect at all; a tool allowlist controls what an authenticated client is allowed to call once connected. A fully authenticated client with no allowlist can still call every tool your server exposes, including ones never meant for external use.

How do I actually defend against prompt injection in tool responses?

There's no single complete fix, but layered mitigations help: treat all tool output as untrusted data rather than trusted instructions, strip or flag content that resembles embedded instructions before it reaches the model, log what was returned for later review, and require explicit user confirmation before acting on anything a tool response suggests doing.

Does OAuth for MCP use a custom protocol, or standard OAuth?

The MCP authorization spec is built on standard OAuth 2.1 plus specific existing RFCs — OAuth 2.0 Authorization Server Metadata (RFC 8414), Dynamic Client Registration (RFC 7591), and Protected Resource Metadata (RFC 9728) — rather than inventing a new authorization scheme from scratch.

Want AdminKit to watch this for you?

Free checks tell you the state today. Protective DNS and monitoring tell you when it changes.

Huy Nguyen (David), Founder and CEO of Netbase JSC

Talk to an expert

Huy Nguyen (David), Founder & CEO, Netbase JSC

Ask whether this fix applies to your setup, or get a second pair of eyes on your DNS and mail records.