Configure self-managed Context Gateway

Prepare Helm values, file references, credential storage, the database registry, Context Surface databases, and optional features for Context Gateway.

The chart reads non-secret settings from Helm values and every credential from a mounted file. Prepare gateway-values.yaml and the Secrets it references before you deploy.

Helm values

Value Purpose
tenantId The deployment's tenant. Must equal the Identity Service's single tenant ID.
publicBaseURL The Data Plane's public origin, used in every Gateway's mcpEndpoint.
dataplane.ingress An optional Ingress for the Data Plane, off by default. When on, hosts must include the publicBaseURL host and route / with pathType: Prefix, annotations must not rewrite paths, and for an https:// origin a tls entry with a secretName must cover that host. Otherwise rendering fails.
identityService.baseURL The Identity Service runtime API that checks agent keys.
identityService.allowInsecureTransport true for an in-cluster http:// Identity Service URL. Default false.
profile prod (default) or dev logging.
security.profile standard (default) or fips. See Configure security and tracing.
imagePullSecrets Credentials for a private registry.
controlplane.config, dataplane.config Application settings for each plane. They default to {}, so the image's defaults apply.

Start with the complete deployment values example, then apply the settings you need from this page.

File references

Each credential has its own reference. Point it at a Kubernetes Secret key with existingSecret and secretKey, or at a Secrets Store CSI (Container Storage Interface) Driver file with secretProviderClass and fileName. Change a reference's optional checksum to roll out both planes after the file changes.

Helm reference File contents Used by
metadataDB YAML with metadata_db.urls. Both planes
credentialStorage.redis.connection YAML with credential_storage.redis.urls. Both planes
credentialStorage.redis.keyring Directory of base64-encoded 32-byte Advanced Encryption Standard (AES) keys. Both planes
credentialStorage.vault.credentials.controlplane YAML with credential_storage.vault.token, with write and delete access. Control Plane
credentialStorage.vault.credentials.dataplane YAML with credential_storage.vault.token, with read access. Data Plane
databaseConnections[] YAML with databases.<id>.urls. Both planes
controlplane.adminToken The admin token operators send to the Control Plane. Control Plane
controlplane.internalToken The token Identity Service sends to the grant callback. Control Plane
dataplane.runtimeToken The token the Data Plane sends to Identity Service. Data Plane
license The license file as issued. Both planes
tls.caBundle A PEM-encoded certificate authority (CA) bundle. Both planes

The admin, internal, and runtime tokens must be distinct. Keep the admin token, the internal token, and the Vault writer token out of every CSI class the Data Plane mounts.

Credential storage

credentialStorage.provider Configuration
redis (default) A credential Redis connection and a keyring shared by both planes. credentialStorage.redis.keyFiles maps each key ID to a file in the keyring, and activeKeyId names the key for new writes.
vault Separate writer and reader tokens for the Control Plane and Data Plane.
aws_secrets_manager Separate Identity and Access Management (IAM) roles for each plane through workload identity.

Database registry

Register every database a Gateway uses under the same ID on both planes: Context Surface databases and Gateway databases. Put display names in shared.config.databases and connection URLs in a databaseConnections file.

shared:
  config:
    databases:
      clinics: {name: Clinic directory}
      results: {name: Gateway database}
databaseConnections:
  - existingSecret: gateway-database-connections
    secretKey: config.yaml

Both planes probe every entry at startup. An entry that does not answer does not stop a plane. The plane logs Gateway database did not answer at startup with the entry's database_id and starts.

Default databases

An on-prem deployment uses two databases from the registry, and each has its own job:

Database Holds Written by
Gateway database Cached results and compression handles. Only the Gateway.
Surface database The customer data that Context Surfaces read. Never the Gateway.

Name a default for each so that administrators do not repeat the ID on every request. Both defaults are optional, and both planes read them:

shared:
  config:
    databases:
      gateway-db: {name: Gateway database}
      surface-db: {name: Surface database}
databaseConnections:
  - existingSecret: gateway-database-connections
    secretKey: config.yaml
defaultDatabases:
  gatewayDb: gateway-db
  surfaceDb: surface-db

The chart renders these as default_databases.gateway and default_databases.surface in the shared configuration. Each must name a databases entry, or both planes refuse to start.

