Skip to content

[BUG] Env var references from .mcp.json don't get expanded #3

@arisgrout

Description

@arisgrout

Describe the bug

The mcp-code-wrapper has a hardcoded behavior where environment variable references in .mcp.json (e.g., ${GITHUB_TOKEN}) are passed as literal strings instead of being expanded from process.env. This breaks integrations that rely on environment variables injected by secret managers like infisical, doppler, or 1password CLI.

Steps to reproduce

  1. Configure .mcp.json with environment variable reference syntax (see MCP Configuration below)
  2. Run with environment variable injected: infisical run --path=/ --tags=cc -- bunx mcp-code-wrapper .
  3. Select the MCP server from the list
  4. Observe authentication failure - the MCP server receives literal "${GITHUB_TOKEN}" instead of the actual token value

Expected behavior

The wrapper should:

  1. Expand ${VAR_NAME} syntax in env configurations using process.env
  2. Support standard secret manager workflows (infisical, doppler, 1password CLI)
  3. Allow keeping credentials out of .mcp.json for security

Actual behavior

The MCP server receives the literal string "${GITHUB_TOKEN}" as the environment variable value, causing authentication failures:

Error: Request failed with status code 401
    at MCPClient.errorHandler (file:.../executor.js:...

Environment

  • OS: Linux (Fedora 43)
  • Node version: 22.x
  • Package version: mcp-code-wrapper@latest
  • Infisical CLI version: Latest

MCP Configuration

{
  "mcpServers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

Additional context

Root Cause:

In runtime-executor.ts, the env object from .mcp.json is passed directly to subprocesses without expanding ${VAR} patterns:

runtime-executor.ts (line 217-221):

return {
  command: serverConfig.command,
  args: serverConfig.args || [],
  env: serverConfig.env || {}  // ← Literal values, no expansion
};

The same issue likely exists in generator.ts and executor.ts for wrapper generation.

Suggested Fix:

Add environment variable expansion before passing env to subprocesses:

function expandEnvVars(value: string): string {
  return value.replace(/\$\{([^}]+)\}/g, (_, varName) => process.env[varName] || '');
}

function expandEnvObject(env: Record<string, string>): Record<string, string> {
  const expanded: Record<string, string> = {};
  for (const [key, value] of Object.entries(env)) {
    expanded[key] = expandEnvVars(value);
  }
  return expanded;
}

// Then in loadServerConfig:
return {
  command: serverConfig.command,
  args: serverConfig.args || [],
  env: expandEnvObject(serverConfig.env || {})
};

This fix should be applied to:

  1. runtime-executor.ts (for runtime execution)
  2. executor.ts (for wrapper generation)
  3. generator.ts (if applicable)

Workaround:

Hardcode tokens directly in .mcp.json (not recommended for security):

{
  "mcpServers": {
    "github": {
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "github_pat_actual_token_here"
      }
    }
  }
}

Note:

This issue affects all users who:

  • Use secret management tools (infisical, doppler, 1password CLI, vault)
  • Want to keep credentials out of .mcp.json
  • Follow security best practices of not hardcoding tokens in config files

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions