The Authentication Challenge
An MCP server that connects to GitHub, Slack, or a cloud provider needs credentials. Those credentials must be stored securely, transmitted safely, and refreshed when they expire. Getting this right is critical because a compromised credential gives attackers access to whatever service the MCP server connects to.
The MCP protocol doesn't prescribe a specific authentication mechanism. This flexibility lets server developers choose the approach that best fits their use case, but it means there's no standardized way to handle authentication across servers.
API Key Pattern
The simplest authentication pattern is passing an API key to the MCP server through environment variables. The server reads the key at startup and includes it in requests to the external service. This works well for services with stable, long-lived API keys.
The advantage is simplicity. Set an environment variable, start the server, and authentication works. The disadvantage is that API keys stored in environment variables can be exposed through process listings, log files, or configuration file leaks. Use environment variable files (like .env) with appropriate file permissions rather than setting variables directly in the shell.
OAuth Flow Pattern
Services that use OAuth (Google, Microsoft, Slack, GitHub) require a more complex authentication flow. The user needs to authorize the MCP server to access their account, which involves redirecting to the service's authorization page, granting permission, and receiving an access token.
Some MCP servers handle this by launching a local web server during the authorization flow. The user opens a URL, grants permission, and the redirect sends the token back to the local server. This flow is user-friendly but requires the MCP server to include HTTP server capabilities for the auth step.
Others use a separate authorization tool that the user runs once to obtain tokens, which are then stored locally and used by the MCP server. This separates the auth concern from the MCP server itself but adds an extra setup step.
Token Refresh
OAuth access tokens expire. When they do, the MCP server needs to use a refresh token to obtain a new access token without requiring the user to re-authorize. Implementing token refresh correctly is important for long-running MCP servers that need uninterrupted access to external services.
Common issues include: not handling token refresh at all (the server stops working when the token expires), refreshing tokens but not persisting the new tokens (requiring re-authorization after server restart), and race conditions when multiple requests trigger simultaneous token refreshes.
Security Best Practices
Never hardcode credentials in MCP server source code. This seems obvious, but it happens frequently enough to be worth stating. Credentials in source code can be committed to version control, shared through code reviews, and exposed through repository access.
Use the most restrictive scopes possible when configuring OAuth access. If the MCP server only needs to read emails, don't request permission to send emails. Restricting scopes limits the damage if the server is compromised or if a prompt injection attack tries to misuse the server's capabilities.
Store tokens in secure locations. Keychain integration (macOS), credential manager (Windows), or encrypted files with restricted permissions (Linux) are all better than plain text files. Some MCP servers support these secure storage backends; check the documentation before falling back to less secure alternatives.
Related Reading
- The Security Implications of Connecting LLMs to External Tools
- Data Privacy When Using MCP Servers
- How to Evaluate an MCP Server Before Installing It
Browse MCP servers on Skillful.sh. Search for authenticated integrations.