# MetaMCP Environment Variables: Production Best Practices and Security Guide

> Secure your MetaMCP production deployment with best practices for environment variables. Use secret stores, set NODE_ENV=production, and validate variables at startup.

- Repository: [metatool-ai/metamcp](https://github.com/metatool-ai/metamcp)
- Tags: best-practices
- Published: 2026-03-07

---

**Store secrets in Docker or Kubernetes secret stores, reference them using `${VAR}` syntax in MCP server configurations, set `NODE_ENV=production`, and validate required variables at startup to secure MetaMCP production deployments.**

MetaMCP, an open-source Docker-based service from the `metatool-ai/metamcp` repository, manages STDIO MCP servers as child processes. Properly configuring MetaMCP environment variables in production requires understanding how the container merges host environment variables with server-specific configurations while keeping sensitive credentials out of source control.

## Understanding MetaMCP's Environment Variable Architecture

### How MetaMCP Inherits Environment Variables

When MetaMCP spawns a STDIO MCP server, it constructs the child process environment by merging three sources. According to the source code in [`apps/backend/src/lib/stdio-transport/process-managed-transport.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/lib/stdio-transport/process-managed-transport.ts), the `getDefaultEnvironment()` function (lines 94-115) combines the container's current process environment with a safe-inheritance whitelist and any explicit `env` map defined in the server configuration.

### The Default Safe-Inheritance List

The `DEFAULT_INHERITED_ENV_VARS` array (lines 49-91 in [`process-managed-transport.ts`](https://github.com/metatool-ai/metamcp/blob/main/process-managed-transport.ts)) defines which host environment variables MetaMCP safely passes to child processes by default. This whitelist prevents leaking unrelated host information, such as user home directories or shell histories, into MCP server containers. You should avoid adding arbitrary host variables to this list unless specifically required by your MCP servers.

## Production Configuration Best Practices for MetaMCP

### Keep Secrets Out of Source Control

Store actual secret values only in the container's runtime environment using Docker `--env-file`, Docker Secrets, Kubernetes Secrets, or CI/CD secret stores. As documented in the README (lines 102-124), MetaMCP resolves `${VAR}` references at runtime from the container's environment and never writes expanded values to the MCP JSON configuration file.

### Use ${VAR} Syntax for Dynamic Values

Reference environment variables in your MCP server definitions using the `${VAR}` syntax. For example, configure `API_KEY=${OPENAI_API_KEY}` in your server JSON configuration. This approach, shown in the README's Environment Variable References section (lines 112-118), keeps secrets out of version-controlled JSON files while allowing the same configuration to be reused across development, staging, and production environments.

### Set NODE_ENV=production Explicitly

Add `ENV NODE_ENV=production` in your Dockerfile or docker-compose file. The repository's `example.env` file (line 1) demonstrates this setting, and the Dockerfile (line 18) sets `NEXT_TELEMETRY_DISABLED=1` for production builds. Many internal code branches, such as OAuth utilities, guard production-only behavior behind this flag (`process.env.NODE_ENV === "production"` as seen in lines 70-78 of the README analysis).

### Validate Required Variables at Startup

Implement a bootstrap validation script that checks for critical environment variables before MetaMCP starts. This prevents the service from running with partial configuration. The script should verify variables such as `APP_URL`, `DATABASE_URL`, and any OIDC credentials, exiting with a clear error message if any are missing.

## Implementing Secure MetaMCP Deployments

### Docker Compose Configuration Example

For production deployments, use Docker Compose with an external environment file. The repository's [`docker-compose.yml`](https://github.com/metatool-ai/metamcp/blob/main/docker-compose.yml) demonstrates this pattern, separating runtime secrets from the container image.

```yaml
services:
  metamcp:
    image: ghcr.io/metatool-ai/metamcp:latest
    env_file:
      - .env                 # Runtime secrets, never committed

    environment:
      - NODE_ENV=production  # Force production mode

    ports:
      - "8080:8080"

```

### MCP Server Definition with Environment References

Configure your MCP servers to reference environment variables rather than hard-coding secrets. This JSON configuration can be safely committed to source control.

```json
{
  "OpenAI": {
    "type": "STDIO",
    "command": "uvx",
    "args": ["mcp-openai"],
    "env": {
      "API_KEY": "${OPENAI_API_KEY}",
      "BASE_URL": "https://api.openai.com/v1"
    }
  }
}

```

### Bootstrap Validation Script

Add a TypeScript validation script to your deployment to ensure all required MetaMCP environment variables are present before startup.

```typescript
// src/bootstrap.ts
const required = [
  "APP_URL",
  "DATABASE_URL",
  "OPENAI_API_KEY",
  "OIDC_CLIENT_ID",
  "OIDC_CLIENT_SECRET",
];

for (const key of required) {
  if (!process.env[key]) {
    console.error(`Missing required environment variable: ${key}`);
    process.exit(1);
  }
}
console.log("All required environment variables are present");

```

Execute this script before starting the main application: `node src/bootstrap.js && npm start`.

## Summary

- Store secrets in Docker or Kubernetes secret stores, never in source control or MCP JSON configuration files.
- Use the `${VAR}` syntax in MCP server definitions to reference container environment variables at runtime.
- Set `NODE_ENV=production` explicitly in your Dockerfile or docker-compose configuration.
- Validate required MetaMCP environment variables at startup using a bootstrap script to fail fast on misconfiguration.
- Rely on the built-in `DEFAULT_INHERITED_ENV_VARS` whitelist in [`process-managed-transport.ts`](https://github.com/metatool-ai/metamcp/blob/main/process-managed-transport.ts) to prevent leaking host environment variables to child processes.

## Frequently Asked Questions

### How does MetaMCP handle environment variable inheritance?

MetaMCP merges the container's process environment with a safe-inheritance whitelist (`DEFAULT_INHERITED_ENV_VARS` in [`apps/backend/src/lib/stdio-transport/process-managed-transport.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/lib/stdio-transport/process-managed-transport.ts)) and any explicit `env` map defined in the server configuration. This ensures child MCP server processes receive only necessary variables without exposing unrelated host environment data.

### What is the recommended way to store secrets for MetaMCP?

Store secrets in the container's runtime environment using Docker `--env-file`, Docker Secrets, Kubernetes Secrets, or CI/CD secret stores. Never commit actual values to source control. Reference these secrets in your MCP JSON configuration using the `${VAR}` syntax, which MetaMCP resolves at runtime without writing values to disk.

### Should I use turbo.json globalEnv for production deployments?

No. The `globalEnv` array in [`turbo.json`](https://github.com/metatool-ai/metamcp/blob/main/turbo.json) is designed for local development with Turborepo and should not be relied upon for production. According to the repository documentation, production deployments should inject environment variables directly via Docker or Kubernetes secret stores rather than through the Turborepo configuration.

### How do I validate that all required MetaMCP environment variables are set?

Implement a bootstrap validation script that checks for critical variables such as `APP_URL`, `DATABASE_URL`, and OIDC credentials before starting the MetaMCP service. If any required variables are missing, the script should exit with a clear error message. This "fail fast" approach prevents the service from running with partial configuration and makes deployment issues immediately obvious.