commit 9fc30a35733e3590c626402b27dd8b721f20efeb Author: CaffeineTux Date: Sun Nov 16 02:28:44 2025 -0500 Initial homelab GitOps repository setup This commit establishes the foundation for the homelab GitOps repository: - Created layered architecture (infrastructure/platform/apps) - Added MCP servers umbrella chart with SOPS-encrypted secrets - Configured Flux Kustomizations for infrastructure and platform layers - Set up SOPS + Age for secrets management - Added .gitignore and documentation MCP servers include: - Gateway with auth (API keys in encrypted secrets) - n8n MCP (workflow automation) - Playwright MCP (browser automation) - Kubernetes MCP (kubectl operations) - GitHub MCP (repository management) - Gitea MCP (self-hosted git) - SQLite MCP (database operations) - Filesystem MCP (file operations) - Fetch MCP (HTTP requests) - Memory MCP (shared memory/state) All secrets are encrypted with SOPS using Age encryption. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36a849e --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Secrets (before SOPS encryption) +**/secrets/*.yaml.dec +*.key +*.pem +age.key +*.agekey +.age-key.txt +.sops.key + +# Helm +*.tgz +charts/ +Chart.lock + +# Flux +.flux.yaml + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.bak +*.orig + +# Custom values with unencrypted secrets +custom-values.yaml +*-secrets.yaml.dec + +# Build artifacts +dist/ +build/ diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..201904d --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,10 @@ +creation_rules: + # Default rule for all encrypted files + - path_regex: .*\.enc\.yaml$ + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + age: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry + + # Alternative pattern for secrets files + - path_regex: secrets.*\.yaml$ + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + age: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d2669c --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# Homelab GitOps Repository + +This repository contains the declarative configuration for my Kubernetes homelab, managed using FluxCD v2 and SOPS-encrypted secrets. + +## Architecture + +The repository is organized into three layers: + +### Layer 0 - Infrastructure +Core cluster infrastructure that other applications depend on: +- **cert-manager**: TLS certificate management +- **ingress-nginx**: Ingress controller for HTTP/HTTPS routing +- **storage**: Persistent volume provisioning + +### Layer 1 - Platform +Platform services that support applications: +- **gitea**: Self-hosted Git server +- **harbor**: Container registry +- **n8n**: Workflow automation +- **mcp-servers**: Model Context Protocol servers with gateway +- **gotify**: Push notifications +- **prometheus**: Monitoring and alerting + +### Layer 2 - Apps +User-facing applications: +- **media**: Audiobookshelf, Media-Servarr stack, MPD +- **ai**: Ollama, Open WebUI +- **file-sharing**: Firefox Send, Pairdrop, Pingvin Share, PsiTransfer +- **utilities**: BentoPDF, Stirling PDF, Minecraft + +## Secrets Management + +All secrets are encrypted using [SOPS](https://github.com/getsops/sops) with [age](https://github.com/FiloSottile/age) encryption. + +### Decrypting Secrets + +```bash +# Decrypt a single file +sops -d infrastructure/cert-manager/secrets.enc.yaml > secrets.yaml + +# Edit encrypted file in-place +sops infrastructure/cert-manager/secrets.enc.yaml +``` + +### Encrypting New Secrets + +```bash +# Encrypt a new secret file +sops -e secrets.yaml > secrets.enc.yaml +``` + +## Deployment + +This repository is deployed using FluxCD v2: + +```bash +# Bootstrap Flux (already done) +flux bootstrap git \ + --url=http://192.168.1.49:13001/admin/homelab.git \ + --branch=main \ + --path=clusters/production + +# Check Flux status +flux get all +``` + +## Environment + +- **Platform**: K3s on ARM (Raspberry Pi) +- **OS**: Termux on Android +- **GitOps**: FluxCD v2 +- **Secrets**: SOPS + Age encryption +- **Registry**: Harbor (self-hosted) + +## Directory Structure + +``` +. +├── bootstrap/ # Flux bootstrap manifests +├── infrastructure/ # Layer 0: Core infrastructure +├── platform/ # Layer 1: Platform services +├── apps/ # Layer 2: Applications +├── clusters/ # Cluster-specific configurations +│ └── production/ # Production cluster Kustomizations +└── docs/ # Additional documentation +``` + +## Maintenance + +### Updating Applications + +1. Edit the HelmRelease or Kustomization in the appropriate directory +2. Commit and push changes to Gitea +3. Flux will automatically reconcile within 1 minute (or force with `flux reconcile`) + +### Adding New Applications + +1. Create directory in appropriate layer (infrastructure/platform/apps) +2. Add namespace.yaml, helmrelease.yaml, and kustomization.yaml +3. If secrets needed, create secrets.enc.yaml using SOPS +4. Add reference to layer's kustomization.yaml +5. Commit and push + +## Contact + +Maintained by CaffeineTux diff --git a/clusters/production/infrastructure.yaml b/clusters/production/infrastructure.yaml new file mode 100644 index 0000000..8b42f4f --- /dev/null +++ b/clusters/production/infrastructure.yaml @@ -0,0 +1,18 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: infrastructure + namespace: flux-system +spec: + interval: 10m + timeout: 5m + sourceRef: + kind: GitRepository + name: homelab + path: ./infrastructure + prune: true + wait: true + decryption: + provider: sops + secretRef: + name: sops-age diff --git a/clusters/production/platform.yaml b/clusters/production/platform.yaml new file mode 100644 index 0000000..ef1394c --- /dev/null +++ b/clusters/production/platform.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: platform + namespace: flux-system +spec: + interval: 10m + timeout: 5m + sourceRef: + kind: GitRepository + name: homelab + path: ./platform + prune: true + wait: true + # Depend on infrastructure being ready first + dependsOn: + - name: infrastructure + decryption: + provider: sops + secretRef: + name: sops-age diff --git a/infrastructure/kustomization.yaml b/infrastructure/kustomization.yaml new file mode 100644 index 0000000..548e902 --- /dev/null +++ b/infrastructure/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: [] + # Infrastructure components will be added here: + # - cert-manager + # - ingress-nginx + # - storage diff --git a/platform/kustomization.yaml b/platform/kustomization.yaml new file mode 100644 index 0000000..58d1061 --- /dev/null +++ b/platform/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - mcp-servers + # Add other platform services as they are migrated: + # - gitea + # - harbor + # - n8n + # - gotify + # - prometheus diff --git a/platform/mcp-servers/Chart.yaml b/platform/mcp-servers/Chart.yaml new file mode 100644 index 0000000..31e8ecd --- /dev/null +++ b/platform/mcp-servers/Chart.yaml @@ -0,0 +1,79 @@ +apiVersion: v2 +name: mcp-umbrella +description: Umbrella Helm chart that deploys all MCP servers + MCP Gateway +type: application +version: 1.0.0 +appVersion: "1.0.0" +keywords: + - mcp + - model-context-protocol + - automation + - ai + - n8n + - gateway +maintainers: + - name: CaffeineTux +home: https://github.com/modelcontextprotocol +sources: + - https://github.com/modelcontextprotocol/servers +dependencies: + - name: mcp-gateway + version: "1.0.0" + repository: "file://../mcp-gateway" + condition: mcp-gateway.enabled + - name: n8n-mcp + version: "1.0.0" + repository: "file://../n8n-mcp" + condition: n8n-mcp.enabled + - name: playwright-mcp + version: "1.0.0" + repository: "file://../playwright-mcp" + condition: playwright-mcp.enabled + - name: kubernetes-mcp + version: "1.0.0" + repository: "file://../kubernetes-mcp" + condition: kubernetes-mcp.enabled + - name: github-mcp + version: "1.0.0" + repository: "file://../github-mcp" + condition: github-mcp.enabled + - name: postgresql-mcp + version: "1.0.0" + repository: "file://../postgresql-mcp" + condition: postgresql-mcp.enabled + - name: sqlite-mcp + version: "1.0.0" + repository: "file://../sqlite-mcp" + condition: sqlite-mcp.enabled + - name: prometheus-mcp + version: "1.0.0" + repository: "file://../prometheus-mcp" + condition: prometheus-mcp.enabled + - name: slack-mcp + version: "1.0.0" + repository: "file://../slack-mcp" + condition: slack-mcp.enabled + - name: s3-mcp + version: "1.0.0" + repository: "file://../s3-mcp" + condition: s3-mcp.enabled + - name: filesystem-mcp + version: "1.0.0" + repository: "file://../filesystem-mcp" + condition: filesystem-mcp.enabled + - name: puppeteer-mcp + version: "1.0.0" + repository: "file://../puppeteer-mcp" + condition: puppeteer-mcp.enabled + - name: fetch-mcp + version: "1.0.0" + repository: "file://../fetch-mcp" + condition: fetch-mcp.enabled + - name: memory-mcp + version: "1.0.0" + repository: "file://../memory-mcp" + condition: memory-mcp.enabled + - name: gitea-mcp + version: "1.0.0" + repository: "file://../gitea-mcp" + condition: gitea-mcp.enabled diff --git a/platform/mcp-servers/README.md b/platform/mcp-servers/README.md new file mode 100644 index 0000000..b2311aa --- /dev/null +++ b/platform/mcp-servers/README.md @@ -0,0 +1,394 @@ +# MCP Umbrella Helm Chart + +Complete deployment solution for the MCP (Model Context Protocol) server ecosystem. This umbrella chart deploys all MCP servers with a central gateway for unified access. + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ MCP Gateway │ +│ (LoadBalancer Service) │ +│ http://:3000 │ +│ │ +│ Routes requests to individual MCP servers: │ +│ POST /mcp/n8n-mcp → n8n-mcp:3001 │ +│ POST /mcp/playwright-mcp → playwright-mcp:3002 │ +│ POST /mcp/kubernetes-mcp → kubernetes-mcp:3003 │ +│ POST /mcp/github-mcp → github-mcp:3004 │ +│ ... (all 13 MCP servers) │ +└─────────────────────────────────────────────────────────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ + │ n8n-MCP │ │Playwright│ │Kubernetes│ │ GitHub │ + │ :3001 │ │ MCP │ │ MCP │ │ MCP │ + │ │ │ :3002 │ │ :3003 │ │ :3004 │ + └──────────┘ └──────────┘ └──────────┘ └──────────┘ + ... (9 more servers) + + ┌──────────────────────────────────────────────────────┐ + │ Memory MCP (Central State) │ + │ :3013 → Redis/PostgreSQL │ + │ Provides shared state for all MCP servers │ + └──────────────────────────────────────────────────────┘ +``` + +## Features + +- **13 MCP Servers** available for automation +- **Central Gateway** with API key authentication +- **LoadBalancer** access to entire MCP ecosystem +- **Memory-MCP** as central coordinator for shared state +- **Selective Deployment** - enable only the servers you need +- **Production-Ready** with RBAC, security contexts, and health checks +- **Auto-Scaling** for gateway and resource-intensive servers + +## Quick Start + +### 1. Prerequisites + +```bash +# Ensure you're in the right directory +cd /data/data/com.termux/files/home/git/mcp-servers/mcp-umbrella + +# Build chart dependencies +helm dependency build +``` + +### 2. Generate API Keys + +```bash +# Generate secure API keys for the gateway +echo "n8n API key: $(openssl rand -hex 32)" +echo "admin API key: $(openssl rand -hex 32)" +``` + +### 3. Configure Required Secrets + +Create a `custom-values.yaml` file: + +```yaml +mcp-gateway: + gateway: + auth: + apiKeys: + - name: "n8n" + key: "YOUR_N8N_API_KEY_HERE" + - name: "admin" + key: "YOUR_ADMIN_API_KEY_HERE" + +n8n-mcp: + n8nMCP: + n8n: + apiKey: "YOUR_N8N_INSTANCE_API_KEY" + +github-mcp: + github: + token: "YOUR_GITHUB_TOKEN" + owner: "your-github-username" +``` + +### 4. Deploy + +```bash +# Create the mcp namespace +kubectl create namespace mcp + +# Install the umbrella chart +helm install mcp-ecosystem . \ + --namespace mcp \ + -f custom-values.yaml +``` + +### 5. Verify Deployment + +```bash +# Check all pods +kubectl get pods -n mcp + +# Get gateway LoadBalancer IP +kubectl get svc -n mcp mcp-ecosystem-mcp-gateway + +# Test health endpoint +GATEWAY_IP=$(kubectl get svc -n mcp mcp-ecosystem-mcp-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +curl http://$GATEWAY_IP:3000/health +``` + +## MCP Servers Included + +| Server | Port | Status | Description | +|--------|------|--------|-------------| +| **mcp-gateway** | 3000 | Always Enabled | Central routing gateway | +| **n8n-mcp** | 3001 | Enabled | n8n workflow automation | +| **playwright-mcp** | 3002 | Enabled | Browser automation | +| **kubernetes-mcp** | 3003 | Enabled | Kubectl operations | +| **github-mcp** | 3004 | Enabled | GitHub API operations | +| **postgresql-mcp** | 3005 | Disabled* | PostgreSQL operations | +| **sqlite-mcp** | 3006 | Enabled | SQLite operations | +| **prometheus-mcp** | 3007 | Disabled* | Metrics queries | +| **slack-mcp** | 3008 | Disabled* | Slack operations | +| **s3-mcp** | 3009 | Disabled* | S3/MinIO operations | +| **filesystem-mcp** | 3010 | Enabled | File operations | +| **puppeteer-mcp** | 3011 | Disabled* | Chrome automation | +| **fetch-mcp** | 3012 | Enabled | HTTP requests | +| **memory-mcp** | 3013 | Enabled | Central state coordinator | + +*\*Requires additional configuration - see [Configuration](#configuration) section* + +## Configuration + +### Enabling/Disabling Servers + +In your `custom-values.yaml`: + +```yaml +# Enable a disabled server +prometheus-mcp: + enabled: true + prometheus: + url: "http://your-prometheus-server" + +# Disable an enabled server +playwright-mcp: + enabled: false +``` + +### Configuring the Gateway + +```yaml +mcp-gateway: + service: + type: LoadBalancer + loadBalancerIP: "192.168.1.100" # Optional static IP + + ingress: + enabled: true # Enable Ingress (currently disabled) + hosts: + - host: mcp.caffeinetux.com + paths: + - path: / + pathType: Prefix + + autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 5 +``` + +### Configuring Memory-MCP Backend + +Choose Redis or PostgreSQL: + +```yaml +memory-mcp: + storage: + backend: "redis" # or "postgres" + + redis: + host: "redis.default.svc.cluster.local" + port: 6379 + password: "your-redis-password" +``` + +## Usage Examples + +### From n8n Workflow + +Use the HTTP Request node: + +```javascript +// n8n HTTP Request Node +Method: POST +URL: http://mcp-ecosystem-mcp-gateway.mcp.svc.cluster.local:3000/mcp/playwright-mcp +Authentication: Header Auth +Header Name: Authorization +Header Value: Bearer YOUR_N8N_API_KEY + +Body: +{ + "jsonrpc": "2.0", + "method": "navigate", + "params": { + "url": "https://example.com" + }, + "id": 1 +} +``` + +### From External Client + +```bash +# Get list of available servers +curl -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \ + http://:3000/servers + +# Make MCP request to Kubernetes-MCP +curl -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "jsonrpc": "2.0", + "method": "get_pods", + "params": {"namespace": "default"}, + "id": 1 + }' \ + http://:3000/mcp/kubernetes-mcp +``` + +### Store Shared State in Memory-MCP + +```bash +# Store a value +curl -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "jsonrpc": "2.0", + "method": "memory_store", + "params": { + "namespace": "workflow", + "key": "user_session", + "value": {"user_id": 123, "state": "active"}, + "ttl": 3600 + }, + "id": 1 + }' \ + http://:3000/mcp/memory-mcp + +# Retrieve the value +curl -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "jsonrpc": "2.0", + "method": "memory_retrieve", + "params": { + "namespace": "workflow", + "key": "user_session" + }, + "id": 2 + }' \ + http://:3000/mcp/memory-mcp +``` + +## Upgrading + +```bash +# Update dependencies +helm dependency update + +# Upgrade the deployment +helm upgrade mcp-ecosystem . \ + --namespace mcp \ + -f custom-values.yaml +``` + +## Uninstalling + +```bash +# Remove the deployment +helm uninstall mcp-ecosystem --namespace mcp + +# Optionally delete the namespace +kubectl delete namespace mcp +``` + +## Troubleshooting + +### Gateway not accessible + +```bash +# Check gateway pod logs +kubectl logs -n mcp -l app.kubernetes.io/name=mcp-gateway + +# Check service +kubectl describe svc -n mcp mcp-ecosystem-mcp-gateway +``` + +### MCP server not responding + +```bash +# Check specific server logs +kubectl logs -n mcp -l app.kubernetes.io/name=playwright-mcp + +# Check if server is registered in gateway +curl -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \ + http://:3000/servers +``` + +### Authentication errors + +```bash +# Verify API keys are set +kubectl get secret -n mcp mcp-ecosystem-mcp-gateway-auth -o yaml + +# Test without auth (should fail with 401) +curl http://:3000/servers +``` + +## Resource Requirements + +### Minimal Setup (5 servers) +- **CPU**: ~2 cores total +- **Memory**: ~3Gi total +- **Storage**: ~15Gi (PVCs for SQLite, Filesystem, Playwright) + +### Full Setup (all 13 servers) +- **CPU**: ~6 cores total +- **Memory**: ~10Gi total +- **Storage**: ~50Gi (with all persistence enabled) + +### Per-Server Resources + +| Server | CPU Request | CPU Limit | RAM Request | RAM Limit | +|--------|-------------|-----------|-------------|-----------| +| Gateway | 100m | 500m | 128Mi | 512Mi | +| n8n-MCP | 50m | 200m | 128Mi | 256Mi | +| Playwright | 200m | 1000m | 512Mi | 2Gi | +| Kubernetes | 100m | 100m | 128Mi | 128Mi | +| Memory-MCP | 100m | 200m | 256Mi | 512Mi | +| Others | 50-100m | 100-200m | 64-128Mi | 128-256Mi | + +## Security + +- **API Key Authentication** on gateway +- **RBAC** for Kubernetes-MCP cluster access +- **Secrets** for all credentials (GitHub tokens, database passwords, etc.) +- **Non-root users** in all containers +- **Read-only root filesystem** where possible +- **Network policies** (add custom NetworkPolicy resources as needed) + +## Advanced Configuration + +### Custom n8n Node + +See [n8n-mcp-node/README.md](../n8n-mcp-node/README.md) for installing a custom n8n node that simplifies MCP gateway access. + +### Monitoring + +```yaml +# Enable Prometheus monitoring +prometheus-mcp: + enabled: true + prometheus: + url: "http://prometheus-server.prometheus.svc.cluster.local" +``` + +### High Availability + +```yaml +mcp-gateway: + replicaCount: 3 + autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 10 +``` + +## Support + +For issues or questions: +- Check the individual MCP server READMEs in `../*/README.md` +- Review logs: `kubectl logs -n mcp ` +- GitHub Issues: https://github.com/modelcontextprotocol/servers + +## License + +See individual MCP server repositories for their respective licenses. diff --git a/platform/mcp-servers/helmrelease.yaml b/platform/mcp-servers/helmrelease.yaml new file mode 100644 index 0000000..5c714b8 --- /dev/null +++ b/platform/mcp-servers/helmrelease.yaml @@ -0,0 +1,41 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: mcp-umbrella + namespace: mcp +spec: + interval: 10m + timeout: 5m + chart: + spec: + chart: ./platform/mcp-servers + sourceRef: + kind: GitRepository + name: homelab + namespace: flux-system + interval: 5m + + # Depend on namespace and secrets + dependsOn: + - name: mcp-secrets + namespace: mcp + + install: + createNamespace: false + remediation: + retries: 3 + + upgrade: + remediation: + retries: 3 + remediateLastFailure: true + cleanupOnFail: true + + valuesFrom: + - kind: ConfigMap + name: mcp-umbrella-values + optional: true + + values: + # Values from values.yaml will be automatically used + # Additional overrides can be placed here diff --git a/platform/mcp-servers/kustomization.yaml b/platform/mcp-servers/kustomization.yaml new file mode 100644 index 0000000..9e3f968 --- /dev/null +++ b/platform/mcp-servers/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: mcp + +resources: + - namespace.yaml + - secrets.enc.yaml + - helmrelease.yaml + +# SOPS decryption for encrypted secrets +# Flux will automatically decrypt files matching this pattern +# Make sure flux-system has the age secret configured diff --git a/platform/mcp-servers/namespace.yaml b/platform/mcp-servers/namespace.yaml new file mode 100644 index 0000000..8272032 --- /dev/null +++ b/platform/mcp-servers/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: mcp + labels: + app.kubernetes.io/part-of: mcp-ecosystem + toolkit.fluxcd.io/tenant: platform diff --git a/platform/mcp-servers/secrets.enc.yaml b/platform/mcp-servers/secrets.enc.yaml new file mode 100644 index 0000000..bfde068 --- /dev/null +++ b/platform/mcp-servers/secrets.enc.yaml @@ -0,0 +1,119 @@ +apiVersion: v1 +kind: Secret +metadata: + name: mcp-gateway-api-keys + namespace: mcp +type: Opaque +stringData: + n8n-key: ENC[AES256_GCM,data:s/IIC99kiFR64YcHrukDfHcctfrO6gMY2jpbql2VIikwhpMAnXDN4mVddlwNIwHOtjIgP6oL8c9Q4lfiANy5sg==,iv:rl1pR9IcsOsPNtvb7sH8VE7cEkb1SrKqcqoHTLBcedU=,tag:PJCcbvp3pd94XWPMo2IQ0Q==,type:str] + admin-key: ENC[AES256_GCM,data:m0QIropOzru9e7VxowzFphJYA0O31BLBr+fyTdHgCkHtMpwCgxvBQfmwTpeBM355CPGLUiZ14YhYWXRiOc2fMg==,iv:xVA0HRgu/NaEprersvP9mxWD6rJrsI1yJhBJ+hUaAEY=,tag:bgY2YEKKnHyH5zOCIFStag==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1eTE4UEt0bzN4OWJuamNt + Mm9aZkNRdVZIckZuMmZNeWVGWkhhWTl2dERjCldzWVZxemQ2ZTJaOFF1cFBRcHFn + eENmcmhjaUNEOFZ1anNLWEpOcGJRVmMKLS0tIG05N1pldmY5d1ZXUVRleXlQWWx1 + dmJRbnFzNlZRZElTQVZ3RmNzVzRZWUUKkcXqeJd3Domjt7TlKn78HqgGiCOQ0whM + ZwgQ+6Q97D95bBK3Wa0TiZ4FNqKJvTa5jQ0Onh03eQ5eXKHJiqTcdw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-11-16T07:26:31Z" + mac: ENC[AES256_GCM,data:WliyDuYa0RUFoYOqqaYyXmmf8NYKe9sdOgSaOfSjhnHwvT4Z2nh+k/RR9fmpZ7qjrZFVdE9kfur21Mh6hKZnJ7vlA63u3YFq4Buu3fOdlSPLA3FRTeDbFy0kIDM2R4OqkXQrCVUFxGaQkG4lKw6XAKLZDnmQw9059wKRbbMTWpc=,iv:pU5RJCtoctkIy22VgFJPLEkmsgA/t4x1FwEJgkc1pdE=,tag:96pa5LoubQurpR8Yydcr2A==,type:str] + pgp: [] + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + version: 3.9.2 +--- +apiVersion: v1 +kind: Secret +metadata: + name: n8n-mcp-api-key + namespace: mcp +type: Opaque +stringData: + apiKey: ENC[AES256_GCM,data:v51UaiPHLi0acynqtXkEr1jCcf39hLa0pgcKPg2xLUwTf53IlN+HqbwTzWByTu4zBAHksCqrU1nvCdhi5wuAxjv1YVpObytA+UyPnM13UEw7ThrGqlpq4+lytA0ZsIFgjsDqb7T7Xyr1gNrQjZVpT17LQGAhbEQAuhXxzR3VIzOFpFj4zO7+im9WlEMUz5oq/T70/PMYSR7zw12we9GHfze5WZQ42AuwCIk7kuloSd+/9UzQyJZlRSVVyPBmtJGz3Mfoa02F84RgJsEHEXou,iv:pyO0SFcVFXenBTVMNcC/O9jEfVr79ZMQXVagAc9mjKc=,tag:A+3wEzEkt7qMcYZSR77xgA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1eTE4UEt0bzN4OWJuamNt + Mm9aZkNRdVZIckZuMmZNeWVGWkhhWTl2dERjCldzWVZxemQ2ZTJaOFF1cFBRcHFn + eENmcmhjaUNEOFZ1anNLWEpOcGJRVmMKLS0tIG05N1pldmY5d1ZXUVRleXlQWWx1 + dmJRbnFzNlZRZElTQVZ3RmNzVzRZWUUKkcXqeJd3Domjt7TlKn78HqgGiCOQ0whM + ZwgQ+6Q97D95bBK3Wa0TiZ4FNqKJvTa5jQ0Onh03eQ5eXKHJiqTcdw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-11-16T07:26:31Z" + mac: ENC[AES256_GCM,data:WliyDuYa0RUFoYOqqaYyXmmf8NYKe9sdOgSaOfSjhnHwvT4Z2nh+k/RR9fmpZ7qjrZFVdE9kfur21Mh6hKZnJ7vlA63u3YFq4Buu3fOdlSPLA3FRTeDbFy0kIDM2R4OqkXQrCVUFxGaQkG4lKw6XAKLZDnmQw9059wKRbbMTWpc=,iv:pU5RJCtoctkIy22VgFJPLEkmsgA/t4x1FwEJgkc1pdE=,tag:96pa5LoubQurpR8Yydcr2A==,type:str] + pgp: [] + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + version: 3.9.2 +--- +apiVersion: v1 +kind: Secret +metadata: + name: github-mcp-token + namespace: mcp +type: Opaque +stringData: + token: ENC[AES256_GCM,data:TDOzJ8eWs+q2y8//fGU5kQN9LBkuvZ0oYvDVG94XsJ9Ul33YBgGCjQ==,iv:hRF5eizLhux3YLoKuCYhdJzQr4jEyGItp6TfYq/OuZ4=,tag:9EiwNhGU/uZ4A0jxQZ4Dwg==,type:str] + owner: ENC[AES256_GCM,data:Wk1V8l0vw7EbHLc=,iv:IcOTaXB7l0+G0ewj33RmwOB14sCYNduO1jDsSTvvjv4=,tag:ois9qnprTmfo3DrtCc/pnQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1eTE4UEt0bzN4OWJuamNt + Mm9aZkNRdVZIckZuMmZNeWVGWkhhWTl2dERjCldzWVZxemQ2ZTJaOFF1cFBRcHFn + eENmcmhjaUNEOFZ1anNLWEpOcGJRVmMKLS0tIG05N1pldmY5d1ZXUVRleXlQWWx1 + dmJRbnFzNlZRZElTQVZ3RmNzVzRZWUUKkcXqeJd3Domjt7TlKn78HqgGiCOQ0whM + ZwgQ+6Q97D95bBK3Wa0TiZ4FNqKJvTa5jQ0Onh03eQ5eXKHJiqTcdw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-11-16T07:26:31Z" + mac: ENC[AES256_GCM,data:WliyDuYa0RUFoYOqqaYyXmmf8NYKe9sdOgSaOfSjhnHwvT4Z2nh+k/RR9fmpZ7qjrZFVdE9kfur21Mh6hKZnJ7vlA63u3YFq4Buu3fOdlSPLA3FRTeDbFy0kIDM2R4OqkXQrCVUFxGaQkG4lKw6XAKLZDnmQw9059wKRbbMTWpc=,iv:pU5RJCtoctkIy22VgFJPLEkmsgA/t4x1FwEJgkc1pdE=,tag:96pa5LoubQurpR8Yydcr2A==,type:str] + pgp: [] + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + version: 3.9.2 +--- +apiVersion: v1 +kind: Secret +metadata: + name: gitea-mcp-token + namespace: mcp +type: Opaque +stringData: + token: ENC[AES256_GCM,data:lmW9WhvdUiSa8rCN7KXHV6USg93QaWqyEA2XCPYshQWm5ZQ0VGza/Q==,iv:Kw6CbzqFKiqELTHZkABdnB1/WUhiP1yW9fXJ94TGSdY=,tag:jVQ8FbHfqwmiGHhsA+is8Q==,type:str] + owner: ENC[AES256_GCM,data:QBY6p1A=,iv:tqcrMSknyxs9DtKzXkotZGM2szY9/LO/9Aa0UKH2cG4=,tag:Gw0DFRNx3WZFld5ZGJY32g==,type:str] + url: ENC[AES256_GCM,data:mTZ85n5G1j3lphgIwMkKket3ARayHhvY8lCcquhrbIBCwBbTeo/zoT2fxTiU6w==,iv:1oZ2Aa+bTqqoqsUT4+cR43f5WSdzgspLFufrMS6Cq4g=,tag:9tker2sFgiC+fRvSo9/X0Q==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1c7ke5ajhtzua7lrvzsg2p7krnnqv5jhvafh4lsl2s022j46jggnss4rxry + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1eTE4UEt0bzN4OWJuamNt + Mm9aZkNRdVZIckZuMmZNeWVGWkhhWTl2dERjCldzWVZxemQ2ZTJaOFF1cFBRcHFn + eENmcmhjaUNEOFZ1anNLWEpOcGJRVmMKLS0tIG05N1pldmY5d1ZXUVRleXlQWWx1 + dmJRbnFzNlZRZElTQVZ3RmNzVzRZWUUKkcXqeJd3Domjt7TlKn78HqgGiCOQ0whM + ZwgQ+6Q97D95bBK3Wa0TiZ4FNqKJvTa5jQ0Onh03eQ5eXKHJiqTcdw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-11-16T07:26:31Z" + mac: ENC[AES256_GCM,data:WliyDuYa0RUFoYOqqaYyXmmf8NYKe9sdOgSaOfSjhnHwvT4Z2nh+k/RR9fmpZ7qjrZFVdE9kfur21Mh6hKZnJ7vlA63u3YFq4Buu3fOdlSPLA3FRTeDbFy0kIDM2R4OqkXQrCVUFxGaQkG4lKw6XAKLZDnmQw9059wKRbbMTWpc=,iv:pU5RJCtoctkIy22VgFJPLEkmsgA/t4x1FwEJgkc1pdE=,tag:96pa5LoubQurpR8Yydcr2A==,type:str] + pgp: [] + encrypted_regex: ^(data|stringData|password|token|apiKey|secret|key)$ + version: 3.9.2 diff --git a/platform/mcp-servers/values-full.yaml b/platform/mcp-servers/values-full.yaml new file mode 100644 index 0000000..b8ebed2 --- /dev/null +++ b/platform/mcp-servers/values-full.yaml @@ -0,0 +1,311 @@ +# MCP Umbrella Chart - Central Configuration +# This chart deploys all MCP servers and the central gateway + +# Global configuration shared across all MCP servers +global: + # Namespace to deploy all MCP services + namespace: mcp + + # Common labels applied to all resources + commonLabels: + app.kubernetes.io/part-of: mcp-ecosystem + managed-by: mcp-umbrella + + # Image pull policy for all charts + imagePullPolicy: IfNotPresent + + # Security context for all pods + securityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + +# ============================================================================= +# MCP Gateway Configuration +# ============================================================================= +mcp-gateway: + enabled: true + replicaCount: 1 + + service: + type: LoadBalancer + port: 3000 + # loadBalancerIP: "192.168.1.100" # Uncomment and set your LoadBalancer IP + + ingress: + enabled: false # Disabled by default, can enable later + className: "nginx" + hosts: + - host: mcp.caffeinetux.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: mcp-gateway-tls + hosts: + - mcp.caffeinetux.com + + gateway: + auth: + enabled: true + apiKeys: + - name: "n8n" + key: "" # SET THIS: Generate with: openssl rand -hex 32 + - name: "admin" + key: "" # SET THIS: Generate with: openssl rand -hex 32 + + logLevel: "info" + timeout: 30000 + + # MCP servers will be auto-populated from enabled servers below + servers: + n8n-mcp: + host: "n8n-mcp" + port: 3001 + playwright-mcp: + host: "playwright-mcp" + port: 3002 + kubernetes-mcp: + host: "kubernetes-mcp" + port: 3003 + github-mcp: + host: "github-mcp" + port: 3004 + postgresql-mcp: + host: "postgresql-mcp" + port: 3005 + sqlite-mcp: + host: "sqlite-mcp" + port: 3006 + prometheus-mcp: + host: "prometheus-mcp" + port: 3007 + slack-mcp: + host: "slack-mcp" + port: 3008 + s3-mcp: + host: "s3-mcp" + port: 3009 + filesystem-mcp: + host: "filesystem-mcp" + port: 3010 + puppeteer-mcp: + host: "puppeteer-mcp" + port: 3011 + fetch-mcp: + host: "fetch-mcp" + port: 3012 + memory-mcp: + host: "memory-mcp" + port: 3013 + gitea-mcp: + host: "gitea-mcp" + port: 3014 + + autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + +# ============================================================================= +# n8n MCP Server Configuration +# ============================================================================= +n8n-mcp: + enabled: true + + n8nMCP: + n8n: + url: "http://n8n.n8n.svc.cluster.local:5678" + apiKey: "" # SET THIS: Get from n8n settings + mode: "full" + logLevel: "info" + +# ============================================================================= +# Playwright MCP Server Configuration +# ============================================================================= +playwright-mcp: + enabled: true + + playwrightMCP: + browsers: + - chromium + - firefox + - webkit + headless: true + timeout: 30000 + + persistence: + enabled: true + size: 10Gi + + resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 200m + memory: 512Mi + +# ============================================================================= +# Kubernetes MCP Server Configuration +# ============================================================================= +kubernetes-mcp: + enabled: true + + rbac: + create: true + # ClusterRole permissions for kubectl operations + rules: + - apiGroups: [""] + resources: ["pods", "services", "configmaps", "secrets"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + - apiGroups: ["apps"] + resources: ["deployments", "statefulsets", "daemonsets"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + +# ============================================================================= +# GitHub MCP Server Configuration +# ============================================================================= +github-mcp: + enabled: true + + github: + token: "" # SET THIS: GitHub Personal Access Token + owner: "" # SET THIS: Default GitHub org/user + +# ============================================================================= +# PostgreSQL MCP Server Configuration +# ============================================================================= +postgresql-mcp: + enabled: false # Disabled by default - requires PostgreSQL instance + + postgresql: + host: "postgresql.default.svc.cluster.local" + port: 5432 + database: "postgres" + user: "postgres" + password: "" # SET THIS if enabling + +# ============================================================================= +# SQLite MCP Server Configuration +# ============================================================================= +sqlite-mcp: + enabled: true + + sqlite: + databasePath: "/data/sqlite.db" + + persistence: + enabled: true + size: 1Gi + +# ============================================================================= +# Prometheus MCP Server Configuration +# ============================================================================= +prometheus-mcp: + enabled: false # Disabled by default - requires Prometheus instance + + prometheus: + url: "http://prometheus-server.prometheus.svc.cluster.local" + +# ============================================================================= +# Slack MCP Server Configuration +# ============================================================================= +slack-mcp: + enabled: false # Disabled by default - requires Slack tokens + + slack: + botToken: "" # SET THIS: Slack Bot Token + appToken: "" # OPTIONAL: Slack App Token for socket mode + +# ============================================================================= +# S3 MCP Server Configuration +# ============================================================================= +s3-mcp: + enabled: false # Disabled by default - requires S3/MinIO credentials + + s3: + endpoint: "" # e.g., "s3.amazonaws.com" or MinIO endpoint + region: "us-east-1" + bucket: "" + accessKeyId: "" # SET THIS + secretAccessKey: "" # SET THIS + +# ============================================================================= +# Filesystem MCP Server Configuration +# ============================================================================= +filesystem-mcp: + enabled: true + + filesystem: + rootPath: "/data" + + persistence: + enabled: true + size: 5Gi + +# ============================================================================= +# Puppeteer MCP Server Configuration +# ============================================================================= +puppeteer-mcp: + enabled: false # Disabled by default - resource intensive + + puppeteer: + headless: true + timeout: 30000 + + persistence: + enabled: true + downloadSize: 5Gi + screenshotSize: 5Gi + + resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 500m + memory: 1Gi + +# ============================================================================= +# Fetch MCP Server Configuration +# ============================================================================= +fetch-mcp: + enabled: true + + fetch: + userAgent: "MCP-Fetch-Server/1.0" + timeout: 30000 + +# ============================================================================= +# Memory MCP Server Configuration (Central Coordinator) +# ============================================================================= +memory-mcp: + enabled: true + + storage: + backend: "redis" # or "postgres" + + # Redis backend configuration (if backend: redis) + redis: + host: "redis.default.svc.cluster.local" # Change to your Redis service + port: 6379 + password: "" # SET THIS if Redis requires auth + db: 0 + + # PostgreSQL backend configuration (if backend: postgres) + postgres: + host: "postgresql.default.svc.cluster.local" + port: 5432 + database: "memory_mcp" + user: "postgres" + password: "" # SET THIS if using postgres backend + + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi diff --git a/platform/mcp-servers/values.yaml b/platform/mcp-servers/values.yaml new file mode 100644 index 0000000..73056c2 --- /dev/null +++ b/platform/mcp-servers/values.yaml @@ -0,0 +1,270 @@ +# MCP Umbrella Chart - Central Configuration +# Secrets are managed in secrets.enc.yaml (SOPS-encrypted) + +# Global configuration shared across all MCP servers +global: + namespace: mcp + commonLabels: + app.kubernetes.io/part-of: mcp-ecosystem + managed-by: mcp-umbrella + imagePullPolicy: IfNotPresent + securityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + +# ============================================================================= +# MCP Gateway Configuration +# ============================================================================= +mcp-gateway: + enabled: true + replicaCount: 1 + + service: + type: LoadBalancer + port: 3000 + + ingress: + enabled: false + className: "nginx" + hosts: + - host: mcp.caffeinetux.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: mcp-gateway-tls + hosts: + - mcp.caffeinetux.com + + gateway: + auth: + enabled: true + # API keys loaded from Secret: mcp-gateway-api-keys + existingSecret: mcp-gateway-api-keys + + logLevel: "info" + timeout: 30000 + + servers: + n8n-mcp: + host: "n8n-mcp" + port: 3001 + playwright-mcp: + host: "playwright-mcp" + port: 3002 + kubernetes-mcp: + host: "kubernetes-mcp" + port: 3003 + github-mcp: + host: "github-mcp" + port: 3004 + postgresql-mcp: + host: "postgresql-mcp" + port: 3005 + sqlite-mcp: + host: "sqlite-mcp" + port: 3006 + prometheus-mcp: + host: "prometheus-mcp" + port: 3007 + slack-mcp: + host: "slack-mcp" + port: 3008 + s3-mcp: + host: "s3-mcp" + port: 3009 + filesystem-mcp: + host: "filesystem-mcp" + port: 3010 + puppeteer-mcp: + host: "puppeteer-mcp" + port: 3011 + fetch-mcp: + host: "fetch-mcp" + port: 3012 + memory-mcp: + host: "memory-mcp" + port: 3013 + gitea-mcp: + host: "gitea-mcp" + port: 3014 + + autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + +# ============================================================================= +# n8n MCP Server Configuration +# ============================================================================= +n8n-mcp: + enabled: true + n8nMCP: + n8n: + url: "http://n8n.n8n.svc.cluster.local:5678" + # API key loaded from Secret: n8n-mcp-api-key + existingSecret: n8n-mcp-api-key + mode: "full" + logLevel: "info" + +# ============================================================================= +# Playwright MCP Server Configuration +# ============================================================================= +playwright-mcp: + enabled: true + playwrightMCP: + browsers: + - chromium + - firefox + - webkit + headless: true + timeout: 30000 + persistence: + enabled: true + size: 10Gi + storageClassName: nfs-client + resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 200m + memory: 512Mi + +# ============================================================================= +# Kubernetes MCP Server Configuration +# ============================================================================= +kubernetes-mcp: + enabled: true + rbac: + create: true + rules: + - apiGroups: [""] + resources: ["pods", "services", "configmaps", "secrets"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + - apiGroups: ["apps"] + resources: ["deployments", "statefulsets", "daemonsets"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + +# ============================================================================= +# GitHub MCP Server Configuration +# ============================================================================= +github-mcp: + enabled: true + github: + # Token and owner loaded from Secret: github-mcp-token + existingSecret: github-mcp-token + +# ============================================================================= +# PostgreSQL MCP Server Configuration +# ============================================================================= +postgresql-mcp: + enabled: false + postgresql: + host: "postgresql.default.svc.cluster.local" + port: 5432 + database: "postgres" + user: "postgres" + +# ============================================================================= +# SQLite MCP Server Configuration +# ============================================================================= +sqlite-mcp: + enabled: true + sqlite: + databasePath: "/data/sqlite.db" + persistence: + enabled: true + size: 1Gi + +# ============================================================================= +# Prometheus MCP Server Configuration +# ============================================================================= +prometheus-mcp: + enabled: false + prometheus: + url: "http://prometheus-server.prometheus.svc.cluster.local" + +# ============================================================================= +# Slack MCP Server Configuration +# ============================================================================= +slack-mcp: + enabled: false + +# ============================================================================= +# S3 MCP Server Configuration +# ============================================================================= +s3-mcp: + enabled: false + s3: + region: "us-east-1" + +# ============================================================================= +# Filesystem MCP Server Configuration +# ============================================================================= +filesystem-mcp: + enabled: true + filesystem: + rootPath: "/data" + persistence: + enabled: true + size: 5Gi + +# ============================================================================= +# Puppeteer MCP Server Configuration +# ============================================================================= +puppeteer-mcp: + enabled: false + puppeteer: + headless: true + timeout: 30000 + persistence: + enabled: true + downloadSize: 5Gi + screenshotSize: 5Gi + resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 500m + memory: 1Gi + +# ============================================================================= +# Fetch MCP Server Configuration +# ============================================================================= +fetch-mcp: + enabled: true + fetch: + userAgent: "MCP-Fetch-Server/1.0" + timeout: 30000 + +# ============================================================================= +# Memory MCP Server Configuration +# ============================================================================= +memory-mcp: + enabled: true + storage: + backend: "redis" + redis: + host: "redis.default.svc.cluster.local" + port: 6379 + db: 0 + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + +# ============================================================================= +# Gitea MCP Server Configuration +# ============================================================================= +gitea-mcp: + enabled: true + gitea: + # Token, owner, and URL loaded from Secret: gitea-mcp-token + existingSecret: gitea-mcp-token