# Securing API Credentials in MCP Server Configurations: A Complete Guide

> Secure MCP server API credentials by using Docker environment variables or secrets. Learn how to inject and access sensitive data with os.getenv() and file reads to protect your code.

- Repository: [CSK/mcp-wordle-python](https://github.com/cr2007/mcp-wordle-python)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Use environment variables injected via Docker `-e` flags or Docker secrets mounted at runtime to keep API credentials out of source control and image layers, accessing them securely within FastMCP tools using `os.getenv()` or file reads from `/run/secrets/`.**

The Model Context Protocol (MCP) enables AI assistants to interact with external data sources through lightweight server implementations. In the **cr2007/mcp-wordle-python** repository—a FastMCP-based Wordle solution server—sensitive credentials must be injected at runtime rather than embedded in code or Docker images. This guide demonstrates production-ready patterns for securing API keys across Docker, uvx, and local development environments.

## Understanding the MCP Server Architecture

The Wordle MCP (Python) server follows a minimal micro-service pattern built on the FastMCP framework. Understanding where configuration resides is essential before implementing credential security.

### FastMCP Entry Point and Tool Registration

The server initialization occurs in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py), where the FastMCP object is instantiated and tools are registered:

```python
mcp = FastMCP("WordleMCP")               # ← FastMCP registration

```

This object exposes the `get_wordle_data` tool, which fetches Wordle data. While the current implementation accesses public endpoints, extending it to authenticated APIs requires secure credential handling within this entry point.

### Docker Runtime Configuration

