Skip to content

Settings reference

All configuration is environment variables prefixed MEMCOVE_, loaded from the environment or a .env file. The env var is MEMCOVE_ + the field name uppercased (e.g. portMEMCOVE_PORT). dict and list fields are parsed as JSON (e.g. MEMCOVE_SHARED_SCHEMAS=["ref_market"]).

The defaults target the local Docker stack, so local development needs no changes.

MCP server

Setting Type Default Notes
MEMCOVE_HOST str 0.0.0.0 bind address
MEMCOVE_PORT int 8090 MCP Streamable HTTP port

Iceberg REST catalog

Setting Type Default
MEMCOVE_ICEBERG_REST_URI str http://localhost:8181
MEMCOVE_ICEBERG_WAREHOUSE str s3://warehouse/
MEMCOVE_ICEBERG_CATALOG_NAME str memcove

Object store (S3 / MinIO)

Setting Type Default Notes
MEMCOVE_S3_ENDPOINT str http://localhost:9000 MinIO locally; real S3 in prod
MEMCOVE_S3_REGION str us-east-1
MEMCOVE_S3_ACCESS_KEY str | None minio clear (empty) to use the AWS default credential chain — IRSA / instance profile / STS
MEMCOVE_S3_SECRET_KEY str | None minio12345 clear alongside the access key for keyless auth
MEMCOVE_S3_PATH_STYLE bool true
MEMCOVE_WAREHOUSE_BUCKET str warehouse
MEMCOVE_STAGING_BUCKET str memcove-staging upload staging; accepts bucket or bucket/sub/path to scope uploads to a prefix
MEMCOVE_ARTIFACTS_BUCKET str memcove-artifacts exports; accepts bucket or bucket/sub/path to scope exports to a prefix

Trino (read / derive / export engine)

Setting Type Default Notes
MEMCOVE_TRINO_HOST str localhost
MEMCOVE_TRINO_PORT int 8080
MEMCOVE_TRINO_USER str memcove service principal (connect identity when not impersonating)
MEMCOVE_TRINO_CATALOG str iceberg
MEMCOVE_TRINO_HTTP_SCHEME str http set https for a TLS-fronted Trino
MEMCOVE_TRINO_IMPERSONATION bool false connect as the tenant so your Trino access control applies per tenant. See Authentication & tenancy.
MEMCOVE_TRINO_SESSION_PROPERTIES dict {} resource caps etc., e.g. {"query_max_run_time":"60s"}

Arrow Flight (streaming data plane)

Setting Type Default Notes
MEMCOVE_FLIGHT_HOST str 0.0.0.0 bind address
MEMCOVE_FLIGHT_PORT int 8815
MEMCOVE_FLIGHT_ADVERTISE_URI str grpc://localhost:8815 what clients are told to dial
MEMCOVE_FLIGHT_TICKET_SECRET str dev-insecure-change-me HMAC signing secret — override in any real deployment.
MEMCOVE_FLIGHT_TICKET_TTL_SECONDS int 300 signed ticket lifetime

Change the ticket secret before you expose the Flight port

MEMCOVE_FLIGHT_TICKET_SECRET defaults to a known, insecure value. Anyone who can reach the Flight port with the default secret can forge tenant-scoped tickets. Set a strong random value in any real deployment; the Flight server logs a loud warning if you don't.

Registry (Postgres / SQLite / MySQL)

The metadata registry runs on any of three backends, selected by the DSN scheme. See registry backends for the trade-offs.

Setting Type Default Notes
MEMCOVE_REGISTRY_DSN str | None None takes precedence over PG_DSN. Scheme selects the backend: postgresql://…, sqlite:///memcove.db (or sqlite:// in-memory), mysql://… (needs the mysql extra)
MEMCOVE_PG_DSN str postgresql://memcove:memcove@localhost:5433/memcove fallback when REGISTRY_DSN is unset; host port 5433 avoids clashing with a local pg on 5432
MEMCOVE_PG_POOL_MIN_SIZE int 1 connections kept warm (Postgres pool)
MEMCOVE_PG_POOL_MAX_SIZE int 10 pool grows to this under load
MEMCOVE_PG_POOL_TIMEOUT float 10.0 seconds to wait for a free connection before erroring

Reconciler / self-healing

The reconciler diffs the Iceberg catalog against the registry to backfill missing rows and drop dangling ones; deletion is fail-safe. Tune the guardrails:

Setting Type Default Notes
MEMCOVE_RECONCILE_MIN_ABSENT_SWEEPS int 2 a row must be absent across this many consecutive sweeps before deletion
MEMCOVE_RECONCILE_DELETION_CAP_RATIO float 0.25 a sweep that would delete more than this fraction of a namespace aborts + alerts
MEMCOVE_RECONCILE_DELETION_CAP_MIN int 3 the ratio cap only applies once a sweep would delete more than this many rows

Guardrails

Setting Type Default Notes
MEMCOVE_PREVIEW_ROW_CAP int 1000 max rows returned by query_memory / preview
MEMCOVE_INLINE_BYTES_CAP int 8388608 8 MiB max for inline ingest
MEMCOVE_EXPORT_ROW_CAP int 5000000 safety cap for artifact export
MEMCOVE_PRESIGN_TTL_SECONDS int 3600 presigned URL lifetime

Tenancy

Setting Type Default Notes
MEMCOVE_TENANT_HEADER str x-memcove-tenant direct-mode tenant header
MEMCOVE_DEFAULT_TENANT str default fallback when the header is absent
MEMCOVE_TENANT_SUBJECT_HEADER str "" e.g. x-auth-subject; enables the fail-closed provisioning map
MEMCOVE_TENANT_GROUP_HEADER str "" e.g. x-auth-groups (comma-separated)
MEMCOVE_TENANT_MAP dict {} subject/group → internal tenant id

See Authentication & tenancy for how these interact.

Native OAuth 2.1 (resource server)

Off by default (trusted-header / proxy model). When enabled, Memcove validates bearer JWTs itself against the IdP's JWKS so a client like Claude can connect directly — see Native OAuth.

Setting Type Default Notes
MEMCOVE_OAUTH_ENABLED bool false turn on the native resource server
MEMCOVE_OAUTH_ISSUER str "" IdP issuer URL, e.g. https://keycloak.example.com/realms/memcove
MEMCOVE_OAUTH_JWKS_URI str "" optional; derived from the issuer's OIDC discovery when empty
MEMCOVE_OAUTH_AUDIENCE str "" expected aud; empty = skip the audience check. Set to match your IdP's token audience
MEMCOVE_OAUTH_REQUIRED_SCOPES list [] scopes every token must carry, e.g. ["memcove.use"]
MEMCOVE_OAUTH_ALGORITHMS list ["RS256"] accepted JWT signing algorithms
MEMCOVE_OAUTH_TENANT_CLAIM str sub claim used as the tenant id when the identity isn't in TENANT_MAP (map wins, fail-closed, when set)
MEMCOVE_PUBLIC_URL str "" this server's public URL (OAuth resource id); falls back to http://host:port

Shared reference plane

Setting Type Default Notes
MEMCOVE_SHARED_SCHEMAS list ["ref_market"] read-only schemas every tenant may query; never rewritten to a tenant namespace

Scratchpad plane

An optional fast, small, ephemeral store backed by DuckDB behind Trino — see Scratchpad. Off by default; needs Trino ≥ 480.

Setting Type Default Notes
MEMCOVE_SCRATCH_ENABLED bool false enable target=scratch and the scratch.<label> SQL alias
MEMCOVE_SCRATCH_CATALOG_MODE str shared shared (one static DuckDB catalog, schema-per-tenant) or per_tenant (a scratch_<tenant> catalog via Trino dynamic catalog management)
MEMCOVE_SCRATCH_CATALOG str scratch catalog name in shared mode
MEMCOVE_SCRATCH_CATALOG_PREFIX str scratch per_tenant: catalog is <prefix>_<tenant>
MEMCOVE_SCRATCH_DUCKDB_DIR str /data/scratch per_tenant: Trino-side dir (on a shared volume) for the <tenant>.duckdb files

Ingest allowlist

Setting Type Default Notes
MEMCOVE_ALLOWED_S3_INGEST_PREFIXES list [] agent s3_parquet URIs must match one of these prefixes; empty = disabled (fail closed)

Full .env.example

The shipped example, annotated:

.env.example
# --- Memcove configuration (copy to .env) ---

# MCP server
MEMCOVE_HOST=0.0.0.0
MEMCOVE_PORT=8090

# Iceberg REST catalog
MEMCOVE_ICEBERG_REST_URI=http://localhost:8181
MEMCOVE_ICEBERG_WAREHOUSE=s3://warehouse/
MEMCOVE_ICEBERG_CATALOG_NAME=memcove

