## Host the MCP Gateway This guide explains how to deploy Frontegg's **MCP Gateway** Helm chart in your Kubernetes cluster. The chart packages two services that expose an MCP-compliant authorization and tool routing layer in front of your MCP servers. | Component | Role | | --- | --- | | `mcp-auth` | Serves OAuth, dynamic client registration, authorization, and callback endpoints for MCP clients. | | `mcp-gw` | Receives MCP requests and routes or authorizes them against Frontegg. | Both components share a Redis backend for token and session caching and are configured against a Frontegg vendor using region, client credentials, and `applicationId`. ### What the chart deploys For each release, the chart renders: - `Deployment/-mcp-gateway-auth`, which runs the `mcp-auth` image. - `Deployment/-mcp-gateway-gw`, which runs the `mcp-gw` image. - `Service/-mcp-gateway-auth`, a ClusterIP service on `mcpAuth.port`. - `Service/-mcp-gateway-gw`, a ClusterIP service on `mcpGw.port`. - A shared `ServiceAccount`, which is optional and enabled by default. - HorizontalPodAutoscaler resources per component, which are optional and disabled by default. > The chart does not ship an Ingress, API gateway, or other layer-7 router. You must front the two services with the path-matching ingress or API gateway you already use, such as NGINX Ingress, Traefik, Istio, Envoy, AWS ALB, GCP HTTPS LB, or Kong. See [Routing](#routing) for the path map you need to configure. ### Installation ```console helm repo add frontegg https://frontegg.github.io/helm-charts/ helm repo update helm upgrade --install mcp-gateway frontegg/mcp-gateway -f my-values.yaml ``` ### Minimal values.yaml Every value under `env` must be filled in for a working deployment. Names are camelCase in `values.yaml` and are translated to `UPPER_SNAKE_CASE` environment variables on both containers. For example, `vendorClientId` becomes `VENDOR_CLIENT_ID`. ```yaml env: # Redis shared cache for sessions and tokens. redisHost: my-redis.example.com redisPort: "6379" redisPassword: "" redisDb: "0" redisTlsEnabled: "true" cacheTtl: "300" # Frontegg vendor. fronteggRegion: "eu" # eu | us | ca | au | stg vendorClientId: "" vendorClientSecret: "" applicationId: "" # The hostname this gateway will be reached at, without scheme. fronteggMcpGwHost: "tenant.mcp-gw.frontegg.com" # The same host with scheme, used as the OAuth issuer and authorization URL. externalAuthorizationUrl: "https://tenant.mcp-gw.frontegg.com" # Your hybrid auth backend, with scheme. hybridAuthHost: "https://hybrid-auth.customer.example.com" ``` Optional environment values: | Key | Purpose | | --- | --- | | `approvalFlowWebhookEndpoint` | Webhook that receives tool-call approval requests. | | `eventWebhookProvider` | Where to forward audit events, such as `datadog`. | | `eventWebhookUrl` | Destination URL for the event webhook. | | `eventWebhookSecret` | Shared secret for signing event webhook deliveries. | These are commented out in the default `values.yaml`. Uncomment and set them if needed. ### Routing The two services must sit behind a path-matching HTTP router, such as an Ingress controller, service mesh gateway, or cloud API gateway. Configure it so that the following auth-related paths land on `mcp-auth` and everything else lands on `mcp-gw`: | Path | Target service | | --- | --- | | `/.well-known/*` | `-mcp-gateway-auth` | | `/authorize` | `-mcp-gateway-auth` | | `/integration-callback` | `-mcp-gateway-auth` | | `/security-stepup-verify` | `-mcp-gateway-auth` | | `/dcr/register` | `-mcp-gateway-auth` | | Everything else, `/` | `-mcp-gateway-gw` | Your router must satisfy these requirements: - **Order and specificity**: The auth paths above must win over the catch-all `/` route. Most ingress controllers do this automatically based on prefix length. On routers that match in declared order, declare the auth rules first. - **Host header preservation**: The `Host` header of the incoming request must match `env.fronteggMcpGwHost`. Both services use it to validate issuer URLs. If your gateway rewrites the upstream host, configure it to pass the original host. - **Single external hostname**: Both services are reached on the same external host. Only the path differs. ### Common configuration #### Image tags Image tags are pinned in the chart and are bumped by Frontegg as part of releasing a new chart version. Do not override `mcpAuth.tag` or `mcpGw.tag`. To pick up a new image, upgrade to a newer chart version: ```console helm repo update helm upgrade mcp-gateway frontegg/mcp-gateway -f my-values.yaml ``` #### Resources Each component has independent `resources` blocks under `mcpAuth.resources` and `mcpGw.resources`. Defaults are conservative, with 200m CPU and 256Mi memory requests and a 512Mi memory limit, and are suitable for low-traffic tenants. #### Autoscaling Autoscaling is disabled by default. Enable it per component: ```yaml autoscaling: mcpGw: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 70 mcpAuth: enabled: true minReplicas: 2 maxReplicas: 5 targetCPUUtilizationPercentage: 70 ``` When `autoscaling..enabled` is `true`, the Deployment's `replicas` field is omitted so the HPA can manage it. #### Probes All three probes, `liveness`, `readiness`, and `startup`, hit `GET /health` on port `http`. Override per component if your environment needs different timings: ```yaml mcpGw: livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 10 ``` #### Pod scheduling `nodeSelector`, `tolerations`, `affinity`, `podAnnotations`, `podLabels`, `podSecurityContext`, and `securityContext` are top-level values and apply to both deployments. There is no per-component override today. To schedule the two components differently, install the chart twice with a `nameOverride`. #### Service account A single ServiceAccount is shared by both deployments. To use an existing one: ```yaml serviceAccount: create: false name: my-existing-sa ``` ### Values reference | Key | Default | Description | | --- | --- | --- | | `mcpAuth.repository` | `527305576865.dkr.ecr.us-east-1.amazonaws.com/docker-hub/frontegg/hybrid-agen-co-auth` | `mcp-auth` image repository. Override only for private registry mirrors. | | `mcpAuth.tag` | Pinned by chart | Managed by Frontegg and bumped by chart release. Do not override. | | `mcpAuth.pullPolicy` | `IfNotPresent` | Image pull policy. | | `mcpAuth.replicaCount` | `1` | Used when `autoscaling.mcpAuth.enabled` is `false`. | | `mcpAuth.port` | `8080` | Service port. The container always listens on 8080. | | `mcpAuth.resources` | `requests: {cpu: 200m, memory: 256Mi}`, `limits: {memory: 512Mi}` | Default resource requests and limits. | | `mcpAuth.{liveness,readiness,startup}Probe` | `GET /health` on port `http` | Default health probes. | | `mcpGw.*` | Mirrors `mcpAuth.*` defaults | `mcp-gw` deployment configuration. | | `imagePullSecrets` | `[]` | List of `name` entries for private registry credentials. | | `nameOverride` and `fullnameOverride` | `""` | Name override values. | | `serviceAccount.create` | `true` | Whether to create a ServiceAccount. | | `serviceAccount.automount` | `true` | Whether to automount the ServiceAccount token. | | `serviceAccount.annotations` | `{}` | Useful for IRSA or Workload Identity. | | `serviceAccount.name` | `""` | If empty, defaults to the chart fullname. | | `service.type` | `ClusterIP` | Applied to both services. | | `podAnnotations` and `podLabels` | `{}` | Applied to both deployments' pod templates. | | `podSecurityContext` | `{}` | Pod-level security context. | | `securityContext` | `capabilities.drop: [NET_RAW]` | Container-level security context. | | `autoscaling.mcpAuth.enabled` | `false` | Whether autoscaling is enabled for `mcp-auth`. | | `autoscaling.mcpAuth.minReplicas` and `maxReplicas` | `1` and `100` | Replica bounds for `mcp-auth`. | | `autoscaling.mcpAuth.targetCPUUtilizationPercentage` | `80` | CPU utilization target. | | `autoscaling.mcpAuth.targetMemoryUtilizationPercentage` | Unset | Set to enable memory-based scaling. | | `autoscaling.mcpGw.*` | Mirrors `autoscaling.mcpAuth.*` | Autoscaling configuration for `mcp-gw`. | | `volumes` and `volumeMounts` | `[]` | Applied to both deployments. | | `nodeSelector`, `tolerations`, and `affinity` | `{}`, `[]`, and `{}` | Applied to both deployments. | | `env.redisHost` | `""` | Hostname of the shared Redis instance. | | `env.redisPort` | `"6379"` | Redis port. | | `env.redisPassword` | `""` | Redis password. | | `env.redisDb` | `"0"` | Redis database. | | `env.redisTlsEnabled` | `"true"` | Set to `"false"` for plain Redis. | | `env.cacheTtl` | `"300"` | Token and session cache TTL in seconds. | | `env.fronteggRegion` | `"eu"` | Supported values are `eu`, `us`, `ca`, `au`, and `stg`. | | `env.vendorClientId` | `""` | Frontegg vendor client ID. | | `env.vendorClientSecret` | `""` | Frontegg vendor client secret. | | `env.applicationId` | `""` | Frontegg application ID. | | `env.fronteggMcpGwHost` | `""` | External hostname of the gateway, without scheme. | | `env.externalAuthorizationUrl` | `""` | Same hostname with scheme, published as the OAuth issuer. | | `env.hybridAuthHost` | `""` | URL of your hybrid auth service, with scheme. | | `env.approvalFlowWebhookEndpoint` | Commented | Webhook for approval-flow callbacks. | | `env.eventWebhookProvider` | Commented | Example: `datadog`. | | `env.eventWebhookUrl` | Commented | Destination URL for event webhooks. | | `env.eventWebhookSecret` | Commented | Shared secret for signing event webhooks. | Every key under `.Values.env` is converted from camelCase to `UPPER_SNAKE_CASE` and emitted as a container environment variable on both containers. To add a new environment variable, add a key under `env`. ### Verify the install ```console # Watch the rollout. kubectl rollout status deploy/-mcp-gateway-auth kubectl rollout status deploy/-mcp-gateway-gw # Health checks. Both should return 200. kubectl port-forward svc/-mcp-gateway-auth 8080:8080 & curl -fsS http://localhost:8080/health kubectl port-forward svc/-mcp-gateway-gw 8081:8080 & curl -fsS http://localhost:8081/health ``` ### Upgrade the chart There are no CRDs and no persistent state owned by the chart. Redis lives outside it. Image versions are tied to chart versions. Each chart release pins the matching `mcp-auth` and `mcp-gw` images. To roll out a new image, upgrade the chart: ```console helm repo update helm upgrade mcp-gateway frontegg/mcp-gateway --version -f my-values.yaml ``` Do not override `mcpAuth.tag` or `mcpGw.tag` in your values file. Those are managed by Frontegg as part of the chart release.