Skip to content

Client setup

Cursor MCP env variables: keep the API key out of mcp.json

Use ${env:NAME} in Cursor's mcp.json to read an MCP server's API key from the environment, and fix the header that arrives as a literal string.

Published

This article was drafted with AI assistance from the sources listed below and edited and published by Teneo Labs. Disclosure: this site is run by Teneo Labs, the company behind Live Web Data API, which this article mentions.

Before you blame the server
  • The header uses ${env:NAME}, with the env: prefix.
  • The variable is set in the environment Cursor starts from.
  • Cursor was restarted after the variable was set.
  • mcp.json is valid JSON, with no trailing comma.
  • The server shows as enabled with its tools in Cursor's MCP settings.

Cursor reads MCP servers from mcp.json: ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one. A remote server needs a URL and usually an Authorization header, and the header is where keys leak: the file is easy to commit and easy to paste into a chat. Cursor can read the key from the environment instead.

Checked against Cursor's MCP docs as of this post's date.

The syntax

Cursor resolves ${env:NAME} in mcp.json, including in url and headers:

{
  "mcpServers": {
    "live-web-data": {
      "url": "https://fetchmcp.net/mcp",
      "headers": { "Authorization": "Bearer ${env:LIVE_WEB_DATA_API_KEY}" }
    }
  }
}

The env: prefix matters. It is the same variable syntax VS Code uses in its config files. Claude Code's .mcp.json uses ${NAME} without a prefix, so a snippet copied between the two clients silently sends the literal text.

For a local server started over stdio, the env object in the server entry sets variables for that process, and the same ${env:NAME} reference works inside it.

Why the variable is empty

The usual failure is not the syntax. It is where Cursor was started. Environment variables are inherited by programs a shell starts, so:

  • export LIVE_WEB_DATA_API_KEY=... in a terminal reaches programs started from that terminal,
  • a Cursor window opened from the macOS dock, the Windows start menu or a desktop launcher did not start from that shell and does not have it.

The server then receives an empty or literal header and answers 401, and Cursor shows the server with an error. Fixes, from quickest to most durable:

  1. Start Cursor from the shell that has the variable, for example with the cursor . command if you installed it.
  2. Set it for your user account. On Windows, add it under your user's environment variables and restart Cursor. On macOS and Linux, set it where your desktop session reads it, then log out and in, or start Cursor from a shell.
  3. Restart Cursor fully after any change. A reload of the window may not pick up a new environment.

Check that it worked

Open the MCP section of Cursor's settings. The server should show as enabled with its tools listed. If it shows an error, test the same URL and header outside Cursor with the MCP Inspector CLI: if Inspector works with your shell's variable, Cursor's environment is the gap. The full per-client setup is in the setup guide, and key rotation is in the authentication guide.

Try it

Live Web Data API, made by Teneo Labs, takes its key as a bearer header, so the snippet above works as written once LIVE_WEB_DATA_API_KEY is set. The current config is in the MCP docs.

Frequently asked questions

What is the syntax for environment variables in Cursor's mcp.json?

${env:NAME}, for example "Bearer ${env:LIVE_WEB_DATA_API_KEY}" in a headers value. The ${NAME} form without env: is Claude Code's syntax and is not the same.

Why does Cursor not see a variable I exported in my terminal?

An export applies to that terminal session and the programs it starts. A Cursor window opened from the dock or start menu never saw it. Start Cursor from that terminal, or set the variable for your user account and restart Cursor.

Sources

  1. Model Context Protocol (Cursor docs) (Documentation)
  2. Variables reference (VS Code docs) (Documentation)