[BUG] env variable expansion not working in plugin .mcp.json

Resolved 💬 30 comments Opened Oct 12, 2025 by yonijacobi Closed Dec 19, 2025

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When including env variables in .mcp.json file inside plugin root folder instead of reading the value of the variables it reads the var string as is ("${VAR}"), with same file in the project root instead of the plugin folder it not happens

What Should Happen?

It should use the envioronment variables like in regular .mcp.json file, as mentioned in the docs

Error Messages/Logs

Steps to Reproduce

  1. install plugin with mcp servers using the builtin /plugin comand
  2. restart claude and run /mcp to verify the mcp servers from the plugin installed
  3. use tool that requires permissions or other usage of env variables

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.0.14

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

30 Comments

github-actions[bot] · 9 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/6204
  2. https://github.com/anthropics/claude-code/issues/3239
  3. https://github.com/anthropics/claude-code/issues/1254

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yonijacobi · 9 months ago

👎

creatorrr · 9 months ago

I had the same experience. Env var substitution works for the ones defined in local .mcp.json but not when inside a plugin's .mcp.json file

evrimalacan · 9 months ago

I got very excited about the plugins and quickly created a marketplace with our company's favorite MCPs hoping this will give us an easy way to share MCPs, only to notice the same problem... Each server in the plugin's .mcp.json is throwing authentication errors 😭

By the way, this issue seems to affect hooks as well: https://github.com/anthropics/claude-code/issues/9447

joelclimbsthings · 9 months ago

Having the same issue 🤚🏻

vmandela · 8 months ago

Have the same issue. ${PWD} is passed literally to the mcp invocation without environment variable expansion.

~~~
{
"mcpServers": {
"serena": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/oraios/serena@v0.1.4",
"serena",
"start-mcp-server",
"--context",
"ide-assistant",
"--log-level",
"DEBUG",
"--project",
"${PWD}"
]
}
}
}
~~~

hongwei0417 · 8 months ago

Same issues from notion mcp env variable

"notionApi": {
	"command": "npx",
	"args": ["-y", "@notionhq/notion-mcp-server"],
	"env": {
		"NOTION_TOKEN": "${NOTION_TOKEN}"
	}
}
theagenticguy · 8 months ago

Also have the same issue:

{
  "mcpServers": {
    "context7": {
      "type": "http",
      "url": "https://mcp.context7.com/mcp",
      "headers": {
        "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}"
      }
    },
    "deepwiki": {
      "type": "http",
      "url": "https://mcp.deepwiki.com/mcp"
    },
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@brave/brave-search-mcp-server"],
      "env": {
        "BRAVE_API_KEY": "${BRAVE_API_KEY}"
      }
    },
    "tavily": {
      "type": "http",
      "url": "https://mcp.tavily.com/mcp/?tavilyApiKey=${TAVILY_API_KEY}"
    },
    "exa": {
      "type": "http",
      "url": "https://mcp.exa.ai/mcp/?exaApiKey=${EXA_API_KEY}"
    }
  }
}

2.0.24 (Claude Code)

Manouchehri · 8 months ago

Likewise, glad to know it's not something I was doing wrong on my end.

dvic · 8 months ago

I can confirm this bug as well.

theagenticguy · 8 months ago

Update: environment variables seem to get expanded correctly in the "env" key-value pairs, because Brave API is working. Everywhere else, they are not expanded:

claude --version
>>> 2.0.32 (Claude Code)
● plugin:ai-engineering:context7 - resolve-library-id (MCP)(libraryName: "amazon bedrock agentcore")
  ⎿  Unauthorized. Please check your API key. The API key you provided (possibly incorrect) is: ${CONTEXT7_API_KEY}. API keys should start with 'ctx7sk'

● Context7 Results:
  ❌ Failed - Both Context7 instances (essentials and ai-engineering) require API key configuration. The API key should start with 'ctx7sk' but is currently set to a placeholder value ${CONTEXT7_API_KEY}.

  Overall Web Search Tool Status:
  - Brave Search: ✅ Working - fully configured and functional
  - Tavily: ❌ Needs API key (401 Unauthorized)
  - Exa: ❌ Configuration issue (400 Bad Request)
  - Context7: ❌ Needs API key (should start with 'ctx7sk')
smar-sean-sekora · 8 months ago

same issue...
it works when adding the MCP configuration to ~/.claude.json, but for the plugin's .mcp.json I need to hard code the value for it to work

neotheprogramist · 8 months ago

I confirm this bug as well.
I cannot keep my github token safe in envs and setup Github mcp server in my claude code plugin.

{
  "mcpServers": {
    "memory": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "env": {}
    },
    "git": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-server-git"],
      "env": {}
    },
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp",
      "headers": {
        "Authorization": "Bearer ${GITHUB_PAT}"
      }
    }
  }
}

2.0.36 (Claude Code)