# Object store (MinIO locally; real S3 in prod). Leave the access/secret keys
# EMPTY to use the AWS default credential chain (IRSA / instance profile / STS)
# instead of static keys — the recommended setup on AWS.
MEMCOVE_S3_ENDPOINT=http://localhost:9000
MEMCOVE_S3_REGION=us-east-1
MEMCOVE_S3_ACCESS_KEY=minio
MEMCOVE_S3_SECRET_KEY=minio12345
MEMCOVE_S3_PATH_STYLE=true
# Buckets used by the data plane. STAGING/ARTIFACTS accept either a bare bucket or a
# bucket with a sub-path (e.g. my-bucket/teams/data-eng) to scope uploads/exports to a
# prefix your team owns instead of the bucket root.
MEMCOVE_WAREHOUSE_BUCKET=warehouse
MEMCOVE_STAGING_BUCKET=memcove-staging
MEMCOVE_ARTIFACTS_BUCKET=memcove-artifacts
# MEMCOVE_STAGING_BUCKET=my-bucket/teams/data-eng
# MEMCOVE_ARTIFACTS_BUCKET=my-bucket/teams/data-eng

# Trino (read / derive / export engine)
MEMCOVE_TRINO_HOST=localhost
MEMCOVE_TRINO_PORT=8080
MEMCOVE_TRINO_USER=memcove                # service principal (connect identity when not impersonating)
MEMCOVE_TRINO_CATALOG=iceberg
MEMCOVE_TRINO_HTTP_SCHEME=http            # set https for a TLS-fronted Trino
# Defense-in-depth: connect to Trino AS the caller's tenant so the operator's own
# Trino access control applies per tenant. Requires impersonation rights on the
# service principal + a configured grant backend. Off = single identity (dev).
MEMCOVE_TRINO_IMPERSONATION=false
# Session properties applied to every data connection (resource caps etc.) — generic
# passthrough; set whatever your Trino version supports. JSON object.
MEMCOVE_TRINO_SESSION_PROPERTIES={}
# e.g. {"query_max_run_time":"60s","query_max_scan_physical_bytes":"10GB"}

# Arrow Flight streaming data plane (M3)
MEMCOVE_FLIGHT_HOST=0.0.0.0
MEMCOVE_FLIGHT_PORT=8815
MEMCOVE_FLIGHT_ADVERTISE_URI=grpc://localhost:8815
# HMAC secret for signing Flight tickets/descriptors so a client cannot forge one for
# another tenant. MUST be overridden in any real deployment (default is insecure).
MEMCOVE_FLIGHT_TICKET_SECRET=dev-insecure-change-me
MEMCOVE_FLIGHT_TICKET_TTL_SECONDS=300   # signed tickets expire after this many seconds

# Control-plane registry. The DSN scheme selects the backend:
#   postgresql://…            (production default, pooled)
#   sqlite:///memcove.db      (embedded file — zero-setup local dev, no container)
#   sqlite://                 (in-memory)
#   mysql://user:pass@host/db (needs the `mysql` extra: pip install memcove[mysql])
# MEMCOVE_REGISTRY_DSN takes precedence; MEMCOVE_PG_DSN is kept for compatibility.
# (Host port 5433 avoids clashing with a local postgres on 5432.)
MEMCOVE_PG_DSN=postgresql://memcove:memcove@localhost:5433/memcove
# MEMCOVE_REGISTRY_DSN=sqlite:///memcove.db
# Connection pool sizing (min kept warm, grows to max under load; timeout in seconds
# to wait for a free connection before erroring)
MEMCOVE_PG_POOL_MIN_SIZE=1
MEMCOVE_PG_POOL_MAX_SIZE=10
MEMCOVE_PG_POOL_TIMEOUT=10.0

# Reconciler / read-repair (self-healing). Diffs the Iceberg catalog against the registry
# to backfill missing rows and drop dangling ones; deletion is fail-safe.
MEMCOVE_RECONCILE_MIN_ABSENT_SWEEPS=2    # sweeps a row must be absent before deletion
MEMCOVE_RECONCILE_DELETION_CAP_RATIO=0.25 # abort a sweep that would delete >this fraction of a namespace
MEMCOVE_RECONCILE_DELETION_CAP_MIN=3     # ...but only once it would delete more than this many rows

# Guardrails
MEMCOVE_PREVIEW_ROW_CAP=1000
MEMCOVE_INLINE_BYTES_CAP=8388608        # 8 MiB max for inline ingest
MEMCOVE_EXPORT_ROW_CAP=5000000          # safety cap for artifact export
MEMCOVE_PRESIGN_TTL_SECONDS=3600

