Client Authentication with MCP Servers
This guide explains how to authenticate your applications when connecting to MCP servers that you've deployed through MCP-Cloud.ai.
Authentication Methods
MCP servers support several authentication methods:
- API Key Authentication - The primary method for server-to-server and application-to-server communication
- JWT Token Authentication - Secure, claims-based authentication with flexible token management
- Session-Based Authentication - For web applications and interactive use cases
- OAuth 2.0 - For integrations with third-party services and applications
API Key Authentication
API keys are the most common way to authenticate with your MCP server. When you deploy an MCP server, you'll receive an API key that you can use to make authenticated requests.
Using API Keys in Requests
To authenticate with an API key, include it in the Authorization
header of your HTTP requests:
Authorization: Bearer mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Example using cURL:
curl -X POST \
https://your-mcp-server.mcp-cloud.ai/v1/chat/completions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-d '{
"model": "claude-3-5-sonnet",
"messages": [{"role": "user", "content": "Hello, how are you?"}]
}'
API Key Security Best Practices
When working with API keys:
Store Securely: Never hardcode API keys in your source code
// WRONG const apiKey = "mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // RIGHT const apiKey = process.env.MCP_API_KEY;
Use Environment Variables: Store API keys in environment variables
# Set environment variable export MCP_API_KEY=mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Use in application node app.js
Restrict Access: Limit API key access to only the services that need it
Use Secrets Management: For production, use a secrets manager like:
- AWS Secrets Manager
- Google Secret Manager
- HashiCorp Vault
- Azure Key Vault
Rotate Keys Regularly: Refresh your API keys periodically
Set Proper Permissions: Use the minimum required permissions for each key
JWT Token Authentication
JWT (JSON Web Token) tokens provide a secure, claims-based authentication mechanism for your MCP servers. These tokens contain digitally signed information about the sender and can include additional metadata like expiration times and user roles.
Setting Up JWT Authentication
To enable JWT authentication for an MCP server:
- Navigate to the Servers list in your dashboard
- Click the Settings icon (⚙️) for the server you want to secure
- Select the JWT Auth tab
- Click Generate Token to create a new JWT token
- Provide a description for your token (e.g., "Production API Token")
- Choose whether the token should expire or be indefinite
- Click Create Token
The token will now be associated with your server, and JWT authentication will be enabled.
Viewing and Managing Your JWT Tokens
To view the details of a JWT token associated with your server:
- Navigate to the Servers list in your dashboard
- Expand the Advanced section for your server
- If the JWT Auth status shows "Enabled", click View JWT Token
- The token details will be displayed, including token status, creation date, and usage example
Using JWT Tokens in Client Applications
To authenticate API requests using your JWT token, add an Authorization header to your HTTP requests:
Authorization: Bearer YOUR_JWT_TOKEN
Example with cURL:
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" https://your-server-url.run.app/sse
Example with JavaScript:
fetch('https://your-server-url.run.app/sse', {
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
})
JWT Token Security Practices
- Keep tokens secure: Never share JWT tokens or include them in client-side code
- Use time-limited tokens: For production environments, use tokens with an expiration time
- Monitor token usage: Check the "Last Used" timestamp to identify potentially compromised tokens
- Revoke tokens when not needed: Invalidate tokens that are no longer in use
Session-Based Authentication
For web applications where users interact with your MCP server, you can use session-based authentication.
Implementing Session Authentication
Create an authentication endpoint in your application that exchanges user credentials for a session token
Request a session token from your MCP server:
// Server-side code async function getMCPServerSession(userId) { const response = await fetch('https://your-mcp-server.mcp-cloud.ai/v1/auth/session', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' }, body: JSON.stringify({ user_id: userId, expires_in: 3600 // 1 hour session }) }); const data = await response.json(); return data.session_token; }
Use the session token in client requests:
// Client-side code async function callMCPServerWithSession(sessionToken, prompt) { const response = await fetch('https://your-mcp-server.mcp-cloud.ai/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + sessionToken }, body: JSON.stringify({ model: "claude-3-5-sonnet", messages: [{ role: "user", content: prompt }] }) }); return response.json(); }
Session Security Considerations
- Set appropriate expiration times for session tokens
- Implement token refresh mechanisms for longer sessions
- Store session tokens securely (HTTP-only cookies for web apps)
- Implement CSRF protection for web applications
OAuth 2.0 Integration
For more complex applications, MCP servers support OAuth 2.0 authentication. This is useful when:
- Integrating with third-party services
- Building applications with multiple users
- Implementing fine-grained permissions
OAuth Flow for MCP Servers
Register your application with the MCP server to get client credentials
Implement the OAuth flow in your application:
// Step 1: Redirect user to authorization endpoint function redirectToAuth() { const authUrl = new URL('https://your-mcp-server.mcp-cloud.ai/v1/oauth/authorize'); authUrl.searchParams.append('client_id', YOUR_CLIENT_ID); authUrl.searchParams.append('redirect_uri', YOUR_REDIRECT_URI); authUrl.searchParams.append('response_type', 'code'); authUrl.searchParams.append('scope', 'chat.completions chat.contexts'); window.location.href = authUrl.toString(); } // Step 2: Exchange authorization code for access token async function exchangeCodeForToken(code) { const response = await fetch('https://your-mcp-server.mcp-cloud.ai/v1/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: YOUR_CLIENT_ID, client_secret: YOUR_CLIENT_SECRET, code: code, grant_type: 'authorization_code', redirect_uri: YOUR_REDIRECT_URI }) }); const data = await response.json(); return { accessToken: data.access_token, refreshToken: data.refresh_token, expiresIn: data.expires_in }; }
Use the access token for API requests:
async function callMCPServerWithOAuth(accessToken, prompt) { const response = await fetch('https://your-mcp-server.mcp-cloud.ai/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` }, body: JSON.stringify({ model: "claude-3-5-sonnet", messages: [{ role: "user", content: prompt }] }) }); return response.json(); }
Refresh Tokens
For long-lived applications, implement token refresh:
async function refreshAccessToken(refreshToken) {
const response = await fetch('https://your-mcp-server.mcp-cloud.ai/v1/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: YOUR_CLIENT_ID,
client_secret: YOUR_CLIENT_SECRET,
refresh_token: refreshToken,
grant_type: 'refresh_token'
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || refreshToken, // Some servers don't issue new refresh tokens
expiresIn: data.expires_in
};
}
Rate Limiting and Usage Tiers
MCP servers implement rate limiting based on your authentication credentials:
Tier | Rate Limit | Total Requests Per Day |
---|---|---|
Free | 10 req/min | 1,000 |
Standard | 60 req/min | 10,000 |
Professional | 300 req/min | 100,000 |
Enterprise | Custom | Custom |
If you exceed these limits, you'll receive a 429 Too Many Requests
response with a Retry-After
header indicating when you can resume requests.
Troubleshooting Authentication Issues
Common Error Codes
Status Code | Meaning | Possible Solution |
---|---|---|
401 Unauthorized | Invalid API key or JWT token | Check your credential format and value |
403 Forbidden | Valid credentials but insufficient permissions | Request additional permissions for your API key |
429 Too Many Requests | Rate limit exceeded | Implement backoff logic and respect rate limits |
Debugging Authentication Problems
Check Credential Format: Ensure your API key or JWT token is properly formatted
Verify Authorization Header: Make sure you're using the correct format:
Authorization: Bearer YOUR_CREDENTIAL
Check for Whitespace: Trim any accidental whitespace from your credentials
Test with cURL: Try a simple request using cURL to isolate client-side issues:
curl -v https://your-mcp-server.mcp-cloud.ai/v1/models \ -H "Authorization: Bearer YOUR_CREDENTIAL"
Check Server Logs: If you have access, review your MCP server logs for authentication errors
Examples in Different Languages
Python
import requests
def call_mcp_server(api_key, prompt):
url = "https://your-mcp-server.mcp-cloud.ai/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
data = {
"model": "claude-3-5-sonnet",
"messages": [{"role": "user", "content": prompt}]
}
response = requests.post(url, headers=headers, json=data)
response.raise_for_status() # Raise exception for 4xx/5xx errors
return response.json()
# Usage
api_key = "mcp_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Better to use environment variables
result = call_mcp_server(api_key, "What is the capital of France?")
print(result['choices'][0]['message']['content'])
Node.js
const axios = require('axios');
async function callMCPServer(apiKey, prompt) {
try {
const response = await axios.post(
'https://your-mcp-server.mcp-cloud.ai/v1/chat/completions',
{
model: "claude-3-5-sonnet",
messages: [{ role: "user", content: prompt }]
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
}
}
);
return response.data;
} catch (error) {
if (error.response) {
console.error('Error response:', error.response.status, error.response.data);
}
throw error;
}
}
// Usage
const apiKey = process.env.MCP_API_KEY;
callMCPServer(apiKey, "What is the capital of France?")
.then(result => console.log(result.choices[0].message.content))
.catch(error => console.error('Error:', error));
Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class MCPServerClient {
private final String apiKey;
private final String serverUrl;
private final HttpClient httpClient;
public MCPServerClient(String apiKey, String serverUrl) {
this.apiKey = apiKey;
this.serverUrl = serverUrl;
this.httpClient = HttpClient.newHttpClient();
}
public String callCompletion(String prompt) throws Exception {
String requestBody = String.format("""
{
"model": "claude-3-5-sonnet",
"messages": [{"role": "user", "content": "%s"}]
}
""", prompt);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(serverUrl + "/v1/chat/completions"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException("API error: " + response.statusCode() +
" " + response.body());
}
return response.body();
}
public static void main(String[] args) {
try {
String apiKey = System.getenv("MCP_API_KEY");
MCPServerClient client = new MCPServerClient(
apiKey,
"https://your-mcp-server.mcp-cloud.ai"
);
String result = client.callCompletion("What is the capital of France?");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}