Back to blog
MCP server authentication OAuth 2.1 shield and gateway illustration
System Design

MCP Server Authentication: A Production Deployment Guide

Jul 21, 2026 10 min read Avinash Tyagi
mcp server authentication mcp production deployment model context protocol oauth 2.1 mcp rate limiting streamable http ai agents mcp security api gateway token passthrough

Getting a Model Context Protocol server running on your laptop takes an afternoon. Getting one running in production, serving multiple AI agents on behalf of multiple users, is a different problem. MCP server authentication is the centre of that gap.

The local version is forgiving. You run over stdio, the server trusts the process that launched it, and there is exactly one user.

None of that survives production. Once your server is reachable over HTTP you inherit every problem a public API has: identity, access control, abuse control, multi-tenancy, and observability. You also inherit problems specific to agentic systems, because the caller is a language model that can be manipulated by the data it reads.

If you have not built one yet, start with our step-by-step MCP server tutorial, and read MCP security risks developers need to know for the threat model assumed here.

What production means for an MCP server

Production is not a deployment target. It is a set of properties you can prove.

A production server answers these on demand: who is calling, what are they allowed to do, what did they do last Tuesday, what happens at a thousand calls a minute, and what happens when the process dies mid-request. If any answer is "not sure," you are running a prototype with a public IP.

The common failure is not a dramatic breach. It is a server that works for one team, gets shared, and becomes a shared-credential system where every agent acts as the same service account with no way to attribute or revoke anything.

Step one: pick the right transport

Transport choice constrains everything downstream, so decide it first.

stdio suits local, single-user tools. The client spawns the server as a subprocess, so there is no network surface and no auth story to get wrong.

Streamable HTTP is the transport for anything remote. It replaced HTTP+SSE, uses ordinary POST and GET, and works with infrastructure you already own: load balancers, API gateways, and serverless platforms.

Inside Streamable HTTP, the decision is stateful versus stateless. In stateful mode the server issues a session ID and keeps context in memory, which blocks horizontal scaling without sticky sessions. In stateless mode every request is self-contained, so any instance serves any request.

MCP server authentication: OAuth 2.1 is not optional

The Model Context Protocol MCP specification models a protected server as an OAuth 2.1 resource server. Your server does not authenticate users. It validates tokens issued by an authorization server, and MCP clients obtain those tokens on the user's behalf.

That separation matters. You should not be writing login flows or minting session cookies inside an MCP server. You should be validating a JWT and reading claims.

Surveys of public servers find a majority still rely on static API keys, while only a small single-digit percentage implement OAuth. Static keys are the shared-service-account problem in pure form: one string, no user identity, no expiry, no selective revocation.

MCP server authentication OAuth 2.1 token flow diagram with audience validation
OAuth 2.1 token flow for MCP server authentication, with audience validation on every request.

The four things to get right

PKCE is mandatory. OAuth 2.1 requires Proof Key for Code Exchange with S256 on every authorization code flow. This stops an intercepted code from being redeemed by an attacker.

Audience binding is mandatory. MCP clients must send a resource parameter (RFC 8707) when requesting a token, binding it to your server's canonical URI. Reject any token whose aud claim does not match. Without this, a token minted for one server can be replayed against another, the attack the 2025-06-18 spec revision added resource indicators to prevent.

Validate locally, cache the keys. Verify the JWT signature and expiry in-process against a cached JWKS document, with a short TTL of around five minutes. Reach for introspection only when you need real-time revocation.

Keep tokens short-lived. Under an hour normally, under fifteen minutes for anything that writes or spends money. Agent sessions routinely outlive the token lifetimes OAuth designers had in mind.

The token passthrough trap

This anti-pattern is explicitly prohibited by the specification.

Token passthrough is forwarding the client's access token, unchanged, to a downstream API. The token was issued for your server, not the downstream service, so forwarding it defeats audience validation, bypasses downstream rate limiting, and destroys your audit trail.

