Model Context Protocol (MCP) · 18 min read

Security and Authentication in MCP

Apply authentication, authorization, and transport security to MCP deployments.

MCP host, client, and server components connected through the protocol. Source: Wikimedia Commons · MCP developers · MIT License

Threat model the connection

List the assets, principals, trust boundaries, and abuse cases before selecting an authentication method. Consider a malicious client, a compromised server, a stolen token, an untrusted tool description, prompt injection in resource content, replay, tenant confusion, and denial of service. Decide whether the server is local, private network, or internet-facing because the exposure changes the required controls. Security should be tied to concrete actions and data, not treated as a generic checkbox on the transport.

Authenticate both sides

Use a secure transport and verify the server endpoint and client identity appropriate to the deployment. Tokens should be short-lived, scoped to the intended audience, rotated, and stored in a secret manager or protected credential store. Mutual authentication may be appropriate for service-to-service connections. Never place credentials in prompts, tool arguments, resource text, logs, or source control. Validate issuer, audience, expiry, and signature rather than merely checking that a token exists.

Scoped token verification settingspython
AUTH = {
    "issuer": "https://auth.example.com/",
    "audience": "mcp-invoice-server",
    "required_scopes": ["invoice:read"],
    "max_token_age_seconds": 900,
}

def authorize(claims: dict, scope: str) -> bool:
    return (
        claims.get("iss") == AUTH["issuer"]
        and claims.get("aud") == AUTH["audience"]
        and scope in claims.get("scope", "").split()
    )

Authorize every operation

Authorization must happen at the server for every request and should consider the principal, tenant, tool, object, operation, and current state. Separate read, create, update, delete, export, and administrative permissions. Enforce row-level or object-level scope where applicable, and re-check ownership after resolving identifiers. A client may hide a dangerous tool from the model, but that is only a usability control. The server must remain safe if a caller is buggy, malicious, or operating with an old policy.

Secure transport and secrets

Encrypt data in transit and configure certificate validation correctly; avoid disabling verification to make local development work. Keep secrets out of error messages and diagnostic traces, and rotate them without requiring source changes. Use separate credentials for development and production, with the smallest practical lifetime and scope. Review dependency and SDK updates because protocol handlers, HTTP clients, and serialization libraries all sit inside the security boundary. A secure channel protects messages but does not make their contents trustworthy.

Validate hostile content

MCP servers may receive paths, URLs, identifiers, filters, queries, and free text from a model-influenced caller. Apply allowlists, canonicalization, length limits, type checks, output encoding, and parameterized queries. Defend against path traversal, SSRF, injection, deserialization bugs, oversized payloads, and resource exhaustion. Treat resource contents and tool results as untrusted data when they return to the model. Keep policy decisions in application code so malicious text cannot grant itself permissions. Review parser behavior too.

Protect tenants and privacy

For multi-user systems, bind every connection and object lookup to a tenant or user identity that comes from authenticated context, not from model-supplied arguments. Test cross-tenant reads, exports, cache keys, logs, and error messages. Minimize retained prompts and results, define deletion behavior, and redact sensitive fields before observability storage. If a provider or host processes private data, document the data flow and retention assumptions. Privacy failures often happen in debugging systems rather than in the primary database.

Respond to incidents

Prepare controls for revoking credentials, disabling a server or tool, reviewing recent calls, preserving relevant evidence, and notifying affected owners. Alerts should cover authentication failures, authorization denials, unusual tool volume, large exports, new destinations, and repeated validation failures. Practice a kill switch that leaves the host usable in a degraded mode. After an incident, add a regression test and update the threat model. Security is an operating process that must work during pressure, not just a design document.