# Tenancy. How a caller becomes an internal tenant (applies to both the proxy-header and
# native-OAuth paths):
#   auto    (default) trust the tenant header (dev) / token claim, or the map if configured
#   shared  everyone -> ONE tenant (MEMCOVE_SHARED_TENANT, else default). No isolation.
#   private every verified identity -> its OWN tenant, hashed so users never collide.
#           Needs a trusted identity: MEMCOVE_TENANT_SUBJECT_HEADER (proxy) or OAuth claim.
#   mapped  explicit MEMCOVE_TENANT_MAP, fail-closed (unmapped identities rejected).
MEMCOVE_TENANT_MODE=auto
MEMCOVE_TENANT_HEADER=x-memcove-tenant   # "auto" dev path: client-settable tenant
MEMCOVE_DEFAULT_TENANT=default
MEMCOVE_SHARED_TENANT=                    # "shared" mode target; empty => default
# Identity sources for mapped/private on the proxy path (your auth proxy sets these; the
# raw tenant header is NOT trusted in those modes).
MEMCOVE_TENANT_SUBJECT_HEADER=          # e.g. x-auth-subject
MEMCOVE_TENANT_GROUP_HEADER=            # e.g. x-auth-groups (comma-separated)
MEMCOVE_TENANT_MAP={}                   # "mapped": JSON {"oidc|abc":"acme","team-research":"research"}

# Native OAuth 2.1 (MCP resource server). Off by default (trusted-header / proxy model).
# When enabled, Memcove validates bearer JWTs itself against the IdP's JWKS, so a client
# like Claude can connect directly — no auth proxy needed. Provider-agnostic; Keycloak is
# the documented default (see deploy/keycloak/ and docs/configuration/auth.md).
MEMCOVE_OAUTH_ENABLED=false
MEMCOVE_OAUTH_ISSUER=                    # e.g. https://keycloak.example.com/realms/memcove
MEMCOVE_OAUTH_JWKS_URI=                  # optional; derived from the issuer's OIDC discovery if empty
# Expected `aud`; EMPTY (default) skips the audience check. Set it to match your IdP's
# token audience to enforce it (the Keycloak worked example issues `aud=memcove`).
MEMCOVE_OAUTH_AUDIENCE=
MEMCOVE_OAUTH_REQUIRED_SCOPES=[]        # JSON list, e.g. ["memcove.use"]
MEMCOVE_OAUTH_ALGORITHMS=["RS256"]      # accepted JWT signing algorithms
# Claim used as the tenant id when the identity isn't in MEMCOVE_TENANT_MAP (map wins and
# is fail-closed when set). e.g. sub, preferred_username, or a custom "tenant" claim.
MEMCOVE_OAUTH_TENANT_CLAIM=sub
MEMCOVE_PUBLIC_URL=                      # this server's public URL (OAuth resource id); defaults to http://host:port

# Shared read-only reference plane (the gateway). Schemas every tenant may SELECT
# from but none may write; not rewritten to the caller's namespace. JSON list.
MEMCOVE_SHARED_SCHEMAS=["ref_market"]

# Scratchpad plane: fast, small, ephemeral DuckDB store BEHIND Trino (needs Trino >= 480
# + a DuckDB catalog). Agents use target=scratch and the scratch.<label> SQL alias, and
# can JOIN scratch with lakehouse + reference in one query. See docs/concepts/scratchpad.md.
MEMCOVE_SCRATCH_ENABLED=false
# "shared"     — one static `scratch` DuckDB catalog you configure in Trino (schema-per-
#                tenant isolation; single-writer file shared across tenants).
# "per_tenant" — Memcove creates a scratch_<tenant> catalog per tenant via Trino dynamic
#                catalog management (catalog.management=dynamic); file-level isolation.
MEMCOVE_SCRATCH_CATALOG_MODE=shared
MEMCOVE_SCRATCH_CATALOG=scratch          # catalog name in shared mode
MEMCOVE_SCRATCH_CATALOG_PREFIX=scratch   # per_tenant: catalog is scratch_<tenant>
MEMCOVE_SCRATCH_DUCKDB_DIR=/data/scratch # per_tenant: Trino-side dir for <tenant>.duckdb files

# Ingest allowlist for agent-supplied s3_parquet URIs. Empty = feature DISABLED
# (fail closed). JSON list of permitted s3:// prefixes.
MEMCOVE_ALLOWED_S3_INGEST_PREFIXES=[]