Authentication is optional in the MCP specification, but a remote HTTP server that holds anyone's data should use it. The specification points HTTP servers to OAuth 2.1 based authorization. Local stdio servers should not follow that flow and should read credentials from the environment instead. Skipping it entirely is only reasonable for a harmless, local, read-only tool.
Definitions
Transport. How the client and server talk. MCP defines stdio (the client launches the server as a child process) and Streamable HTTP (a network endpoint).
Authorization. Proof that the caller may use this server and what it may do. In the HTTP flow the MCP server acts as an OAuth resource server, the MCP client is an OAuth client, and a separate authorization server issues tokens.
Audience. The server a token was issued for. The server must check that tokens were issued to it.
Decision table
| Situation | What the spec says | Practical choice |
|---|---|---|
| Local stdio server | Should not use the HTTP authorization flow; get credentials from the environment | Keep secrets in environment variables, not in config files in git |
| Remote HTTP server with user data | Should conform to the authorization specification | OAuth with short-lived tokens, exact redirect URIs, PKCE |
| Remote HTTP server, public data only | Authorization is optional | Still rate limit and log |
| Another transport | Must follow established security practices for that protocol | Pick the practices before you pick the transport |
What a compliant HTTP server does
- It returns HTTP 401 when a request has no valid token, and points to its protected resource metadata.
- It publishes that metadata so a client can find the authorization server. RFC 9728 defines this document.
- It validates every token: issued by the expected authorization server, not expired, and issued for this server as the audience.
- It checks the token on every request. The specification says authorization must be included in each HTTP request, even inside one session.
- It never accepts tokens meant for other services and never passes the client's token on to an upstream API. If it calls an upstream API, it uses a separate token for that API.
- It asks for the least scope needed and returns HTTP 403 with an insufficient scope challenge when more is required.
Tokens must not be placed in the query string. They go in the Authorization header.
Common mistakes
- Treating the session ID as proof of identity. The specification says servers must not use sessions for authentication.
- Binding one broad token to every tool.
- Storing a long-lived key in a shared config file that gets committed.
- Assuming that because a server is only on an internal network, no token is needed.
Quick check
Can I use an API key for MCP instead of OAuth?
The specification describes OAuth based authorization for HTTP. Some deployments still use keys. If you do, treat the key like any secret: scope it, rotate it, keep it out of git and check how the server logs it.
Why does the server need to check the token audience?
Without the check, a token issued for a different service could be replayed against this one. The specification requires servers to accept only tokens issued specifically for them.
Is stdio automatically safe?
No. It avoids network exposure, but the server is local code. Review the launch command and run it with limited access.
Where Safeguard fits
Safeguard scans the dependencies behind an MCP server and applies policies and gates to changes that touch agent configuration. Start with a free scan at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.