Environment Variables¶
Use explicit absolute paths and protected secret injection. Restart the process reading an environment setting after changing it; coordinated secret or YAML activation requires matching affected services. Never place secrets in documentation, URLs or client-side bundles.
Storage and purpose-separated secrets¶
| Variable | Recipient | Meaning |
|---|---|---|
DATABASE_URL |
Console/gateway/bootstrap/command-line tools | Required. postgres:// or postgresql:// URL of the one PostgreSQL 16+ database holding governance and application tables, for example postgres://mission_control:replace-with-a-generated-password@127.0.0.1:5432/mission_control. Secret; keep the password in the user part |
API_KEY_PEPPER |
Console/gateway | Key digest verification; changing it invalidates issued credentials |
INTERNAL_SERVICE_SECRET |
Console/gateway; Collector under its prefixed name | Console/Collector internal signatures only |
AGENT_RUNTIME_INBOUND_SECRET |
Gateway/runtime | Authenticate private runtime invocation |
AGENT_RUNTIME_HEARTBEAT_SECRET |
Gateway/runtime | Authenticate runtime component heartbeat |
MANAGED_EXECUTION_AUTH_MASTER |
Gateway only | Derive short-lived managed execution inference authority |
The gateway requires all four transport secrets to be distinct and at least 32 characters. Runtime gets only inbound and heartbeat values, never INTERNAL_SERVICE_SECRET, the master, a caller virtual key or provider credential. Master rotation invalidates existing proofs. The Collector receives MISSION_CONTROL_INTERNAL_SERVICE_SECRET, not runtime/master secrets. Coordinate affected restarts and drain in-flight work.
DATABASE_URL changes require restarting every process that reads it. Each process opens a pool of at most 10 connections. The gateway, the Console and connector:rotate-credentials refuse to start with STORAGE_MIGRATION_REQUIRED: run pnpm --filter @mission-control/database db:migrate while a bundled migration is missing; nothing migrates at startup except bootstrap, and config:check does not check migrations. On the existing VPS the variable lives in shared.env (mode 600) and the deployment helper refuses a password= query parameter.
Test databases¶
These settings are for contributors' test runs only. Never point them at a server that holds real data.
| Variable | Default | Meaning |
|---|---|---|
MISSION_CONTROL_TEST_DATABASE_URL |
postgres://postgres@localhost:5433/postgres |
Administrative connection of the package test suites. Each test clones a migrated template into its own mc_test_* database and drops it afterwards. pnpm db:test:up from platform/ starts the matching throwaway server in Docker; pnpm db:test:down discards it. |
MISSION_CONTROL_E2E_DATABASE_URL |
postgres://postgres@127.0.0.1:5433/mission_control_e2e |
Database the Playwright journeys drop, create, migrate and seed, then hand to the gateway and Console as DATABASE_URL. Its name must contain e2e: the journeys refuse any other database before dropping anything. |
Removed in this release¶
The platform no longer uses these settings. Remove them from service environments and scripts.
| Variable | Replacement |
|---|---|
DATABASE_PATH |
DATABASE_URL. The deployment helper and the service start guard refuse a shared.env that still defines it, even empty. |
APPLICATION_DATABASE_PATH |
DATABASE_URL; the application tables live in the same database. Refused like DATABASE_PATH. |
DEPLOY_DATABASE_PATH |
None; the deployment helper reads DATABASE_URL from shared.env. Setting it stops the helper before any Git or SSH step. |
DEPLOY_APPLICATION_DATABASE_PATH |
None; refused like DEPLOY_DATABASE_PATH. |
MISSION_CONTROL_TEST_DIALECT |
None; every test suite runs on Postgres. |
Existing SQLite data moves once with Migrate from SQLite.
Console and authentication¶
| Variable | Default/requirement | Meaning |
|---|---|---|
APP_URL |
http://localhost:3000 |
Canonical Console URL for authentication/invitations. |
TRUSTED_ORIGINS |
APP_URL |
Comma-separated auth origins. |
BETTER_AUTH_SECRET |
Required runtime | Session/authentication secret. |
AUTH_RATE_LIMIT_MAX |
20 per 60s |
General authentication limit. |
MAGIC_LINK_RATE_LIMIT_MAX |
5 per 60s |
Magic-link request limit. |
GITHUB_CLIENT_ID |
Optional pair | GitHub OAuth app client ID. Enables Continue with GitHub on /sign-in. |
GITHUB_CLIENT_SECRET |
Optional pair | GitHub OAuth app client secret. |
BOOTSTRAP_ADMIN_EMAIL |
Required bootstrap | First owner email and initial sign-in eligibility. |
BOOTSTRAP_ORGANIZATION_NAME |
Required bootstrap | Initial organization name. |
BOOTSTRAP_ORGANIZATION_SLUG |
Required bootstrap | Initial lowercase URL slug. |
GATEWAY_PUBLIC_URL |
http://127.0.0.1:4000 |
Inference listener and Connect snippet origin; set the same value in the gateway, which derives the MCP resource identifier from it. |
OAUTH_CLIENT_REDIRECT_SCHEMES |
Empty | Comma-separated private-use URI schemes (for example cursor) accepted as client redirect URIs beside HTTPS and loopback HTTP. Empty rejects custom schemes. Changing it requires a Console restart. |
GATEWAY_MANAGEMENT_URL |
http://127.0.0.1:4001 |
Private control listener used by server actions. |
CONFIGURATION_REPOSITORY_URL |
Empty | Legacy optional repository URL helper. The current Declare page provides Copy YAML without a repository shortcut; open the reviewed configuration repository separately. |
CONTROL_GATEWAY_URL |
Falls back to management URL | Console startup/30-second heartbeat destination. |
CONSOLE_INSTANCE_ID |
Hostname/local fallback | Stable Console heartbeat instance ID. |
CONSOLE_INTERNAL_PORT |
Unset (off) | Port of the Console's private health listener (/healthz). Never route it through the public ingress. Requires a Console restart. |
CONSOLE_INTERNAL_HOST |
127.0.0.1 |
Address the private health listener binds; set the pod address when an orchestrator probes it. |
NEXT_PUBLIC_DOCS_URL |
Optional build-time | Console documentation link. |
NODE_ENV |
Runtime supplied | production forbids development mail transport. |
GitHub sign-in stays off until both GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET hold a value; a half-configured pair leaves the button hidden. Register the OAuth app callback as APP_URL plus /api/auth/callback/github. GitHub is a credential for an address that is already invited, so it never widens sign-in eligibility beyond BOOTSTRAP_ADMIN_EMAIL, existing accounts, and unexpired pending invitations.
Enterprise identity¶
These server-only settings configure one provider and one organization per Console deployment. All six required values must be set together; invalid or partial configuration prevents startup. Changes require a Console restart. See Enterprise identity.
| Variable | Requirement | Meaning |
|---|---|---|
SSO_PROVIDER |
Required when enabled | entra, okta, or keycloak. |
SSO_ORGANIZATION_SLUG |
Required when enabled | Existing organization governed by the directory. |
SSO_ISSUER |
Required when enabled | Exact HTTPS issuer without userinfo, query or fragment. |
SSO_CLIENT_ID |
Required when enabled | Confidential OIDC application client ID. |
SSO_CLIENT_SECRET |
Required when enabled | Console-only client secret. |
SCIM_BEARER_TOKEN |
Required when enabled | Provisioning bearer secret; at least 16 characters, preferably generated with high entropy. |
SSO_TENANT_ID |
Required for Entra only | Concrete tenant GUID matching the issuer. |
SSO_EXTRA_SCOPES |
Optional | Additional space/comma-separated scopes beyond openid profile email; SCIM supplies groups. |
Callbacks are /api/auth/callback/microsoft-entra-id, /api/auth/callback/okta, and /api/auth/callback/keycloak. The SCIM base is /api/scim/v2. Neither client nor SCIM secrets belong in browser settings or organization YAML. For deterministic local tests only, SSO_ALLOW_INSECURE_LOOPBACK=true permits a loopback HTTP issuer with NODE_ENV=test, or with NODE_ENV=development and MISSION_CONTROL_E2E=1. Production rejects this exception; it never allows arbitrary HTTP issuers.
Mail variables: MAIL_TRANSPORT (smtp or development-only console), MAIL_FROM, SMTP_HOST, SMTP_PORT (587), SMTP_SECURE (false), optional paired SMTP_USER/SMTP_PASSWORD, and development-only MAIL_OUTBOX_PATH.
Gateway listeners and catalog¶
| Variable | Default/requirement | Meaning |
|---|---|---|
MISSION_CONTROL_CONFIG |
../../config/mission-control.yaml |
Global catalog path. |
INFERENCE_GATEWAY_HOST |
127.0.0.1 |
Public inference bind host. |
INFERENCE_GATEWAY_PORT |
4000 |
Public inference port. |
CONTROL_GATEWAY_HOST |
127.0.0.1 |
Private operations bind host. |
CONTROL_GATEWAY_PORT |
4001 |
Private operations port. |
GATEWAY_DRAIN_SECONDS |
10 |
Seconds a stopping instance keeps serving while its readiness probes answer draining, so a load balancer stops routing to it; 0 closes at once (Run several gateway instances). |
GATEWAY_SHUTDOWN_TIMEOUT_SECONDS |
60 |
After the listeners closed, seconds the requests and streams in flight may take before their connections are destroyed. |
GATEWAY_MAX_IN_FLIGHT |
256 |
Governed requests one instance admits at a time, from the end of authorization to the end of the request. Past it, requests are refused 503 instance_saturated, one Team is held to half of it (429 team_share_exceeded), and /readyz/traffic answers saturated until the instance is back under 80% (Model gateway). A positive integer; long streams at high concurrency need a higher value. |
MCP_ALLOWED_ORIGINS |
Empty | Comma-separated exact browser origins for MCP POST /mcp and OPTIONS /mcp; empty denies every browser origin, while non-browser clients may omit Origin. |
APP_URL |
http://localhost:3000 |
Trusted Console URL for the MCP OAuth callback; set the same public value in Console and gateway. |
GATEWAY_PUBLIC_URL |
http://127.0.0.1:4000 |
Public inference URL used to build the MCP resource identifier (<url>/mcp) and the protected-resource metadata; set it to the same value the Console uses. Changing it requires a gateway restart, and clients discover the new resource identifier at their next sign-in. |
MCP_CREDENTIAL_ENCRYPTION_KEYS |
Required for OAuth | Gateway-only JSON mapping key IDs to base64 32-byte AES keys. Retain old keys during rotation. |
MCP_CREDENTIAL_ACTIVE_KEY_ID |
Required for OAuth | Keyring entry used to encrypt client material, grants and PKCE verifiers. |
MCP_AUTH_ALLOWED_PRIVATE_ORIGINS |
Empty | Exact comma-separated HTTPS origins approved by deployment for RFC1918/ULA auth endpoints. Also requires connector origin approval; loopback/link-local/mapped addresses stay blocked. |
MCP_DISCOVERY_INTERVAL_SECONDS |
300 |
Gateway-owned unified MCP connection/schema refresh interval in seconds; 0 disables scheduled refresh. Restart gateway after changing. |
AGENT_ALLOWED_ORIGINS |
Empty | Exact browser origins for /v1/deployments/{deploymentId}:invoke. |
AGENT_RUNTIME_URL |
http://127.0.0.1:4100 |
Private Agent runtime origin. |
EXPERIMENTS_ENABLED |
true |
Gateway-owned evaluation experiment execution. false leaves every started experiment Queued with no item invoked, and the Console's Evaluate → Experiments pages keep working: they start, cancel and archive as usual. It also gates the judge pass: false leaves every judgment Pending, and the auto-evaluation sampler pass: false leaves every auto-evaluation unsampled, with nothing drawn from production traffic while it stands. Restart the gateway after changing it. |
LOG_LEVEL |
info |
Safe/redacted service log level. |
MISSION_CONTROL_OTLP_ENDPOINT |
Optional | The Collector's /v1/traces URL for the gateway's own request spans, exported only for Organizations with telemetry.standardOtlp.enabled: true; unset disables gateway span export with a startup warning. |
Every env/NAME referenced by organization YAML must exist in the gateway environment, including Anthropic/Azure API-key and model-classifier references, and must not be a reserved name.
Native cloud adapters use their SDK credential chains in the gateway. AWS uses its default chain; Azure default-credential uses DefaultAzureCredential; Vertex uses Google application default credentials. Standard SDK settings such as AWS_PROFILE, AWS workload credential variables, Azure identity variables and GOOGLE_APPLICATION_CREDENTIALS are consumed by those SDKs. Region/project/location/resource endpoints remain explicit YAML settings. See Native providers. This does not add an external secret-manager service to Mission Control.
MCP_ALLOWED_ORIGINS never accepts *. An allowed preflight must request POST and only Accept, Authorization, Content-Type, standard MCP headers, Mcp-Param-*, W3C trace headers, X-Mission-Control-Session-Id, or X-Mission-Control-Customer-Subject; every other requested header fails closed. Changing the allowlist requires a gateway restart and affects no existing key or protocol session (the current MCP revision has no sessions).
The gateway holds the writer and cleanup ClickHouse identities for the signed producer writer. It may also export its own request spans through the Collector. The Collector holds no ClickHouse credential.
Names Organization YAML cannot reference¶
One gateway serves every Organization, and its environment also holds the platform's own settings and secrets. A resolved reference is sent to a URL the YAML author chooses, so an env/NAME reference must name a variable that holds that Organization's own credential. These names are reserved:
| Reserved for | Names |
|---|---|
| Mission Control settings | Every variable on this page, for any service, secret or not, and MCP_PROBE_AUTHORIZATION of the mcp:probe diagnostic command |
| Platform namespaces | Any name starting with MISSION_CONTROL_, MC_, MCP_CREDENTIAL_, CLICKHOUSE_, AGENT_RUNTIME_, DEPLOY_, OTLP_, OTEL_, BETTER_AUTH_, NODE_ or NEXT_ |
| AWS credential chain | Any name starting with AWS_ |
| Azure identity | AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_CLIENT_CERTIFICATE_PATH, AZURE_CLIENT_CERTIFICATE_PASSWORD, AZURE_CLIENT_SEND_CERTIFICATE_CHAIN, AZURE_USERNAME, AZURE_PASSWORD, AZURE_AUTHORITY_HOST, AZURE_REGIONAL_AUTHORITY_NAME, AZURE_FEDERATED_TOKEN_FILE, AZURE_ADDITIONALLY_ALLOWED_TENANTS, AZURE_TOKEN_CREDENTIALS, AZURE_POD_IDENTITY_AUTHORITY_HOST, DEFAULT_IDENTITY_CLIENT_ID, IDENTITY_ENDPOINT, IDENTITY_HEADER, IDENTITY_SERVER_THUMBPRINT, IMDS_ENDPOINT, MSI_ENDPOINT, MSI_SECRET, and any name starting with AZURE_IDENTITY_ |
| Google application default credentials | GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_API_CERTIFICATE_CONFIG, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_QUOTA_PROJECT, GCLOUD_PROJECT, METADATA_SERVER_DETECTION, and any name starting with GOOGLE_EXTERNAL_ACCOUNT_, CLOUDSDK_ or GCE_METADATA_ |
| PostgreSQL client | PGHOST, PGHOSTADDR, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, PGPASSFILE, PGSERVICE, PGSERVICEFILE, PGOPTIONS, PGAPPNAME, PGSSLMODE, PGSSLCERT, PGSSLKEY, PGSSLROOTCERT |
| Outbound proxy | HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY |
Provider key names such as env/OPENAI_API_KEY, env/ANTHROPIC_API_KEY and env/AZURE_OPENAI_API_KEY remain available. Gateway startup, Console startup and config:check refuse a file that references a reserved name before any secret is resolved, and name the file and field:
Secret reference names a reserved platform environment variable (acme.yaml: providers.primary.credential)
To recover, set the credential in a variable the Organization owns, change the reference to that name, for example env/ACME_OPENAI_API_KEY, run config:check, and restart the gateway and Console. No new virtual key or session is needed. The gateway's secret resolver also refuses a reserved name before it reads the environment.
Agent runtime¶
| Variable | Default/requirement | Meaning |
|---|---|---|
AGENT_RUNTIME_HOST, AGENT_RUNTIME_PORT |
127.0.0.1, 4100 |
Private runtime bind |
MISSION_CONTROL_GATEWAY_URL |
Required | Inference origin for scoped model/MCP work |
MISSION_CONTROL_CONTROL_URL |
Set for heartbeat | Private control origin; heartbeat secret required when set |
AGENT_RUNTIME_INBOUND_SECRET |
Required | Private invocation authentication |
AGENT_RUNTIME_HEARTBEAT_SECRET |
Required with heartbeat | Purpose-separated heartbeat authentication |
MISSION_CONTROL_OTLP_ENDPOINT |
Required | HTTP /v1/traces URL or gRPC authority |
MISSION_CONTROL_OTLP_PROTOCOL |
http/protobuf |
http/protobuf or grpc |
AGENT_RUNTIME_INSTANCE_ID |
Optional | Component instance identifier |
LOG_LEVEL |
info |
Safe service logging |
No global secret fallback exists. Managed generation uses a 4,096 output-token bound per model round; no environment knob changes it. Reusable external clients have no global output default and must choose per-call bounds under finite budgets.
Gateway Team telemetry writer¶
| Variable | Requirement | Meaning |
|---|---|---|
CLICKHOUSE_URL, CLICKHOUSE_DATABASE |
Complete writer/admin set | HTTP(S) endpoint and current Team database |
CLICKHOUSE_COLLECTOR_USERNAME, CLICKHOUSE_COLLECTOR_PASSWORD |
Complete set | Historical account name used by gateway writer, not Collector |
CLICKHOUSE_ADMIN_USERNAME, CLICKHOUSE_ADMIN_PASSWORD |
Complete set | Separate deletion/physical cleanup identity |
CLICKHOUSE_TLS_CA_PATH |
Optional | CA for gateway ClickHouse TLS |
All six endpoint/database/writer/admin settings are required together. With none, observed storage is explicitly unavailable; canonical Request/ledger data is not fabricated. Partial configuration fails startup.
Console Observe reader¶
| Variable | Requirement | Meaning |
|---|---|---|
CLICKHOUSE_HTTP_URL |
All-or-none reader set | Read-only HTTP(S) endpoint |
CLICKHOUSE_DATABASE |
Reader set, mission_control |
Current Team database |
CLICKHOUSE_USERNAME, CLICKHOUSE_PASSWORD |
Reader set | Read-only identity, reference mission_control_repository |
CLICKHOUSE_CA_FILE |
Optional | Reader TLS CA |
CLICKHOUSE_MUTATION_USERNAME, CLICKHOUSE_MUTATION_PASSWORD |
Optional pair | Exact Team Trace deletion identity behind authorized Delete Trace observations |
Absent reader settings leave canonical Requests and Usage available with explicit span-storage unavailability. Restart Console after reader/credential changes.
Collector¶
| Variable | Default/requirement | Meaning |
|---|---|---|
MISSION_CONTROL_INTERNAL_URL |
Required | Private control producer authentication/writer/heartbeat origin |
MISSION_CONTROL_INTERNAL_SERVICE_SECRET |
Required | Console/Collector transport secret |
OTLP_GRPC_ENDPOINT, OTLP_HTTP_ENDPOINT |
127.0.0.1:4317, 127.0.0.1:4318 |
Trace ingress binds |
OTLP_TLS_CERT_FILE, OTLP_TLS_KEY_FILE |
Production pair | Ingress TLS |
TELEMETRY_MEMORY_LIMIT_MIB, TELEMETRY_MEMORY_SPIKE_MIB |
384, 64 |
Memory limiter and spike allowance |
TELEMETRY_HEALTH_ENDPOINT |
127.0.0.1:13133 |
Collector health-check bind address (path /health). Set 0.0.0.0:13133 in a container so the orchestrator can probe it; keep it off public networks. |
The pipeline uses mc_producer and synchronous mc_writer. There are no queue-directory, native ClickHouse exporter, runtime-secret or master settings in Collector configuration. Ingress is 4 MiB; writer batches are at most 1,000 spans/4 MiB and private requests time out after five seconds.
ClickHouse migration and reference deployment¶
CLICKHOUSE_URL, CLICKHOUSE_MIGRATION_DATABASE, CLICKHOUSE_TLS_ENABLED, CLICKHOUSE_REQUEST_TIMEOUT_MS, CLICKHOUSE_MIGRATION_USERNAME and CLICKHOUSE_MIGRATION_PASSWORD configure migrations. Reference Compose uses CLICKHOUSE_HTTP_PORT, CLICKHOUSE_NATIVE_PORT, writer credentials above, CLICKHOUSE_REPOSITORY_USERNAME/PASSWORD, CLICKHOUSE_ADMIN_USERNAME/PASSWORD, CLICKHOUSE_BACKUP_USERNAME/PASSWORD, CLICKHOUSE_BACKUP_ENCRYPTION_KEY_HEX, OTLP_GRPC_PORT, OTLP_HTTP_PORT and TELEMETRY_HEALTH_PORT.
The current maintenance backup covers team_span_payloads, team_span_heads and team_span_deletions together. It does not use the old scoped signed-manifest API. Do not cross irreversible historical migration boundaries with a down migration.
External integrations¶
| Variable | Meaning |
|---|---|
MISSION_CONTROL_GATEWAY_URL |
Inference origin |
MISSION_CONTROL_API_KEY |
Ordinary user/service virtual key; no Agent ID |
MISSION_CONTROL_VIRTUAL_MODEL |
Authorized generation model |
MISSION_CONTROL_MCP_TOOL |
Declared tool for the conformance example |
MISSION_CONTROL_OTLP_ENDPOINT, MISSION_CONTROL_OTLP_PROTOCOL |
Standard OTLP endpoint/protocol |
Generic SDKs may use OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL and OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20mck_example_not_a_real_key. These authenticate export; they never grant scope through span attributes. See the PydanticAI guide.
Release version¶
| Variable | Default/requirement | Meaning |
|---|---|---|
MISSION_CONTROL_VERSION |
0.0.0-dev |
The release version the gateway, Console and Agent runtime report. Release images set it from the repository's VERSION file; operators do not set it. A value that is not a semantic version, such as v0.1.0, fails startup with MISSION_CONTROL_VERSION must be a semantic version. |
Deployment helper and retired setting¶
The VPS helper uses DEPLOY_HOST, DEPLOY_REMOTE_ROOT, DEPLOY_CONFIG_ROOT,
DEPLOY_STATE_ROOT, DEPLOY_NODE_BIN_DIR, DEPLOY_UV_BIN,
DEPLOY_GATEWAY_PUBLIC_URL, DEPLOY_CONSOLE_PUBLIC_URL
and DEPLOY_ORGANIZATION_SLUG. It reads DATABASE_URL from shared.env on
the host, validates split listener settings and never resets the database or
ClickHouse. scripts/rollback_vps.sh uses the same roots and
ROLLBACK_RELEASE; see Upgrade and rollback.
MCP_HEALTH_INTERVAL_SECONDS is retired and rejected at startup. Use MCP_DISCOVERY_INTERVAL_SECONDS for the single refresh schedule. Reviewed YAML/static-secret changes need coordinated gateway/Console restart; no Console Apply action exists.