Deployment

Deployment

Production deployment guide with Docker Compose, database migrations, and webhook registration.

This document describes how to deploy the Meta Business MCP system in a production environment.

Prerequisites

  • Docker & Docker Compose (version 20.10+ / Compose V2)
  • PostgreSQL 16 (or AWS RDS PostgreSQL)
  • Redis 7 (or AWS ElastiCache Redis)
  • NATS Server (with JetStream enabled)
  • WhatsApp Business API Account Credentials (from Meta Developer Console)

Infrastructure Dependencies

DependencyMinimum VersionNotes
PostgreSQL16AWS RDS compatible
Redis7AWS ElastiCache compatible
NATS ServerLatest stableMust enable JetStream (--jetstream)
Go1.21+Build only
Docker20.10+Compose V2 required

1. Environment Configuration

Create a production .env configuration file in your project root:

# Server settings
SERVER_HTTP_PORT=8080
SERVER_MCP_NAME=meta-business-mcp
SERVER_MCP_VERSION=1.0.0
TIER=oss

# Database connections
DB_HOST=postgres.prod.internal
DB_PORT=5432
DB_USER=mcp_user
DB_PASSWORD=production_secure_postgres_pass
DB_NAME=meta_mcp
DB_SSLMODE=require

# Cache connection
REDIS_ADDR=redis.prod.internal:6379
REDIS_PASSWORD=production_redis_auth_pass
REDIS_DB=0

# Message broker connection
NATS_URL=nats://nats.prod.internal:4222

# Meta Cloud API credentials
META_API_URL=https://graph.facebook.com
META_ACCESS_TOKEN=EAAG...production_long_lived_system_user_token...
META_PHONE_NUMBER_ID=106555123456789
META_WABA_ID=204555123456789
META_WEBHOOK_VERIFY_TOKEN=production_webhook_verification_passphrase

# Policies file path
POLICIES_PATH=/app/policies.yaml
SCHEDULER_POLL_INTERVAL=30s

2. Docker Compose Deployment

A standard production docker-compose.prod.yaml:

services:
  postgres:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_USER: mcp_user
      POSTGRES_PASSWORD: production_secure_postgres_pass
      POSTGRES_DB: meta_mcp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mcp_user -d meta_mcp"]
      interval: 10s
      timeout: 5s
      retries: 5
 
  redis:
    image: redis:7-alpine
    restart: always
    command: redis-server --requirepass production_redis_auth_pass
    volumes:
      - redisdata:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "production_redis_auth_pass", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
 
  nats:
    image: nats:alpine
    restart: always
    command: "--jetstream -m 8222"
    ports:
      - "4222:4222"
    volumes:
      - natsdata:/data
    healthcheck:
      test: ["CMD", "nc", "-z", "localhost", "4222"]
      interval: 10s
      timeout: 5s
      retries: 5
 
  app:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - ./policies.yaml:/app/policies.yaml
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      nats:
        condition: service_healthy
 
volumes:
  pgdata:
  redisdata:
  natsdata:

Launch Services

docker compose -f docker-compose.prod.yaml up -d --build

3. Build the Binary (Non-Docker)

go build -o mcp-server ./cmd/server/main.go

4. Database Migrations & Seeding

No external migration runner is required. On startup, the application automatically:

  1. Creates all database tables (customers, conversations, messages, templates, policies, campaigns, message_frequencies, error_knowledge_base, audit_logs, conversation_pricing).
  2. Seeds standard Meta error codes into error_knowledge_base.
  3. Seeds business policies from policies.yaml using idempotent ON CONFLICT DO UPDATE.
  4. Seeds conversation pricing data for ID, US, IN, BR, GB, and DEFAULT fallback.

All schema changes use IF NOT EXISTS / ADD COLUMN IF NOT EXISTS. Existing deployments upgrade by restarting the application.

5. Webhook Registration

Register the public URL in the Meta App Developer Portal:

  • Verification: GET /webhook — responds with hub.challenge.
  • Events: POST /webhook — receives inbound messages, status updates, and template events.
  • Signature validation: X-Hub-Signature-256 header is verified on all POST events.

6. Health Checks & Verification

# Verify health check
curl http://localhost:8080/health
# Response: OK
 
# Verify Prometheus metrics
curl http://localhost:8080/metrics
# Response: Prometheus metric scrape output

Observability Endpoints

EndpointMethodResponse
/healthGET200 OK — body: "OK"
/metricsGET200 OK — Prometheus scrape payload
/webhookGET200 OK — webhook challenge echo
/webhookPOST200 OK — body: "EVENT_RECEIVED"

Logging

Structured logs are written to stdout/stderr. Collect via Docker:

docker compose logs -f app

NATS Monitoring

NATS monitoring HTTP interface is available at :8222. Stream and consumer stats: http://localhost:8222/jsz.