The correct pattern is boring:

  1. Validate the incoming token, including its audience claim.
  2. Map the authenticated subject to a downstream-scoped credential, or perform an RFC 8693 token exchange.
  3. Call the downstream API with that credential.
  4. Log both identities, the calling user and the downstream principal.

MCP server authentication and authorization are separate jobs

Knowing who is calling tells you nothing about what they may do. Access control here has a shape ordinary APIs do not, because the caller is an autonomous agent that chose the tool itself.

Scope permissions at the tool level, not the server level. Each tool declares the scope it requires, and your dispatch layer checks it before the handler runs. Do that check in middleware, not scattered through tool implementations where a new tool will forget it.

Apply least privilege to downstream credentials too. If you expose a database query tool, its role should be read-only against specific tables. Do not rely on input validation as the only thing between a prompt injection and a DROP TABLE. Assume the model can be talked into calling any tool with any arguments, and make that blast radius survivable.

Destructive operations deserve a human in the loop. The protocol lets you annotate tools as destructive so clients can prompt for confirmation. Mark them honestly.

Rate limiting and abuse control

Agents behave unlike humans and unlike conventional API clients. A retry loop can produce hundreds of calls in seconds, and a model that misreads a result will often retry with slightly different arguments rather than stopping.

Rate limit on several dimensions at once:

  • Per authenticated user, so one person cannot exhaust capacity for everyone.
  • Per client or agent instance, so one misbehaving integration is contained.
  • Per tool, because a cheap lookup and an expensive report should not share a budget.
  • Globally, as a circuit breaker protecting downstream dependencies.

Token bucket is the right default, since it tolerates bursty agent traffic while capping the sustained average. Return proper 429 responses with a Retry-After header.

Push this to the gateway tier rather than application code. Streamable HTTP lets gateways route and throttle without parsing request bodies, so Kong, Envoy, or Cloudflare can enforce limits before a request reaches your process.

Treat cost as a resource as well. If a tool triggers an LLM call or a paid API, meter spend per user alongside request counts.

Deployment topology: the gateway pattern

Teams running one server implement auth in that server. Teams running four find that per-server auth becomes a maintenance burden, because each new server means another client registration, JWKS cache, and scope set.

The gateway pattern fixes this. One gateway terminates authentication, enforces limits, emits audit logs, and forwards attributed requests to servers over the internal network. The servers get smaller and dumber, which is the point.

MCP gateway pattern topology diagram for production deployment
The gateway pattern: terminate authentication, rate limiting, and audit logging once instead of per server.

If you adopt this, the internal network must be a real trust boundary. Servers trusting a gateway-supplied identity header are trivially compromised if anything else reaches them directly, so use mutual TLS, internal-only binding, or both.

A few other specifics matter for any mcp production deployment. Containerize and stay stateless, scaling on concurrent requests rather than CPU, since these workloads are I/O bound. Make health checks real, because an endpoint returning 200 unconditionally keeps a broken server in rotation. Set aggressive timeouts, around ten to fifteen seconds, with an explicit error the model can reason about. Version your tools, since renaming one silently breaks every agent whose prompt referenced the old shape.

Observability for a non-deterministic caller

Standard API observability assumes a deterministic client. Your logs need to answer a question conventional logs never had to: why did the agent decide to call this?

Log, per invocation: the authenticated user, the agent identity, the tool name, redacted arguments, latency, outcome, and downstream principal. Keep a correlation ID spanning the session so you can reconstruct sequences rather than isolated events.

Two metrics matter that normal APIs ignore. Tool error rate by tool usually means a description is misleading the model rather than broken code. Repeat-call rate, the same tool called with near-identical arguments in one session, signals an agent stuck in a loop and predicts both cost overruns and a confusing tool contract.

