How to keep API keys out of .cursor/mcp.json
Reference environment variables with ${env:NAME} in env, headers, url, args or command, or point a local (stdio) server at an envFile. Keep the actual key in your shell profile or a gitignored .env.
Stats from the 2026-10-20 snapshot of public GitHub configs (methodology). Behavior checked against the official docs linked below.
Local (stdio) server
{
"mcpServers": {
"github": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}"
}
}
}
}Remote server with a header
{
"mcpServers": {
"remote": {
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${env:MY_SERVICE_TOKEN}"
}
}
}
}Using an envFile
Local (stdio) servers accept "envFile": "${workspaceFolder}/.env". Remote servers don't support envFile, so use ${env:NAME} for those. Add .env to .gitignore.
What public configs do
7.8% of 1,427 unique public .cursor/mcp.json files contain at least one value that looks like a real credential. For comparison: Gemini CLI settings 3.4%, Codex config.toml 2.1%. The detector is a heuristic and has false positives.
If a key was already committed
Rotate it first. Deleting it from the file leaves it in git history, and public repos are scanned for keys continuously.
FAQ
Does Cursor support ${env:} in mcp.json?
Yes. Cursor resolves ${env:NAME}, ${userHome}, ${workspaceFolder} and a few other variables in command, args, env, url and headers.