Skip to content

Environment variable reference

Every knob in precis-mcp is an environment variable — there is no config file beyond your model in instance/ and the Compose bundles in deploy/. The deploy bundles read variables from deploy/.env (copy deploy/.env.example in the repository and edit); outside Compose, export them in the service's environment.

Secrets. Any variable can instead be supplied as <NAME>_FILE pointing at a mounted file (Docker Compose secrets:, Kubernetes projected volumes, Vault Agent sidecars). precis_mcp/secrets.py resolves these at startup; a plain value wins if both are set. The tables below flag the variables that normally hold credentials.

Deployment axes

Consumed by Docker Compose and scripts/deploy-mcp.sh, not by the server process itself.

Variable Default Purpose
COMPOSE_PROFILES bundled-clickhouse,bundled-keycloak,bundled-proxy Which optional services the multi-user stack runs. Drop bundled-clickhouse to use your own ClickHouse; drop bundled-keycloak for a direct external IdP; drop bundled-proxy to terminate TLS at your own ingress; append backup to run the backup scheduler sidecar; append ingestion and/or ingestion-watch for the ingestion daemons.
PRECIS_DATA_MODE unset Provisioning preset for deploy-mcp.sh --data-mode: byo / bundle-empty / bundle-sample. See ClickHouse data modes.
PRECIS_AUTH_MODE keycloak (multi-user), devkey (dev server) Identity mode selector: devkey / keycloak / oidc. See Remote access — sign-in & identity modes.
PRECIS_INGRESS_MODE bundled Ingress preset for deploy-mcp.sh --ingress-mode: bundled (the Caddy auto-HTTPS proxy) / byo (your own ingress fronts the 127.0.0.1-published ports).
PRECIS_DOMAIN empty Bare hostname (the host part of PRECIS_BASE_URL, no scheme) the bundled Caddy proxy serves and obtains its Let's Encrypt certificate for. Required when bundled-proxy is in COMPOSE_PROFILES; ignored otherwise.

Application image

Consumed by Docker Compose when it brings the stack up (and at build time), not by the server process itself.

Variable Default Purpose
PRECIS_MCP_TAG current release Tag of ghcr.io/precis-finance/precis-mcp the app services pull. Compose uses this image when present and falls back to building from source when it is absent (or on up --build). Pin a version or a @sha256: digest for an immutable re-pull — see Upgrading.
PRECIS_EXTRAS empty Optional warehouse drivers baked into the image at build time (comma-separated: bigquery,snowflake,mssql,databricks). Only used on the build-from-source path; the published image is the core build without extras.

ClickHouse (the read layer)

Variable Default Purpose
CHHOST localhost ClickHouse host. The bundled service name is clickhouse.
CHPORT 8123 (8443 when CHSECURE) HTTP(S) port.
CHUSER default Username. Also seeds the bundled service — keep in sync.
CHPASSWORD empty Password. Secret.
CHDATABASE default Default database of the ClickHouse connection (also names the database the bundled service creates at first start). The pipeline's own tables always live in the fixed live / staging / semantic databases — see the schema contract.
CHSECURE false TLS on the ClickHouse link (flips the default port to 8443).
CHCACERT unset CA certificate path to pin (with CHSECURE).
CHVERIFY unset Set false to accept a self-signed dev certificate.
PRECIS_CLICKHOUSE_POOL_MAXSIZE 32 Per-host size of the shared ClickHouse HTTP connection pool. Set it at or above PRECIS_MAX_CONCURRENT_READS_GLOBAL so the read-concurrency cap, not pool exhaustion, is what bounds a query burst.
PRECIS_SCENARIO_REGISTRY_TTL 5 Seconds the in-process scenario-registry cache (backing the per-call permission gate) serves without re-reading semantic.scenarios. Scenario writes through the server invalidate immediately; the TTL only bounds staleness for writes made outside the process.

Read concurrency (the /mcp read path)

In-process caps that keep a fan-out of read-tool calls — e.g. an Excel workbook recalculating many PRECIS.* cells at once — from flooding ClickHouse. The caps are per server process; a request that can't get a slot within the wait gets a retryable "busy" tool error.

