MCP Authentication Guide
Learn how to implement authentication in MCP servers — JWT tokens, API keys, OAuth 2.1, and how mcp-framework and the official SDK handle auth.
title: "MCP Authentication Guide" description: "Learn how to implement authentication in MCP servers — JWT tokens, API keys, OAuth 2.1, and how mcp-framework and the official SDK handle auth." order: 5 keywords:
- MCP authentication
- MCP auth
- MCP JWT
- MCP API key
- MCP OAuth
- MCP OAuth 2.1
- MCP security
- MCP server authentication
- model context protocol auth date: "2026-04-01"
MCP servers that use HTTP transports need authentication to verify client identity. The protocol supports API keys (simplest), JWT tokens (stateless verification), and OAuth 2.1 (the specification-recommended standard for third-party access). The stdio transport typically relies on OS-level process isolation instead of explicit authentication. Both mcp-framework and the official @modelcontextprotocol/sdk provide mechanisms for implementing auth.
Why Authentication Matters for MCP
MCP authentication is the process of verifying the identity of clients connecting to an MCP server. For HTTP-based transports (SSE and Streamable HTTP), authentication ensures that only authorized clients can discover and invoke tools, read resources, and access prompt templates. The MCP specification recommends OAuth 2.1 as the standard authentication mechanism for HTTP transports.
When an MCP server runs over HTTP, it is exposed to the network — and potentially the internet. Without authentication, anyone who can reach the server's endpoint can invoke its tools, including tools that modify data, access sensitive information, or trigger external actions.
Authentication is critical for:
- Preventing unauthorized access to server capabilities
- Identifying clients for audit logging and access control
- Enforcing per-client permissions on which tools and resources are available
- Rate limiting and abuse prevention
- Multi-tenant deployments where different clients have different access levels
If your MCP server only uses the stdio transport, authentication is typically unnecessary. The host spawns the server as a local child process, and the OS ensures that only the host can communicate with it through stdin/stdout. Environment variables can pass secrets (like API keys for external services) to the server process without network exposure.
Authentication Methods
API Key Authentication
API key authentication is the simplest method. The client includes a pre-shared key in the request headers, and the server validates it before processing any requests.
| Aspect | API Key | JWT | OAuth 2.1 |
|---|---|---|---|
| Complexity | Low | Medium | High |
| Stateless | No (server must store keys) | Yes (self-contained token) | Depends on grant type |
| Expiration | Manual rotation | Built-in expiry (exp claim) | Token expiry with refresh |
| Scope/permissions | All or nothing (by default) | Claims-based | Scope-based |
| Best for | Internal tools, single-user | Service-to-service | Third-party clients, multi-user |
| MCP spec support | Custom implementation | Custom implementation | Specification recommended |
Implementing API Key Auth
With mcp-framework, you can add API key authentication middleware to your HTTP transport:
import { MCPServer } from "mcp-framework";
const server = new MCPServer({
transport: {
type: "httpStream",
options: {
port: 3000,
endpoint: "/mcp",
middleware: (req, res, next) => {
const apiKey = req.headers["x-api-key"];
if (apiKey !== process.env.MCP_API_KEY) {
res.status(401).json({ error: "Unauthorized" });
return;
}
next();
},
},
},
});
- Store API keys in environment variables, never in code
- Use long, randomly generated keys (at least 32 characters)
- Implement key rotation without downtime
- Log key usage for auditing
- Consider per-client keys for multi-client servers
- Always transmit keys over HTTPS
JWT Authentication
JSON Web Tokens (JWT) provide stateless authentication with built-in expiration and claims. The client obtains a JWT from an identity provider and includes it in the Authorization header of each request.
How JWT Works with MCP
- Client authenticates with an identity provider and receives a JWT
- Client includes the JWT in the
Authorization: Bearer <token>header - Server validates the JWT signature, expiration, and claims
- Server extracts client identity and permissions from the token claims
- Server processes the MCP request based on the client's permissions
import jwt from "jsonwebtoken";
function validateJWT(req, res, next) {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({ error: "No token provided" });
}
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
req.clientId = payload.sub;
req.scopes = payload.scopes;
next();
} catch (err) {
return res.status(401).json({ error: "Invalid token" });
}
}
JWT Claims for MCP
When using JWT with MCP servers, consider including these claims:
| Claim | Purpose | Example |
|---|---|---|
| sub | Client identifier | client-123 |
| scopes | Allowed MCP operations | ["tools:read", "tools:execute"] |
| tools | Allowed tool names | ["query_database", "list_files"] |
| exp | Token expiration | 1714500000 |
| aud | Intended MCP server | my-mcp-server |
OAuth 2.1 Authentication
OAuth 2.1 is the MCP specification's recommended authentication mechanism for HTTP transports. It provides a standardized flow for third-party clients to obtain authorized access to MCP servers.
OAuth 2.1 is the authentication standard recommended by the MCP specification for HTTP-based transports. It enables third-party MCP clients to obtain scoped, time-limited access to MCP servers through a standardized authorization flow. OAuth 2.1 consolidates best practices from OAuth 2.0, including mandatory PKCE, and is designed for modern security requirements.
OAuth 2.1 Flow for MCP
- Discovery — Client discovers the server's OAuth metadata at
/.well-known/oauth-authorization-server - Authorization — Client redirects the user to the authorization endpoint
- PKCE — Client uses Proof Key for Code Exchange (mandatory in OAuth 2.1)
- Token exchange — Client exchanges the authorization code for access and refresh tokens
- Authenticated requests — Client includes the access token in the
Authorizationheader - Token refresh — Client uses the refresh token when the access token expires
Client Auth Server MCP Server
│ │ │
├─ GET /.well-known/oauth ─→│ │
│←─ OAuth metadata ─────────┤ │
│ │ │
├─ Authorization request ──→│ │
│←─ Authorization code ─────┤ (user approves) │
│ │ │
├─ Token exchange ─────────→│ │
│←─ Access + Refresh token ─┤ │
│ │ │
├─ MCP request + Bearer token ───────────────────────→ │
│←─ MCP response ──────────────────────────────────────┤
Use OAuth 2.1 when your MCP server needs to support third-party clients, especially in multi-tenant scenarios where different users have different access levels. For internal or single-user servers, API keys or JWTs are simpler and sufficient.
Per-Tool Authorization
Beyond authenticating the client, MCP servers can implement per-tool authorization — restricting which tools each client is allowed to invoke.
const toolPermissions = {
"read-only-client": ["query_database", "list_files"],
"admin-client": ["query_database", "list_files", "delete_records", "modify_schema"],
};
function authorizeToolCall(clientId, toolName) {
const allowed = toolPermissions[clientId] || [];
return allowed.includes(toolName);
}
Grant each MCP client only the minimum permissions it needs. A client that only reads data should not have access to tools that modify data. Implement per-tool authorization even if you have only one client today — it makes your server ready for multi-client deployment and reduces the blast radius of compromised credentials.
Environment Variable Patterns
For stdio-based servers, authentication to external services is typically handled through environment variables passed by the host:
{
"mcpServers": {
"github-server": {
"command": "node",
"args": ["github-mcp-server/dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx",
"GITHUB_ORG": "my-organization"
}
}
}
}
Never hardcode API keys, tokens, or other credentials in your MCP server source code. Always use environment variables or a secrets manager. For stdio servers, the host passes environment variables at process spawn time. For HTTP servers, use your deployment platform's secrets management (e.g., AWS Secrets Manager, Vault, or environment-specific config).
Security Checklist
Use this checklist when implementing authentication for your MCP server:
- Determine which transport(s) your server uses and their authentication needs
- For HTTP transports, choose an authentication method (API key, JWT, or OAuth 2.1)
- Implement TLS/HTTPS for all HTTP connections
- Validate all tokens and keys on every request
- Implement per-tool authorization for sensitive operations
- Set appropriate token expiration times
- Plan for credential rotation
- Log authentication events for auditing
- Test authentication failure paths
- Document authentication requirements for client developers