Mnemosyne MCP Server: Deployment Detail

Level 3 (Detail) — Build pipeline, Docker image, environment, and cluster deployment.

Concept

Mnemosyne is built as a multi-stage Docker image, published to Docker Hub via GitHub Actions, and deployed to the Kubernetes cluster via Flux GitOps with image automation.

Build Pipeline

Dockerfile (Dockerfile)

Multi-stage build:

StageBase ImagePurpose
buildergolang:1.23-bookwormCompile static binary with CGO_ENABLED=0
finalgcr.io/distroless/static-debian12Minimal runtime — no shell, no package manager

Build command:

RUN CGO_ENABLED=0 GOOS=linux go build -o mnemosyne-mcp cmd/mnemosyne-mcp/main.go

Entrypoint: /mnemosyne-mcp

Default env vars set in Dockerfile:

  • DB_PORT=5432
  • DB_USER=mnemosyne

GitHub Actions (publish.yml)

Trigger: push to main branch

Steps:

  1. Checkout code
  2. Login to Docker Hub (roberto.tazzoli@gmail.com / DOCKER_PASSWORD secret)
  3. Build and push with two tags:
    • tazzo/mnemosyne-mcp:latest
    • tazzo/mnemosyne-mcp:mcp-<run_number>-<sha>

Required Environment Variables

VariableSourceDescription
DB_HOSTtazlab-db-pguser-mnemosyne secretPostgreSQL host
DB_PORTDockerfile default (5432)PostgreSQL port
DB_USERtazlab-db-pguser-mnemosyne secretPostgreSQL user
DB_PASStazlab-db-pguser-mnemosyne secretPostgreSQL password
DB_NAMEtazlab-db-pguser-mnemosyne secretDatabase name
GEMINI_API_KEYmnemosyne-mcp-secrets ExternalSecretGemini embedding API key

Optional Environment Variables

VariableDefaultDescription
MCP_TRANSPORTstdioTransport mode: "" for stdio, "http" for HTTP (SSE streaming disabled to avoid client hangs)
PORT8080HTTP port (only used when MCP_TRANSPORT=http)
LOG_FORMATtextLog format: "text" for human-readable, "json" for structured

Image Automation (Flux)

File: tazlab-k8s/infrastructure/automation/mnemosyne-mcp/automation.yaml

  • ImageRepository: tazzo/mnemosyne-mcp, polled every 1m
  • ImagePolicy: numerical: order: asc on tag pattern mcp-(<N>)-...
  • ImageUpdateAutomation: updates deployment in apps/base/mnemosyne-mcp on master branch

Tag contract: mcp-<run_number>-<sha> — immutable, ascending by run number.

Cluster Deployment

Kubernetes Manifests (tazlab-k8s/apps/base/mnemosyne-mcp/)

FilePurpose
deployment.yamlMain deployment in namespace tazlab-db
service.yamlLoadBalancer service on port 8004 → 8080, IP 192.168.1.240
rbac.yamlServiceAccount + Role for secret reading
external-secret.yamlFetches GEMINI_API_KEY from tazlab-secrets ClusterSecretStore
kustomization.yamlKustomize root, applies wait-for-db-patch

Deployment spec:

  • Image: tazzo/mnemosyne-mcp:mcp-<N>-<sha> (set by image automation marker)
  • Replicas: 1
  • ServiceAccount: mnemosyne-mcp-sa
  • Resources: requests 50m CPU / 128Mi, limits 200m CPU / 256Mi
  • Transport: MCP_TRANSPORT=http (HTTP mode for cluster)
  • Reloader annotation: reloads on tazlab-db-pguser-mnemosyne or mnemosyne-mcp-secrets changes

Network

  • Service type: LoadBalancer (MetalLB)
  • Port mapping: 8004 (external) → 8080 (container)
  • Shared IP pool: tazlab-internal-dashboard
  • Allowed on IP: 192.168.1.240

Database Dependency

The deployment applies wait-for-db-patch.yaml — an init container that blocks until the PostgreSQL database is reachable. This prevents the server from starting before the database is ready.

Deployment Architecture

GitHub Push (main)
       │
       ▼
GitHub Actions → Docker Hub (tazzo/mnemosyne-mcp:mcp-<N>-<sha>)
       │
       ▼
Flux ImageAutomation (polls every 1m)
       │
       ▼
deployment.yaml updated → Flux reconciliation
       │
       ▼
Pod in namespace tazlab-db
       │
       ▼
Service LoadBalancer :8004 → :8080/mcp

See Also