Resolve local environment variables in MCP server definitions

When configuring MCP servers, you often pass keys in the form of environment variables to the MCP servers like this:

{
  "mcpServers": {
    "server-name": {
      "command": "npx",
      "args": ["-y", "mcp-server"],
      "env": {
        "API_KEY": "value"
      }
    }
  }
}

I would like the API_KEY value to be a local environment variable’s value. This way I can add this MCP server definition to my team’s Git repo and everyone will be able to easily configure their MCP servers.

Discussed in How to use environment variables in mcp.json

9 Likes

Bumping this. We’re in the same situation, it’s extremely important for our team. We want to share our MCP configuration via git and without this behavior, it’s impossible. We’re considering moving to VScode AI agent for this feature.

3 Likes

This would be the natural evolution given that cursor now supports rules scoped to a given project: these will be committed to version control but the “secret” needs to stay out.
Using an environment variable would be the standard strategy there.
The second option would be to let the caller specify a path such as ~/.mysecret. Not as elegant, but works too.

2 Likes

Thanks for the idea, have flagged to the team to see whats possible here!

3 Likes

The approach we recommend is to use a wrapper script that loads the .env variables before calling the npx script or whatever your server is. We don’t provide the full .env variables to all servers for security reasons, and there is a very easy workaround

Does VSCode actually do this?

I just tested Copilot agent and they dont put your .env in your servers by default either. Best bet is to use the wrapper script

Actually you can do this

npx dotenv -- npx your-command

thanks for the suggestion @msfeldstein !
Maybe I am somehow doing this wrong, but dotenv does not seem to work on my end

this works just fine but exposes my token in the script:

#!/bin/bash
GITHUB_PERSONAL_ACCESS_TOKEN=MyToken npx -y @modelcontextprotocol/server-github

this hides my token in the env .. but the mcp always fails the auth

#!/bin/bash
npx dotenv -e ~/.env -- npx -y @modelcontextprotocol/server-github

I have tried many permutations of the dotenv command at this point (as well as many emplacements for the .env file) , even though it is possible I am missing something obvious

Hmm try this?

set -a
source ~/.env
set +a

npx -y @modelcontextprotocol/server-github

Hey, saw this problem and built a small tool, mcp-safe-run, to handle exactly this. It lets you use placeholders like file:./secret.txt or keyring:svc:acc in your mcp.json args, keeping secrets out of Git.

I was struggling with it in Roo and Cline, but in there i can use

    "brave-search": {
      "command": "mcp-safe-run",
      "args": [
        "-p",
        "brave_search",
        "--",
        "npx",
        "-y",
        "@modelcontextprotocol/server-brave-search"
      ]
    },

which works, BUT with Cursor the very same command produce

2025-04-23 05:58:08.416 [info] arch: Starting new stdio process with command: mcp-safe-run -p brave_search -- npx -y @modelcontextprotocol/server-brave-search
2025-04-23 05:58:08.416 [error] arch: Client error for command A system error occurred (spawn mcp-safe-run ENOENT)

While in the devcontaiver, where I deal with everything, it is installed and working. I suppose that MCP’s are running in some special container which is prepared for that and i can’t find how can i switch it or tweak

There is the VSCode suggested way to manage this, like ${env:FOO} and it was just adopted by Roo code. It would be great if Cursor used the same syntax

1 Like

As an option, it might be to allow re-use of the dev-container (or host machine) as it allows to do VSCode.

Before the latest changes in VSCode, it was nice to have such a sort of isolation, but now it’s more of a hassle rather than a value. Those, who have security concerns are using workspaces and/or devcontainers anyway, and ironically, that group of users has lthe east options to manage MCP.json file and have to treat it as secret

I’ll update the docs on the repo to state that Cursor doesn’t actually work with the mcp-safe-run.

Windsurf, Roo, and Cline works perfectly fine with keychain, file, and profile placeholders

1 Like

I ended up publishing the “wrap it with a script” idea as a simple NPM package so that at least for simple stdio use cases I can define any env vars in a file and then reference them by name in the cursor MCP config by prefixing the command with npx envmcp: envmcp - npm

1 Like

@griffithsbs ty man! Using it works amazingly, hope the docs will be updated soon for others.

1 Like