Files
infra-librechat/k8s
Stéphane Tailland 7892f0f8f5 Remove the Grafana MCP server
Reverts the declaration. The approach does not hold up in practice: an MCP
client resends the whole tool list every turn, so simply having this server
connected cost ~19k prompt tokens per request — and ~5.4k even after
trimming the tool set by 72%. On top of that its metric-name listing
returns 3330 entries, 137 KiB, which the assistant called twice while
exploring. Conversations tripped Kong's 50k-tokens-per-minute AI rate limit
and sat in a 429 retry loop.

The deployment, the Vault-backed secret and the Grafana service account
stay in place; only the LibreChat wiring goes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 18:18:36 +02:00
..
2026-08-27 18:18:36 +02:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00
2026-05-09 06:42:45 +00:00

LibreChat — Kubernetes Deployment

Deploys LibreChat on Kubernetes with MongoDB, MeiliSearch, and the JIRA MCP server.

Architecture

Namespace: librechat
│
├── Ingress nginx (librechat.sttlab.pc — TLS wildcard *.sttlab.pc)
│   └── librechat :3080
│       ├── mongodb :27017  (StatefulSet, 5 Gi PVC)
│       └── meilisearch :7700  (Deployment, 2 Gi PVC)
│
└── MCP JIRA (namespace: mcp)
    └── mcp-jira :9000  (streamable-http, 49 tools)
Component Image Storage
LibreChat ghcr.io/danny-avila/librechat:latest — (stateless)
MongoDB mongo:7 5 Gi PVC
MeiliSearch getmeili/meilisearch:v1.7 2 Gi PVC

Directory structure

k8s/
├── namespace.yaml             Namespace definition
├── secret.yaml                Credentials (gitignored — never commit real values)
├── configmap.yaml             Application environment config
├── kustomization.yaml         Kustomize entry point
├── mongodb/
│   ├── pvc.yaml
│   ├── statefulset.yaml
│   └── service.yaml
├── meilisearch/
│   ├── pvc.yaml
│   ├── deployment.yaml
│   └── service.yaml
├── librechat/
│   ├── configmap-app.yaml     Mounts librechat.yaml (MCP config, allowedDomains...)
│   ├── deployment.yaml
│   └── service.yaml
└── ingress/
    ├── ingress.yaml
    └── tls.yaml               TLS secret (gitignored — never commit)

Prerequisites

  • Kubernetes cluster with an Nginx ingress controller
  • A default StorageClass (for PVCs)
  • kubectl configured against your cluster
  • Wildcard TLS certificate for *.sttlab.pc in $HOME/tls/

Initial deployment

1. Fill in secrets

Edit secret.yaml with real values. Generate them with:

openssl rand -base64 24   # MONGO_PASSWORD
openssl rand -base64 32   # MEILI_MASTER_KEY, JWT_SECRET, JWT_REFRESH_SECRET
openssl rand -hex 32      # CREDS_KEY
openssl rand -hex 8       # CREDS_IV

Important: MONGO_URI must include ?authSource=admin because MONGO_INITDB_ROOT_USERNAME creates the user in the admin database:

mongodb://librechat:<password>@mongodb:27017/LibreChat?authSource=admin

2. Create the TLS secret

kubectl apply -f k8s/namespace.yaml

kubectl create secret tls sttlab-tls \
  --cert=$HOME/tls/sttlab.pc.crt \
  --key=$HOME/tls/sttlab.pc.key \
  --namespace=librechat \
  --dry-run=client -o yaml > k8s/ingress/tls.yaml

kubectl apply -f k8s/ingress/tls.yaml

3. Deploy

export DOMAIN=librechat.sttlab.pc
kubectl kustomize k8s/ | envsubst '${DOMAIN}' | kubectl apply -f -

Note: DOMAIN must be exported before the pipe. An inline assignment (DOMAIN=x cmd1 | cmd2) does not propagate to envsubst.

4. Verify

kubectl get pods,ingress -n librechat
curl -sk https://librechat.sttlab.pc/health

MCP JIRA

The JIRA MCP server runs in the mcp namespace (mcp-jira:9000, streamable-http transport).

librechat/configmap-app.yaml mounts /app/librechat.yaml into the container:

mcpSettings:
  allowedDomains:
    - "http://mcp-jira.mcp.svc.cluster.local:9000"
mcpServers:
  jira:
    type: streamable-http
    url: http://mcp-jira.mcp.svc.cluster.local:9000/mcp

mcpSettings.allowedDomains is required to allow internal k8s domains, which are blocked by default as SSRF protection.

Updating

export DOMAIN=librechat.sttlab.pc
kubectl kustomize k8s/ | envsubst '${DOMAIN}' | kubectl apply -f -

Force a pod restart:

kubectl rollout restart deployment/librechat -n librechat

Teardown

kubectl delete namespace librechat

This also deletes all PVCs and their data. Back up MongoDB first if needed.