A pre-launch checklist

  • Streamable HTTP transport, stateless unless you have a specific reason otherwise
  • MCP server authentication via OAuth 2.1 with PKCE, no static API keys
  • Audience validation on every request
  • JWKS cached with a short TTL, tokens under one hour
  • No token passthrough, downstream calls use separately scoped credentials
  • Scope checks in shared middleware, not per-handler
  • Destructive tools annotated honestly
  • Rate limits per user, per client, per tool, and globally
  • Cost metering for tools that trigger paid calls
  • Structured audit logs with session correlation IDs
  • Real health checks, explicit timeouts, and a tool versioning policy

If you are choosing which servers to run rather than building your own, our roundup of the best MCP servers for Claude and Cursor covers what is worth adopting, and MCP vs REST APIs covers when the protocol is the right choice at all.

The short version

Production MCP is mostly production API engineering with two additions: the caller is non-deterministic and manipulable, and the identity model has an extra hop because a user delegates authority to an agent.

Validate tokens instead of trusting them. Scope credentials to what each tool needs. Rate limit for looping callers rather than patient human ones. Log enough to reconstruct why a call happened. The rest of the checklist is detail.

References

MCP specification: Authorization (2025-06-18)

MCP Security Best Practices

Auth0: MCP spec updates, all about auth

MCP blog: Exploring the future of MCP transports

Stack Overflow: Authentication and authorization in MCP

Frequently asked questions

Does the MCP specification require OAuth for every server?

No. Authorization is optional in the specification, and stdio servers running locally do not need it at all. But any MCP server reachable over HTTP from the internet should implement OAuth 2.1 with PKCE. The spec models a protected server as an OAuth 2.1 resource server, and static API keys give you no user identity, no expiry, and no selective revocation.

What is token passthrough and why is it prohibited?

Token passthrough is when an MCP server forwards the client's access token unchanged to a downstream API. The specification explicitly forbids it because the token was issued for your server, not the downstream one. Forwarding it defeats audience validation, bypasses the downstream service's rate limiting and consent model, and breaks your audit trail. Validate the incoming token, then call downstream with a separately scoped credential.

Should my MCP server be stateful or stateless?

Default to stateless. Stateless Streamable HTTP lets any instance serve any request, so you can scale horizontally behind a plain load balancer or run on serverless platforms with no session affinity. If you genuinely need session state, store it in Redis rather than process memory and validate the session ID as an opaque token on every request.

How should I rate limit an MCP server?

Limit on four dimensions at once: per authenticated user, per client or agent instance, per tool, and globally as a circuit breaker. Use token bucket, since it tolerates the bursty call patterns agents produce while still capping the sustained average. Enforce it at the gateway tier where possible, and meter cost separately for tools that trigger paid API or LLM calls.

What is the confused deputy problem in MCP?

It affects MCP servers acting as OAuth proxies in front of a third-party provider using a single static client ID. An attacker who can influence the redirect can turn a user's consent into an authorization code that lands on the attacker's server. Mitigate it by requiring explicit consent for every dynamically registered client, validating redirect URIs against a strict allowlist, and avoiding the static-client-ID proxy pattern.

Do I need a gateway in front of my MCP servers?

Not for one server. Once you run three or four, per-server authentication becomes a maintenance burden, because each new server means another client registration, JWKS cache, and scope set. A gateway terminates auth, enforces rate limits, and emits audit logs once, forwarding attributed requests internally. If you do this, treat the internal network as a real trust boundary with mutual TLS or interface binding.

Keep reading

System Design

API Gateway Best Practices: Taming One Failure Domain

An API gateway merges auth, throttling, routing and transformation into one process, making it a correlated failure domain for every service behind it. The failure modes, and what contains them.

Read article
System Design

API Gateway vs Load Balancer vs Reverse Proxy

They all route traffic, but a reverse proxy, a load balancer, and an API gateway solve different problems. Here is how to tell them apart and when to use each.

Read article
System Design

Monolith to Microservices: When and How to Split

A practical guide to monolith-to-microservices migration: when to start, what to extract first with the DICE framework, the strangler fig pattern, and anti-patterns to avoid.

Read article