evrimalacan · 8 months ago

This issue is killing the whole purpose of plugins. Sad to see it isn't getting any attention.
I don't get why anybody would develop plugins if it requires exposing secrets

smar-sean-sekora · 8 months ago

It would be great if the plugins had a similar feature as Roo Code Marketplace and define values to ask the person installing the plugin to supply

caodegao-jk · 8 months ago

Can anyone tell me in which version this issue will be fixed?

no1187 · 8 months ago

I'm literally so annoyed

I found the issue. The .mcp.json file is using the ${VARIABLE} placeholder format, but according to the Anthropic standard mentioned in the CLAUDE.md, the env object should be empty (env: {}) to
automatically load from the .env file.

evrimalacan · 8 months ago
I'm literally so annoyed I found the issue. The .mcp.json file is using the ${VARIABLE} placeholder format, but according to the Anthropic standard mentioned in the CLAUDE.md, the env object should be empty (env: {}) to automatically load from the .env file.

not sure I follow

no1187 · 8 months ago
> I'm literally so annoyed > I found the issue. The .mcp.json file is using the ${VARIABLE} placeholder format, but according to the Anthropic standard mentioned in the CLAUDE.md, the env object should be empty (env: {}) to automatically load from the .env file. not sure I follow

Sorry that's the error message I'm getting from Claude Code , it's running in loops

theagenticguy · 8 months ago
> > I'm literally so annoyed > > I found the issue. The .mcp.json file is using the ${VARIABLE} placeholder format, but according to the Anthropic standard mentioned in the CLAUDE.md, the env object should be empty (env: {}) to automatically load from the .env file. > > > not sure I follow Sorry that's the error message I'm getting from Claude Code , it's running in loops

Claude Code wouldn't be able to fix it, unless it was able to inspect the TypeScript code of Claude Code itself. It's not an LLM problem, it's a problem with parsing ${VARIABLES} in places other than the env: key-object pair

b0dea · 8 months ago

Is there any update on this one? My plugins keep not working now because 'env' vars passed through .claude/settings.json are not being correctly fetched now. As a consequence some MCPs do not work at all and some restart themselves resulting in 2 instances (eg Serena). Thanks

KylinWu · 7 months ago

Same issue.

b0dea · 7 months ago
Same issue.

Created a fresh issue myself, maybe grabs devs attention... - https://github.com/anthropics/claude-code/issues/11927

Also, maybe there is hope to get this fixed soon, just saw here this comment: https://github.com/anthropics/claude-code/issues/11960#issuecomment-3554770561

shukieshah · 7 months ago

Surprised this issue is still not fixed. Spent an hour trying to debug this before stumbling upon this open issue.

shukieshah · 7 months ago

SOLVED: Actually NVM, all I needed to do was update Claude Code. Seems like they fixed this in the latest release! :)

Surprised this issue is still not fixed. Spent an hour trying to debug this before stumbling upon this open issue.
ffriedl89 · 7 months ago

@shukieshah Could you please share your version that you are using and how your .mcp.json file looks like inside your plugin?

I still have the same issue and am using version 2.0.71 of claude code.

TyceHerrman · 6 months ago

I don't think this is solved either. Encountering the issue on 2.0.73.

shukieshah · 6 months ago

@ffriedl89 I'm currently using Claude 2.0.72 (although latest version seems to be 2.0.75). Here is what my MCP configuration looks like inside my plugin.json file:

{
  ...
  "mcpServers": {
    "asymptote-security-mcp": {
      "command": "npx",
      "args": ["-y", "@asymptote-labs/asymptote-security-mcp"],
      "env": {
        "ASYMPTOTE_API_KEY": "${ASYMPTOTE_API_KEY}"
      }
    }
  },
  "hooks": {
  ...
  }
}

Env var evaluation works fine on my end. Have distributed this plugin to others and it works fine for them as well.

Have you tried providing your MCP server config inline within your plugin.json as per https://code.claude.com/docs/en/mcp#plugin-provided-mcp-servers?

theagenticguy · 6 months ago
@ffriedl89 I'm currently using Claude 2.0.72 (although latest version seems to be 2.0.75). Here is what my MCP configuration looks like inside my plugin.json file: `` { ... "mcpServers": { "asymptote-security-mcp": { "command": "npx", "args": ["-y", "@asymptote-labs/asymptote-security-mcp"], "env": { "ASYMPTOTE_API_KEY": "${ASYMPTOTE_API_KEY}" } } }, "hooks": { ... } } ` Env var evaluation works fine on my end. Have distributed this plugin to others and it works fine for them as well. Have you tried providing your MCP server config inline within your plugin.json` as per https://code.claude.com/docs/en/mcp#plugin-provided-mcp-servers?

yep, "env" gets replaced correctly. However some http MCP servers expect a key in the URL param. not sure if those are expanding yet.

github-actions[bot] · 6 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.