Value Used when Without it
defaultDatabases.gatewayDb A Gateway create sends no databaseId. The response's databaseBinding.databaseId shows the resolved database, and cache and compression default to ENABLED as if you had sent it. An explicit databaseId always wins. A Gateway created without databaseId has no database, so the cache and compression are off.
defaultDatabases.surfaceDb A Context Surface create sends no contextSurface.databaseId. An explicit ID always wins. That create returns 400 on contextSurface.databaseId.

Redis Cloud has no defaults and always requires the database ID.

Gateway database requirements

The Gateway database should use maxmemory-policy noeviction, and compression also needs the JSON module. The checks differ by where they run:

  • At startup, the Data Plane checks the default Gateway database. With compression.enabled: true it fails to start when the database does not use noeviction or has no JSON module. Otherwise it logs a warning. An unreachable default Gateway database only logs a warning at startup.
  • When you turn compression on through the API, the Control Plane checks the Gateway database. The request returns 400 on the compression field, with an errors[] entry whose pointer is /compression and whose detail explains the problem when the database cannot hold handles, and 503 when it cannot be reached. The same check runs when an update changes databaseId while compression stays ENABLED.
  • A Gateway create that omits compression never fails on this check. When the database cannot hold handles or cannot be reached, the Gateway is stored with compression set to DISABLED, and the Control Plane logs why.

Size the Gateway database for the rate of stored results, their stored size, and their time to live (TTL). Compression ratios vary with the result, so measure stored bytes for your workload rather than assuming a fixed ratio. Account for cache entries and handles separately.

The cache applies its memory share and 90% guard when the eviction policy is noeviction or unreported. Handles require an explicitly reported noeviction policy before applying their share and headroom checks. An unreported policy disables handle creation.

By default, cache entries can use 40% of the Gateway database's maxmemory and handles can use 50%. cache.max_memory_share and compression.max_memory_share must each be positive and their sum must not exceed 0.95, even when a feature is off. A separate database-wide guard stops new writes above 90% of maxmemory. These are admission limits, not Redis eviction policies. Use maxmemory-policy noeviction and set a finite, positive Redis maxmemory: when maxmemory is 0 (unlimited), neither the shares nor the 90% guard limits writes.

When a limit is reached, the cache serves the Upstream result without storing a new entry. Automatic handle capture can return the result inline. An explicit run_tool_as_handle request that cannot store its result returns a tool error instead of the whole result. Release handles you no longer need, shorten TTLs, or increase database capacity. See Tool call failures.

Do not point both defaults at the same Redis when compression is on. noeviction would then apply to your customer data. The Data Plane logs a warning at startup when the two defaults share an endpoint.

For how to size the Gateway database and the Redis versions it needs, see Redis databases.

Context Surface databases

A Context Surface stores only its database ID. Give each plane its own Redis user on the database, as listed in Redis users for Surface databases. The databaseConnections registry is shared by both planes, so supply each plane's URL for that database ID through an overlay. Put the Control Plane's login in a controlplane.overlays Secret and the Data Plane's login in a dataplane.overlays Secret. Overlays load last and override the registry's connection settings:

databases:
  clinics:
    urls:
      - rediss://<plane-user>:<password>@<host>:<port>

Reference each Secret from controlplane.overlays or dataplane.overlays with existingSecret and secretKey, as in the embedding example below. To change a password, update the Secret and restart both planes.

Semantic and hybrid search tools embed the agent's text before they search. Configure an OpenAI-compatible embedding service in a mounted Data Plane overlay. Save a restricted local file named embedding-secret.yaml:

context_surface:
  embedding:
    endpoint: https://api.openai.com/v1
    model: text-embedding-3-small
    api_key: <embedding-provider-api-key>

Omit api_key if your provider does not require it. Create a Secret from that file:

kubectl -n <namespace-name> create secret generic gateway-embedding --from-file=config.yaml=embedding-secret.yaml

Reference it in your Helm values:

dataplane:
  overlays:
    - existingSecret: gateway-embedding
      secretKey: config.yaml

Keep the real key out of gateway-values.yaml and source control. The overlay contains application settings under context_surface, without a Helm dataplane.config wrapper.

Without an embedding service, every other tool still works, and semantic or hybrid search calls fail with embedding_unavailable. The embedding client ignores proxy variables and dials the endpoint directly, and with an API key set every endpoint must use HTTPS.

The Data Plane keeps at most two clients for each Surface database. One Surface database sees at most 2 × client.pool_size × Data Plane replicas connections, so set context_surface.client_pool.client.pool_size explicitly, in a Data Plane overlay like the embedding one.