Variable Default Purpose
PRECIS_MAX_CONCURRENT_READS_PER_USER 6 Max in-flight read-tool calls for any one user. The working control — contains a single client's burst and stops one user starving others.
PRECIS_MAX_CONCURRENT_READS_GLOBAL 32 Max in-flight read-tool calls across all users. A box guard; keep it at or below the ClickHouse pool size.
PRECIS_READ_SLOT_WAIT_SECONDS 3 How long a call waits for a free slot before returning the retryable busy error.

PostgreSQL (platform state — multi-user bundle only)

Users, profiles, and load history. The single-user trial runs without Postgres.

Variable Default Purpose
PGHOST / PGPORT localhost / 5432 Platform DB endpoint.
PGUSER postgres Username.
PGPASSWORD empty Password. Secret.
PLATFORM_DB_NAME precis_platform Database name.
PGSSLMODE / PGSSLROOTCERT libpq defaults TLS mode / CA path for the platform DB link.
PG_CONNECT_TIMEOUT 5 Per-attempt connect timeout (seconds).
PG_POOL_MIN / PG_POOL_MAX / PG_POOL_TIMEOUT 0 / 10 / 10 Connection-pool bounds and acquire timeout.

Identity — shared

Variable Default Purpose
PRECIS_BASE_URL empty Public origin of your server (https://precis.example.com). OAuth URLs and the /mcp audience derive from it. Required for the multi-user bundle.
PRECIS_AUTH_PREFLIGHT false Run an issuer/JWKS/audience conformance check at boot and fail fast on misconfiguration.
PRECIS_IDENTITY_CLAIM precis_user_id (falls back to preferred_username) Signed token claim carrying the user identity.
PRECIS_IDENTITY_COLUMN id users column the claim is matched against (id or external_id).
PRECIS_BOOTSTRAP_ADMIN_ID empty First admin to create on deploy (read by deploy-mcp.sh, also settable via --admin-id). The deploy creates it idempotently and prints a one-time temporary password; left empty, the deploy prints the manual command instead.

Identity — mode A: single-user dev key

The local trial (precis_mcp.server). Three deliberate gates: the explicit enable flag, a strong key, and a localhost bind.

Variable Default Purpose
ENABLE_MCP_DEV_SERVER unset Must be exactly 1 for the dev server to start.
MCP_DEV_KEY unset Shared bearer key, 32+ chars (openssl rand -hex 32). Secret. Required.
MCP_BIND_HOST 127.0.0.1 Listen address. Use 0.0.0.0 only inside an isolated container network.
MCP_BIND_PORT 8768 Listen port.

Identity — mode B: bundled Keycloak

Variable Default Purpose
KC_BASE_URL_INTERNAL http://localhost:8080/auth Container-to-container Keycloak URL.
KC_BASE_URL_PUBLIC ${PRECIS_BASE_URL}/auth Public Keycloak URL (behind your ingress).
KC_REALM precis Realm name.
KC_CLIENT_ID precis-spa Pre-registered public client.
KC_MCP_AUDIENCE ${PRECIS_BASE_URL}/mcp RFC 8707 audience the /mcp resource requires.
KC_REDIRECT_URI ${PRECIS_BASE_URL}/api/auth/callback OAuth redirect URI.
KC_HOSTNAME_ADMIN http://localhost:8080/auth URL the Keycloak admin console is served at. Defaults to localhost to match the reference ingress, which blocks /auth/admin/ at the edge — reach the console from the host or an SSH tunnel. Set to the public URL only if your ingress allowlists the path.
KC_BOOTSTRAP_ADMIN_USERNAME admin Keycloak admin (used by the realm-reconcile sidecar and the admin CLI).
KC_BOOTSTRAP_ADMIN_PASSWORD unset Keycloak admin password. Secret. Required.
KC_DB_PASSWORD unset Postgres role password for Keycloak's own schema. Secret. Required.

Identity — mode C: direct external OIDC IdP

Set PRECIS_AUTH_MODE=oidc and drop bundled-keycloak from COMPOSE_PROFILES. Per-IdP walkthroughs: external IdP recipes.

Variable Default Purpose
OIDC_ISSUER unset Your IdP's issuer URL. Required in mode C.
OIDC_JWKS_URL unset JWKS endpoint for your IdP's issuer. Required in mode C.
OIDC_AUDIENCE ${PRECIS_BASE_URL}/mcp Audience the /mcp resource requires, verbatim.
OIDC_CLIENT_ID unset Your pre-registered client.
OIDC_CLIENT_SECRET unset Client secret for confidential clients. Secret.

Excel add-in (optional)

The Excel add-in is a separate public OAuth client (PKCE, no secret) of the /mcp endpoint. These knobs are advertised in the /mcp host's protected-resource metadata so the add-in auto-configures from the /mcp URL alone — leave them all unset and the add-in surface is simply off. The two token-shape knobs are independent; set them to match your IdP (see external IdP recipes).

Variable Default Purpose
KC_ENABLE_EXCEL_ADDIN unset Mode B: set true to provision and advertise the bundled-Keycloak precis-excel-addin public client (the realm reconcile creates it; absence deletes it).
EXCEL_ADDIN_CLIENT_ID unset Mode C: the public client_id you registered in your external IdP for the add-in. Wins over the mode-B default when set.
EXCEL_ADDIN_SCOPE openid Exact scope the add-in requests (advertised in the protected-resource metadata as precis_excel_scopes). Keep the default for an IdP that binds the audience via the resource indicator (Keycloak/Auth0/Ping). For an IdP that binds it via a scope (Entra/Okta), set the full request scope, e.g. openid profile email offline_access api://<app-id>/access_as_user (include offline_access so the add-in gets a refresh token, and profile email so the task pane can show the signed-in user's name/email instead of an opaque subject id).
EXCEL_ADDIN_RESOURCE_INDICATOR true Whether the add-in sends the RFC 8707 resource parameter. Leave true for the MCP-conformant shape; set false for an AS that rejects it (Entra's v2 endpoint returns AADSTS901002).
EXCEL_ADDIN_DIST_DIR excel-addin/dist Directory of the built add-in bundle the server hosts at /excel (with a host-templated manifest at /excel/manifest.xml). The published image bakes this directory during the Docker build. Override only when serving a separately built bundle. When the add-in is enabled and this directory exists, the server serves the bundle same-origin with /mcp, so no /mcp CORS_ORIGINS entry is needed.

Your model

Variable Default Purpose
PRECIS_INSTANCE_DIR the bundled demo instance/ Compose bundles only: host path mounted read-only over the container's instance/ (catalogue/, semantic/, integrations/, scenarios.yml). Outside Docker the instance directory is the source checkout's instance/.
PRECIS_INTEGRATIONS_ROOT instance/integrations Override for the integrations registry root alone.
COMPANY_NAME your organisation Name woven into the MCP instructions served to clients.
INSPECTION_ROW_CAP 10000 Hard cap on rows returned by row-level inspection.
USER_DATA_DIR /data/users Per-user file storage root. The Compose bundle mounts a persistent user_data named volume here; only advanced bind-mount deployments need to manage host-path ownership.

Ingestion

Per-source database credentials

A Source names a secret_ref; credentials are read from <SECRET_REF>_* (uppercased). The suffixes depend on the source kind:

  • postgres_HOST, _DATABASE, _USER, _PASSWORD (secret), _PORT (default 5432), _SSLMODE, _SSLROOTCERT
  • mssql — as postgres, plus _DRIVER (default ODBC Driver 18 for SQL Server); default _PORT is 1433
  • snowflake_ACCOUNT, _USER, _PASSWORD, _DATABASE, _WAREHOUSE, _SCHEMA (optional), _ROLE (optional)
  • bigquery_PROJECT_ID, _DATASET_ID (optional), _CREDENTIALS_JSON (service-account key JSON as a value secret, *_FILE-compatible; omit for ADC) — see the BigQuery worked example
  • databricks_SERVER_HOSTNAME, _HTTP_PATH, _ACCESS_TOKEN, _CATALOG (optional), _SCHEMA (optional)

Example: secret_ref: customer_pg (kind postgres) → CUSTOMER_PG_HOST, CUSTOMER_PG_DATABASE, CUSTOMER_PG_USER, CUSTOMER_PG_PASSWORD, … The non-Postgres kinds need their optional driver extra (pip install 'precis-mcp[snowflake]'). See Ingestion & data sources.

In both compose bundles the CUSTOMER_PG_* variables default to the bundled Postgres and the fpa_actuals mock-source database the sample-data generator populates; override them in the environment (or deploy/.env) to point the demo instance's bindings at your own warehouse.

S3-compatible object store (optional — install the s3 extra: pip install ".[s3]")

Variable Default Purpose
PRECIS_S3_BUCKET unset Bucket name; setting it enables the backend.
PRECIS_S3_PREFIX empty Key prefix within the bucket.
PRECIS_S3_REGION unset Region.
PRECIS_S3_ENDPOINT_URL unset Custom endpoint (MinIO and other S3-compatibles).
PRECIS_S3_ACCESS_KEY_ID / PRECIS_S3_SECRET_ACCESS_KEY unset Credentials. Secret.

SFTP drop folder (optional — install the sftp extra: pip install ".[sftp]")

Variable Default Purpose
PRECIS_SFTP_HOST unset Host; setting it enables the backend.
PRECIS_SFTP_USER empty Username.
PRECIS_SFTP_PASSWORD unset Password (or use PRECIS_SFTP_KEY_PATH). Secret.
PRECIS_SFTP_KEY_PATH unset Private-key file for key-based auth.
PRECIS_SFTP_PORT 22 Port.
PRECIS_SFTP_PREFIX empty Remote path prefix.
PRECIS_SFTP_KNOWN_HOSTS unset Path to a known_hosts file covering the host (generate with ssh-keyscan -p <port> <host>). In the compose bundle, bind-mount the file and point this at the container path.
PRECIS_SFTP_HOST_KEY unset The server's public host key inline, <key-type> <base64> (one line of ssh-keyscan output; the hostname field is tolerated). Alternative to a known_hosts file.

Host-key verification is mandatory: set PRECIS_SFTP_KNOWN_HOSTS or PRECIS_SFTP_HOST_KEY. With neither, the SFTP store refuses to start — connecting unverified would let a man-in-the-middle capture the credentials and the data.

Daemons

Variable Default Purpose
PRECIS_SCHEDULER_INTERVAL_SECONDS 60 Tick interval of the binding scheduler.
PRECIS_WATCHER_INTERVAL_SECONDS 30 Tick interval of the drop-folder watcher.

Backups (optional — COMPOSE_PROFILES += backup)

The backup configuration itself is declarative — instance/backup.yml, see Backups & restore. The environment carries only the pieces that can't live in YAML:

Variable Default Purpose
PRECIS_BACKUP_CH_CONFIG unset Host path of the rendered ClickHouse backup-disk config (written by backup init), mounted into the clickhouse service.
BACKUP_WRITER_ACCESS_KEY_ID / BACKUP_WRITER_SECRET_ACCESS_KEY unset S3 writer credential (no delete permission on a WORM bucket). Secret. Names follow credentials.writer in backup.yml.
BACKUP_READER_ACCESS_KEY_ID / BACKUP_READER_SECRET_ACCESS_KEY unset S3 reader credential, used by restore/list. Secret.
BACKUP_ALERT_WEBHOOK_URL unset POSTed on any non-success run outcome (JSON: run id, outcome, failed stores).
PRECIS_BACKUP_CH_TIMEOUT 3600 ClickHouse BACKUP/RESTORE command timeout (seconds).

Local-volume destinations need none of the credentials.

Telemetry (optional — install the telemetry extra: pip install ".[telemetry]")

Variable Default Purpose
PRECIS_TELEMETRY_ENABLED false Master switch for OpenTelemetry instrumentation.
PRECIS_TELEMETRY_CAPTURE_CONTENT false Also capture request/response content on spans. Privacy-sensitive — leave off unless your collector is trusted with data.
OTEL_SERVICE_NAME precis-mcp Service name on emitted spans.
OTEL_EXPORTER_OTLP_ENDPOINT http://otel-collector:4318 OTLP HTTP receiver.
OTEL_PYTHON_EXCLUDED_URLS unset URL patterns excluded from HTTP auto-instrumentation.
OTEL_RESOURCE_ATTRIBUTES unset Extra key=value resource attributes, passed through.

What each surface requires

Single-user local trial (deploy/docker-compose.local.yml): ENABLE_MCP_DEV_SERVER=1, MCP_DEV_KEY, and the CH* connection (the local bundle wires the bundled ClickHouse for you). Everything else is optional.

Multi-user bundle (deploy/docker-compose.yml): the CH* and PG* connections, PRECIS_BASE_URL, and one identity mode — bundled Keycloak (KC_BOOTSTRAP_ADMIN_PASSWORD, KC_DB_PASSWORD) or external OIDC (OIDC_ISSUER + client registration).