Secrets Management

Manage sensitive values like API keys and tokens with Argus MCP's encrypted secret store, supporting file, environment, and keyring providers.

Argus MCP provides an encrypted secret store for managing sensitive values like API keys, tokens, and credentials. Secrets are referenced in config files and resolved at startup -- they never appear in plaintext in config or logs.

Architecture

Config file                    SecretStore
  |                               |
  |  secret:my-api-key        +---+---------------------+
  |  ----------------->       |  SecretResolver          |
  |                           |                          |
  |                           |  Looks up in:            |
  |                           |  +-- FileProvider        |
  |                           |  +-- EnvProvider         |
  |                           |  +-- KeyringProvider     |
  |                           |                          |
  |  sk-abc123...             |  Registers with:         |
  |  <-----------------       |  LogRedactionFilter      |
  |                           +--------------------------+

Configuration

secrets:
  enabled: false
  provider: "env"
  path: ""
  strict: false
FieldTypeDefaultDescription
enabledbooleanfalseEnable automatic secret resolution
providerstring"env"Provider type: "env", "file", or "keyring"
pathstring""Path for the file provider (ignored for other providers)
strictbooleanfalseRaise an error if a referenced secret cannot be resolved

Providers

File Provider (default)

Stores secrets in a Fernet-encrypted JSON file.

SettingValue
Filesecrets.enc (configurable via --path)
EncryptionFernet (AES-128-CBC + HMAC-SHA256)
Master keyARGUS_SECRET_KEY environment variable
File permissions0600 (owner read/write only)
Write strategyAtomic (temp file + rename)
Dependencycryptography package
# Generate a master key
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
export ARGUS_SECRET_KEY="<generated-key>"

# Store secrets
argus-mcp secret set my-api-key
argus-mcp secret set db-password

Environment Provider

Maps secret names to environment variables using a convention:

secret name:  my-api-key
env var:      SECRET_MY_API_KEY

Convention: uppercase, hyphens to underscores, SECRET_ prefix.

export SECRET_MY_API_KEY=sk-abc123

Keyring Provider

Uses the OS-native credential store:

OSBackend
macOSKeychain
LinuxGNOME Keyring / KWallet
WindowsCredential Locker

Service name: argus-mcp. Requires the keyring package.

Config Integration

Reference secrets with the secret: prefix in any config string value:

backends:
  my-server:
    type: sse
    url: "http://localhost:8080/sse"
    headers:
      Authorization: "Bearer secret:my-api-key"

server:
  management:
    token: "secret:mgmt-token"

incoming_auth:
  type: local
  token: "secret:auth-token"

Resolution Process

  1. Config is loaded and parsed
  2. resolve_secrets() walks all string values
  3. Strings matching ^secret:(.+)$ are looked up in the SecretStore
  4. Resolved values replace the references in-memory
  5. Each resolved value is registered with the SecretRedactionFilter

Strict Mode

When strict: true, missing secrets raise an error at startup. When strict: false (default), missing secrets log a warning and keep the secret: reference as-is.

Log Redaction

All resolved secret values are automatically registered with the SecretRedactionFilter:

  • The filter is attached to all log handlers at startup
  • Any log message containing a secret value has it replaced with ***REDACTED***
  • Redaction uses compiled regex patterns for performance
  • Works on string messages, dict args, and tuple args

This ensures no plaintext secrets appear in:

  • Application log files
  • Console output
  • Audit trail messages

SecretStore API

from argus_mcp.secrets.store import SecretStore

store = SecretStore(provider_type="file", path="secrets.enc")

# CRUD operations
store.set("my-key", "my-value")
value = store.get("my-key")
names = store.list_names()
store.delete("my-key")
exists = store.exists("my-key")