Cache and compression

Both features are off by default. Turn them on in the Data Plane configuration:

dataplane:
  config:
    cache:
      enabled: true
    compression:
      enabled: true
      ttl: 15m
Setting Default Meaning
cache.max_entry_bytes 262144 The largest result the cache stores, in bytes.
cache.max_memory_share 0.4 Fraction of Gateway database maxmemory available to cache entries.
compression.max_memory_share 0.5 Fraction of Gateway database maxmemory available to handles.
compression.ttl 15m How long a handle lives. At most 24h. A tool policy can override it.
compression.inline_max_bytes 32768 Results above this size become handles.
compression.max_capture_bytes 8388608 Maximum captured result size in bytes. Automatic capture can return oversized results inline. Explicit capture fails if no handle can be stored.
compression.preview_items, compression.preview_bytes 3, 2048 The size of a handle stub's preview.
compression.max_surface_items 10000 Maximum records collected for a Surface handle.
compression.max_paged_capture_bytes_in_flight 67108864 Per-process byte budget for Surface pages being collected across captures.
compression.max_concurrent_paged_captures 4 Maximum captures collecting Surface continuation pages at once per process.
compression.paged_capture_wait 2s Maximum wait for a paging slot.
compression.paged_capture_time_budget 2s Total paging budget, including the wait for a slot. The request deadline can shorten it.

These settings turn each feature on for the deployment. Each Gateway then has its own cache and compression settings, and a feature serves a Gateway only when both the deployment and the Gateway turn it on. Both need the Gateway to have a database, from its databaseId or from the default Gateway database.

The cache still needs a policy for each tool. Compression applies to every eligible result on a Gateway that has it on, unless a tool's policy opts out. See Turn the cache and compression on or off.

Surface filter and text queries can collect continuation pages into a handle. Capture stops at the row, byte, time, or concurrency limit and returns a partial handle when it has a storable partial result. Read its warning before treating its count as the complete query count. Semantic and hybrid top-K queries are not continued. See Compression.

Bound Data Plane memory

Set dataplane.resources.limits.memory for each pod. At startup, dataplane.config.memory_limit_ratio sets the Go runtime's soft memory limit to that fraction of the container limit. The default is 0.7. An explicit GOMEMLIMIT environment value takes precedence. Without a container memory limit, the automatic setting does not apply. This soft limit leaves room for memory outside the Go heap and does not replace the container limit.

Cache metadata resolutions

The metadata resolution cache is off by default. Enable it only after every Control Plane instance supports invalidating Gateway resolutions after Upstream mutation attempts. Roll out all writers first. Credentials and caller permissions are still checked on every invocation.

dataplane:
  config:
    metadata_cache:
      resolution:
        enabled: true
        max_age: 30s

max_age defaults to 30s and must be positive. It bounds stale resolutions when invalidation fails. Keep this configuration under dataplane.config, not shared.config.

Trust a private CA

Set tls.caBundle to a PEM bundle, or mount a single certificate under /etc/ssl/certs with the chart's examples/certificates.yaml. Restart both planes after you rotate a certificate.

Configure security and tracing

security.profile: fips runs the Federal Information Processing Standards (FIPS)-oriented profile. Both planes then reject plaintext Redis URLs and disabled certificate verification, including in the registered databases.

Both planes serve Prometheus metrics at /metrics. Set shared.config.opentelemetry.enable_tracing: true and an OpenTelemetry Protocol (OTLP) endpoint for traces.

Scale and schedule the planes

Each plane starts one replica. Set replicaCount, or turn on autoscaling, with resources, nodeSelector, tolerations, and affinity under controlplane and dataplane. Autoscaling is off by default, needs Metrics Server, and needs resources.requests.cpu or resources.requests.memory for each target it uses. Leave headroom for old and new pods during upgrades.

Set podDisruptionBudget.enabled: true to give each plane that keeps more than one pod a PodDisruptionBudget with maxUnavailable: 1. dataplane.strategy sets the Data Plane Deployment's rollout strategy.

The startupProbe, livenessProbe, and readinessProbe of each plane use /health/liveness and /health/readiness by default, and accept native Kubernetes probe fields. Set a probe to null to turn it off. The default startup probe allows 150 seconds before liveness checks begin.

RATE THIS PAGE
Back to top ↑