Skip to main content

Why secrets matter

Every MCPApp run loads a Settings model that merges configuration, secrets, and environment overrides. Secrets unlock LLM providers, authenticated MCP servers, OAuth clients, and third-party APIs. Treat them as production-grade credentials across local dev, CI pipelines, and deployed agents.

Quick start: secrets file

Use the gitignored secrets file for iterative development:
mcp_agent.secrets.yaml
openai:
  api_key: "sk-..."

anthropic:
  api_key: "sk-ant-..."

temporal:
  api_key: "..."
Keep both mcp_agent.secrets.yaml and mcp-agent.secrets.yaml ignored—mcp-agent will discover either casing automatically. 📌 Try it: the basic finder agent example expects credentials in this file (or matching environment variables).

Environment variables and .env

Settings uses Pydantic’s nested delimiter (__) and automatically loads a .env file in the working directory. Any environment variable overrides the same key from config or secrets:
export OPENAI_API_KEY="sk-..."
export MCP_AGENT__OPENAI__DEFAULT_MODEL="gpt-4o-mini"
export MCP_AGENT__MCP__SERVERS__FETCH__AUTH__API_KEY="..."
You can reference these variables directly inside the config file with ${VAR_NAME} or rely on the automatic override behaviour. Tip: See the token counter example for a project that mixes .env overrides with secrets files.

Managing OAuth credentials

When you connect to OAuth-protected MCP servers, supply the client credentials in your secrets file or environment:
mcp_agent.secrets.yaml
mcp:
  servers:
    github:
      auth:
        oauth:
          client_id: "github-client-id"
          client_secret: "github-client-secret"
Combine this with the server configuration in mcp_agent.config.yaml to enable the OAuth flow. The oauth_basic_agent example demonstrates the client-only loopback pattern for GitHub, while the oauth/interactive_tool sample shows a full authorization-code flow between an MCP client and server.

Token storage backends

At startup, MCPApp initialises a token manager based on your config (settings.oauth.token_store). By default tokens live in memory; switch to Redis by adding:
mcp_agent.config.yaml
oauth:
  token_store:
    backend: redis
    redis_url: ${OAUTH_REDIS_URL}
This mirrors the Redis instructions in the OAuth examples and keeps tokens durable across restarts. The oauth/pre_authorize workflow example seeds tokens ahead of a background workflow so it never has to pop open a browser.

Discovery & precedence

mcp-agent reads secrets and overrides in the following order (last writer wins):
  • MCP_APP_SETTINGS_PRELOAD / MCP_APP_SETTINGS_PRELOAD_STRICT
  • Explicit Settings instance passed to MCPApp
  • mcp_agent.config.yaml (or mcp-agent.config.yaml)
  • mcp_agent.secrets.yaml / mcp-agent.secrets.yaml
  • Environment variables (including values from .env)
If MCP_APP_SETTINGS_PRELOAD is set, its YAML payload is treated as the complete settings document and no other sources are consulted.

Advanced: preloading secrets without files

MCP_APP_SETTINGS_PRELOAD is the recommended production path when you cannot store plaintext credentials on disk. Provide a YAML or JSON string that serialises the Settings model:
export MCP_APP_SETTINGS_PRELOAD="$(python - <<'PY'
from pydantic_yaml import to_yaml_str
from mcp_agent.config import Settings, OpenAISettings
print(to_yaml_str(Settings(openai=OpenAISettings(api_key='sk-prod-...'))))
PY
)"
  • Set MCP_APP_SETTINGS_PRELOAD_STRICT=true to fail fast if the payload cannot be parsed.
  • Preload also supports non-secret overrides (for example, swapping model defaults).

Best practices

  • Rotate provider keys and refresh MCP_APP_SETTINGS_PRELOAD values via your secret manager.
  • Prefer environment variables or preload for CI/CD pipelines.
  • Avoid logging secret values—mcp-agent’s structured logger redacts known fields, but additional care may be required for custom data structures.
  • Treat secrets files as developer convenience only; they should not ship with containers or production artefacts.
More configuration options →
I