# =============================================================================
# Britive MCP Gateway — Kubernetes manifests
# =============================================================================
# Stateless Gateway replicas sharing one external Postgres. Works on EKS, GKE,
# AKS and self-managed clusters.
#
# BEFORE YOU APPLY -----------------------------------------------------------
#   1. Fill in the Secret below (tenant, pool token, database URL). That is the
#      whole of the pod's configuration — every other setting lives on the
#      gateway pool in your Britive tenant and arrives at startup.
#   2. In the Britive tenant portal, open the gateway pool your token belongs to
#      and set "Public base URL" to the hostname clients will use. OAuth
#      redirect and resource URLs are built from it, so it must match what the
#      browser actually reaches — the Ingress hostname, not the pod.
#   3. Decide how traffic reaches the Service — the Ingress at the bottom is one
#      option; a LoadBalancer Service or your service mesh works too.
#
#   kubectl apply -f mcp-gateway-k8s.yaml
#   kubectl -n britive-mcp-gateway rollout status deploy/mcp-gateway
#
# WHAT THIS DOES NOT CREATE --------------------------------------------------
# A database. The Gateway needs Postgres 14+ that you operate — a managed
# service is the expected choice. Put its URL in the Secret below.
# =============================================================================
apiVersion: v1
kind: Namespace
metadata:
  name: britive-mcp-gateway
---
# =============================================================================
# Secret — replace every value.
# =============================================================================
# There is no master secret to generate. The key that protects stored tokens and
# sessions is minted by the platform for the gateway pool and delivered with the
# pool's settings, so every replica agrees on it with nothing to distribute and
# nothing to keep stable across upgrades.
#
# In a real cluster, prefer an External Secrets Operator, Sealed Secrets, or your
# cloud's secret store over committing this file with values in it.
apiVersion: v1
kind: Secret
metadata:
  name: mcp-gateway
  namespace: britive-mcp-gateway
type: Opaque
stringData:
  # Your Britive tenant: a bare subdomain ("acme") or a full https:// URL.
  TENANT: "REPLACE_ME"
  # The Gateway's own platform credential, from the Britive admin console. It
  # also decides which gateway pool — and therefore which settings — these pods
  # run with.
  GATEWAY_POOL_TOKEN: "REPLACE_ME"
  # Your Postgres. Not created by this manifest.
  DATABASE_URL: "postgresql://gateway:REPLACE_ME@your-db-host:5432/gateway"
  # Optional. Log level until the pool's settings arrive, after which the pool's
  # "Log level" takes over.
  LOG_LEVEL: "info"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-gateway
  namespace: britive-mcp-gateway
  labels:
    app: mcp-gateway
spec:
  # Two for availability rather than throughput. Any pod can serve any request:
  # all state is in Postgres, so no session affinity is needed anywhere.
  replicas: 2
  selector:
    matchLabels:
      app: mcp-gateway
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app: mcp-gateway
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: gateway
          image: britive/mcp-gateway:latest
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
          envFrom:
            - secretRef:
                name: mcp-gateway
          # Schema migrations run on startup, so a new image needs no separate
          # migration job. startupProbe gives that first run room to finish
          # before the liveness probe starts counting failures.
          startupProbe:
            httpGet:
              path: /healthz
              port: http
            periodSeconds: 5
            failureThreshold: 30
          readinessProbe:
            httpGet:
              path: /readyz
              port: http
            periodSeconds: 10
            timeoutSeconds: 5
          livenessProbe:
            httpGet:
              path: /healthz
              port: http
            periodSeconds: 20
            timeoutSeconds: 5
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              memory: 1Gi
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: false
            capabilities:
              drop: ["ALL"]
---
apiVersion: v1
kind: Service
metadata:
  name: mcp-gateway
  namespace: britive-mcp-gateway
spec:
  type: ClusterIP
  selector:
    app: mcp-gateway
  ports:
    - name: http
      port: 80
      targetPort: http
---
# =============================================================================
# Ingress — one way to expose the Service. Adjust for your controller.
# =============================================================================
# TLS is required: OAuth tokens and checked-out credentials cross this
# connection. Terminate it here or at a load balancer in front.
#
# Raise the proxy read timeout. A Britive checkout that needs human approval can
# take longer than a default 60s, and an ingress that cuts the connection at 60s
# fails those tool calls. The annotations below are nginx-ingress; use your own
# controller's equivalent.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mcp-gateway
  namespace: britive-mcp-gateway
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
    # MCP holds a stream open for server-to-client messages; buffering it makes
    # a working call look like a hang.
    nginx.ingress.kubernetes.io/proxy-buffering: "off"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - mcp-gateway.example.internal
      secretName: mcp-gateway-tls
  rules:
    - host: mcp-gateway.example.internal
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: mcp-gateway
                port:
                  name: http