The multi-stage `Dockerfile` builds a minimal runtime image where the application resides in `/app`. The `ENTRYPOINT` executes the `mcp-wordle` console script defined in [`pyproject.toml`](https://github.com/cr2007/mcp-wordle-python/blob/main/pyproject.toml). Critically, the image contains **no embedded credentials**—they must be supplied at container startup via environment variables or secret mounts.

## Configuration Entry Points for Credentials

MCP servers receive configuration through the client registration file (typically Claude Desktop's `~/.config/claude/servers.json`) and runtime environment injection.

### MCP Client Registration File

The README demonstrates the standard registration pattern for Docker-based deployment:

```json
{
  "mcpServers": {
    "Wordle MCP (Python)": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "--init",
        "-e",
        "DOCKER_CONTAINER=true",
        "ghcr.io/cr2007/mcp-wordle-python:latest"
      ]
    }
  }
}

```

This JSON structure is the **only place** where server commands and runtime arguments are defined. Adding `-e KEY=VALUE` flags here injects credentials without touching source code.

### uvx-Based Registration

For Python-centric deployments using `uvx`, the registration supports environment injection:

```json
{
  "Wordle MCP (Python)": {
    "command": "uvx",
    "args": [
      "--from",
      "git+https://github.com/cr2007/mcp-wordle-python",
      "mcp-wordle",
      "--env",
      "WORDLE_API_KEY=${WORDLE_API_KEY}"
    ]
  }
}

```

The `--env` flag (or `--env-file .env`) ensures variables are set before the FastMCP server initializes.

## Secure Credential Injection Patterns

Production MCP servers should implement defense-in-depth for secret management, keeping credentials out of image layers and source control.

### Environment Variables via Docker Flags

The simplest pattern adds `-e` flags to the Docker args array in the MCP config:

```json
"-e",
"WORDLE_API_KEY=${WORDLE_API_KEY}"

```

The host shell expands `${WORDLE_API_KEY}` at runtime, keeping the raw value out of the JSON file. Inside [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py), access the key via:

```python
import os
api_key = os.getenv("WORDLE_API_KEY")
if not api_key:
    raise RuntimeError("Missing WORDLE_API_KEY")

```

### Docker Secret Files

For Docker Swarm or Compose deployments, mount secrets as files:

```yaml

# docker-compose.yml

services:
  wordle-mcp:
    image: ghcr.io/cr2007/mcp-wordle-python:latest
    environment:
      - DOCKER_CONTAINER=true
    secrets:
      - wordle_api_key

secrets:
  wordle_api_key:
    file: ./secrets/wordle_api_key.txt

```

Inside the container, read from `/run/secrets/wordle_api_key`:

```python
from pathlib import Path
secret_path = Path("/run/secrets/wordle_api_key")
if secret_path.is_file():
    api_key = secret_path.read_text().strip()

```

### Local Development with .env Files

The repository includes a `.env.example` file. For local testing, copy it to `.env` and populate values:

```bash

# .env

WORDLE_API_KEY=s3cr3t-k3y-123

```

Load it via `uvx`:

```bash
uvx --from git+https://github.com/cr2007/mcp-wordle-python \
    --env-file .env mcp-wordle

```

This keeps credentials out of shell history and source control while providing a convenient developer experience.

## Implementing Secure Credentials in the Tool

Below is a complete example modifying [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) to securely handle a Wordle API key using multiple fallback methods:

```python
import os
from pathlib import Path
from fastmcp import FastMCP

mcp = FastMCP("WordleMCP")

def get_api_key() -> str:
    """Retrieve API key from environment or Docker secrets."""
    # Priority 1: Environment variable

    api_key = os.getenv("WORDLE_API_KEY")
    
    # Priority 2: Docker secret file

    if not api_key:
        secret_path = Path("/run/secrets/wordle_api_key")
        if secret_path.is_file():
            api_key = secret_path.read_text().strip()
    
    if not api_key:
        raise RuntimeError("Wordle API key not provided via environment or secrets")
    
    return api_key

@mcp.tool(
    name="get_wordle_solution",
    description="Fetches the Wordle solution for a given date",
)
async def get_wordle_solution(target_date: str):
    api_key = get_api_key()
    headers = {"Authorization": f"Bearer {api_key}"}
    # Implementation continues...

```

## Summary

- **Never hard-code credentials** in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) or the `Dockerfile`.
- **Use environment variables** injected via `-e` flags in the MCP client config JSON for Docker deployments.
- **Leverage Docker secrets** mounted at `/run/secrets/` for production Swarm or Compose stacks.
- **Develop locally** with `.env` files loaded through `uvx --env-file` to keep secrets out of git history.
- **Validate at startup** by checking for required environment variables or secret files in your FastMCP entry point to ensure fail-fast behavior.

## Frequently Asked Questions

### How do I pass API credentials to an MCP server running in Docker?

Add environment variable flags to the `args` array in your MCP client configuration. Use the syntax `-e VARIABLE_NAME=${VARIABLE_NAME}` so the host shell expands the value at runtime, keeping the raw secret out of the JSON file. Inside the container, access the value using `os.getenv("VARIABLE_NAME")` in your Python code.

### Can I use Docker secrets instead of environment variables for MCP servers?

Yes. Configure your MCP server to read from files mounted at `/run/secrets/secret_name`. In Docker Compose, define the secret in a top-level `secrets:` section and reference it in your service configuration. In Python, use `Path("/run/secrets/secret_name").read_text()` to retrieve the credential. This method keeps secrets out of environment variables and process listings.

### What is the safest way to handle credentials during local development of MCP servers?

Use a `.env` file that is excluded from version control via `.gitignore`. Load this file using `uvx --env-file .env` when running your MCP server locally. This prevents credentials from appearing in shell history, terminal logs, or source control while providing a convenient developer workflow. Always commit a `.env.example` template with dummy values rather than the actual `.env` file.

### Where should I validate that API credentials are present in an MCP server?

Perform validation at server startup within your main entry point (e.g., [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py)) before registering tools with FastMCP. Check for the presence of required environment variables or secret files and raise a `RuntimeError` with a descriptive message if they are missing. This fail-fast approach ensures that credential issues are caught immediately when the server starts rather than during tool execution.