Kubernetes
ClawQL is usually deployed as clawql-mcp-http: Streamable HTTP MCP on /mcp, GraphQL on /graphql, and (when ENABLE_GRPC=1) gRPC protobuf MCP on port 50051—all in one pod. values-docker-desktop.yaml matches production patterns: with ingress-nginx, http://clawql-mcp.localhost/mcp; with default Istio (make local-k8s-up), ingress-nginx is skipped and svc/clawql-mcp-ingress is a LoadBalancer → localhost on Docker Desktop / Rancher Desktop (pod hostNetwork would bind inside the Kubernetes VM only—see docker/README.md). svc/clawql-mcp-http is often ClusterIP under ambient Istio; MCP HTTP is http://localhost/mcp or http://clawql-mcp.localhost/mcp via Gateway + VirtualService. gRPC uses localhost:50051 through the same ingress Service when enabled. Remote clusters often use Kustomize dev / prod with scripts/deploy/deploy-k8s.sh.
Local MCP on Docker Desktop
Use this when you want the same north-south pattern as production — Ingress + hostname (http://clawql-mcp.localhost/mcp) for Cursor or other MCP clients, without running npx in a terminal.
Prerequisites
- Docker Desktop with Kubernetes enabled (Settings → Kubernetes).
kubectland Helm 3 on your PATH (Helm is required for Kyverno on everylocal-k8s-uppath, including Kustomize).- Repo clone at the version you want to run.
One-shot install
From the repository root:
make local-k8s-up
Or:
bash scripts/kubernetes/local-k8s-docker-desktop.sh
Default: helm upgrade --install with charts/clawql-mcp/values-docker-desktop.yaml: signed ghcr.io/danielsmithdevelopment/clawql-mcp:latest, ghcr.io/danielsmithdevelopment/clawql-website:latest, and ghcr.io/danielsmithdevelopment/clawql-dashboard:latest, all-providers, Obsidian memory vault.hostPath at $HOME/.ClawQL (Helm key vault — not HashiCorp Vault; override CLAWQL_LOCAL_VAULT_HOST_PATH). With default Istio, chart Ingress objects are off and svc/clawql-mcp-http is ClusterIP; north-south HTTP is clawql-mcp-ingress (LoadBalancer on docker/rancher kube contexts). With CLAWQL_LOCAL_K8S_ISTIO=0, Ingress serves clawql-mcp.localhost and svc/clawql-mcp-http stays LoadBalancer for gRPC / diagnostics. The script installs Kyverno and a ClusterPolicy so those images must pass Cosign verification in the clawql namespace (unsigned local docker build deploys are not supported).
Kustomize: CLAWQL_LOCAL_K8S_INSTALLER=kustomize make local-k8s-up — kubectl apply -k docker/kustomize/overlays/local for the MCP workload; Helm still installs Kyverno and applies the ClusterPolicy template from the chart.
For dashboard-specific Helm values and Vault sync wiring, see Dashboard on Kubernetes.
Optional Istio (Docker Desktop — default on): CLAWQL_LOCAL_K8S_ISTIO=ambient or sidecar runs scripts/kubernetes/install-istio-docker-desktop.sh before ClawQL (Helm Istio + istio/gateway clawql-mcp-ingress, Istio Gateway + VirtualService for MCP on :80 / :50051, PeerAuthentication STRICT). ingress-nginx is omitted unless you force it; clawql-mcp-ingress uses LoadBalancer → localhost on docker-desktop / rancher-desktop contexts. Prefer http://localhost/mcp when the gateway is installed. The same path installs Prometheus, Kiali, Grafana, Grafana Tempo, optional Grafana Loki, and a ClawQL OpenTelemetry Collector in istio-system (unless you opt out — see Docker Desktop: Istio & observability and docker/README.md).
How this ties to CI: full golden image and admission story — golden-image-pipeline.md and Security.
Endpoints and client config
- MCP (Streamable HTTP):
http://localhost/mcporhttp://clawql-mcp.localhost/mcp(default Istio vs ingress-nginx — same/mcpshape as prod) - Health:
curl -s http://localhost/healthzorhttp://clawql-mcp.localhost/healthz - Bundled docs UI:
http://docs.localhost(Istio VirtualService when gateway is on; Ingress when Istio is off) - Bundled dashboard UI:
http://clawql.localhost(Helm-managed service; Istio VirtualService when gateway is on, Ingress when Istio is off)
Point your MCP client at url (not stdio command). Example shape:
{
"mcpServers": {
"clawql": {
"url": "http://localhost/mcp"
}
}
}
Same url shape as production (https://mcp.example.com/mcp); only scheme and host differ locally.
Optional gRPC on the same deployment
When ENABLE_GRPC=1 (and optionally ENABLE_GRPC_REFLECTION=1 for grpcurl list), the container listens on 50051 for grpc.health.v1, model_context_protocol.Mcp, and mcp.transport.v1.Mcp.Session. The clawql-mcp-http Service includes a grpc port (50051) alongside HTTP in the Helm chart and Kustomize base / dev / prod—verify with kubectl -n clawql get svc clawql-mcp-http. For native grpc readiness/liveness probes on kubelet 1.27+, use the opt-in overlay docker/kustomize/overlays/grpc-enabled/ (see root README Kubernetes section). Full port matrix: docs/deployment/deploy-k8s.md — Service ports.
What the Helm install sets
- Namespace:
clawql CLAWQL_PROVIDER:all-providers(Google Cloud bundled APIs + every other bundled vendor; same as barenpx clawql-mcpwith no spec env). Override viavalues-docker-desktop.yamlorhelm --set provider=....- Kube context: the script prefers
docker-desktopwhen present so you do not accidentally deploy to another cluster.
Cold start can take a while while specs load. Wait until /healthz returns {"status":"ok",...} or the pod is Ready before the client connects.
MCP auth tokens (merged default bundle)
For local Docker Desktop k8s, execute needs tokens in the clawql-mcp-http pod. Per-vendor env vars match src/auth-headers.ts: GitHub (CLAWQL_GITHUB_TOKEN), Cloudflare (CLAWQL_CLOUDFLARE_API_TOKEN), Google (GOOGLE_ACCESS_TOKEN / CLAWQL_GOOGLE_ACCESS_TOKEN), Slack and other fallbacks (CLAWQL_BEARER_TOKEN / CLAWQL_HTTP_HEADERS), Paperless (PAPERLESS_API_TOKEN), Stirling (STIRLING_API_KEY), optional bearer for Tika/Gotenberg. The same GitHub PAT is often stored as CLAWQL_BEARER_TOKEN for merged-bundle fallback.
One-shot: from the repo root, with gh logged in or values in .env:
bash scripts/kubernetes/k8s-docker-desktop-set-mcp-auth.sh
Pipe a PAT: gh auth token | bash scripts/kubernetes/k8s-docker-desktop-set-mcp-auth.sh. Set CLAWQL_LOAD_DOTENV=0 to skip sourcing .env.
This creates/updates Secret clawql-github-auth (name kept for backward compatibility), attaches keys to deployment/clawql-mcp-http, and restarts. Full table and manual kubectl steps: docker/README.md (section MCP auth). The old script name k8s-docker-desktop-set-github-token.sh is a deprecated alias.
helm upgrade --install reapplies chart values; env injected only with kubectl set env can be overwritten on the next upgrade. Prefer helm --set extraEnv or a Secret wired through values.yaml for durable config.
Rebuild after code changes
Kubernetes on Docker Desktop expects signed images from GHCR. After upstream publishes a new tag, run make local-k8s-up again (or helm upgrade with image.tag / digest). For rapid local edits without admission, use make local-docker-up. Example recycle:
make local-k8s-up
kubectl --context docker-desktop -n clawql rollout restart deployment/clawql-mcp-http
Teardown
helm uninstall clawql -n clawql
Or delete the whole namespace:
kubectl --context docker-desktop delete namespace clawql
Remote clusters (dev / prod)
For registries and image tags (not the local latest flow), use overlays and the deploy script:
ENV=dev IMAGE=us-central1-docker.pkg.dev/<project>/<repo>/clawql-mcp TAG=<tag> make deploy-k8s
Or install the Helm chart with your image registry. Full checklist: docs/deployment/deploy-k8s.md.
More detail in the repo
- Container build, Compose, and extended K8s notes:
docker/README.md - Starter manifest:
docker/kubernetes-starter.yaml
NATS JetStream quick checklist
Use this when enabling in-cluster event streaming for Ouroboros/agent/edge coordination (#127):
- Enable NATS in Helm values (
nats.enabled=true) and keepnats.service.type=ClusterIPunless external exposure is required. - Enable persistence for durable streams (
nats.persistence.enabled=true) and right-sizenats.jetStream.maxFileStore. - Confirm NATS service health (
/healthzon monitor port 8222) before enabling dependent workloads. - Use
nats.urlonly when pointing ClawQL at an external/shared NATS cluster. - Keep subject naming consistent across services (
clawql.workflow.*,clawql.agent.*,clawql.edge.*). - Validate
CLAWQL_NATS_URL/CLAWQL_NATS_JETSTREAMenv vars landed inclawql-mcp-httpafterhelm upgrade.
Full values reference and runbook: NATS JetStream. Helm context: Helm.
Flink Onyx sync quick checklist
Use this when enabling in-cluster Flink for real-time Onyx index freshness (#119):
- Enable Flink in Helm values (
flink.enabled=true) and keepflink.service.type=ClusterIP. - Put connector credentials in a dedicated Secret and wire it with
flink.connectorSecret. - Confirm JobManager + TaskManagers are ready in the same namespace as ClawQL.
- Validate connector throughput and Onyx ingestion latency before scaling task slots/replicas.
- Keep Flink UI private by default; use temporary
kubectl port-forwardfor debugging.
Full architecture, values reference, and runbook: Flink Onyx sync. Helm context: Helm.
