Docker Compose
6 min read
Docker Compose is the primary deployment method for the MCP Hub Platform. It orchestrates all services – application components and infrastructure – in a single configuration file.
Architecture Overview
The Docker Compose deployment runs the following services:
+-------------+
| hub-web | :8080
| (dashboard) |
+------+------+
|
+-------------+-------------+
| |
+---------+----------+ +-------------+---------+
| hub-ingestion- | | hub-results- |
| worker | | worker |
| (downloads code, | | (scoring, cert, |
| uploads to S3) | | publish to registry) |
+---------+----------+ +-------------+---------+
| |
+--------+ +-------------+
| |
+------+----+------+
| lavinmq | :5672 / :15672
| (AMQP broker) |
+------+----+------+
| |
+--------+ +-------------+
| |
+---------+----------+ +-------------+---------+
| scan-worker | | minio | :9000 / :9001
| (security analysis)| | (S3 storage)|
+--------------------+ +-------------+---------+
+-----------+ +----------+ +----------+
| postgres | | redis | | registry |
| :15432 | | :6390 | | :8081 |
+-----------+ +----------+ +----------+
Services
Application Services
| Service | Image | Port | Description |
|---|---|---|---|
| hub-web | mcp-hub | 8080 | Web dashboard and REST API. Serves the UI and handles user requests. |
| hub-ingestion-worker | mcp-hub | – | Processes ingestion jobs: downloads code from Git/uploads, packages tarballs, uploads to S3, publishes ANALYZE jobs to AMQP. |
| hub-results-worker | mcp-hub | – | Processes analysis results: downloads scan results from S3, runs controls mapping, computes scores, publishes certified artifacts to registry. |
| scan-worker | mcp-scan | 8083 | Security analysis worker: downloads source tarballs from S3, runs mcp-scan, uploads results to S3, publishes ANALYZE_COMPLETE to AMQP. |
| registry | mcp-registry | 8081 | Artifact distribution service: stores and serves certified MCP bundles and manifests. |
| hub-migrate | mcp-hub | – | Ephemeral container that runs database migrations on startup. Exits after completion. |
Infrastructure Services
| Service | Image | Port(s) | Description |
|---|---|---|---|
| postgres | postgres:16 | 15432 | PostgreSQL database. Hosts both mcphub and mcp_registry databases. |
| redis | redis:7-alpine | 6390 | Cache and rate limiting. Note: port 6390, not the default 6379. |
| minio | minio/minio | 9000, 9001 | S3-compatible object storage. Port 9000 is the API, port 9001 is the web console. |
| minio-init | minio/mc | – | Ephemeral container that creates required S3 buckets on startup. |
| lavinmq | cloudamqp/lavinmq | 5672, 15672 | AMQP message broker. Port 5672 is AMQP, port 15672 is the management UI. |
Quick Start
1. Clone and Configure
git clone https://github.com/your-org/mcp-hub-platform.git
cd mcp-hub-platform
2. Start All Services
docker compose -f docker-compose.local.yml up -d
3. Verify Health
docker compose -f docker-compose.local.yml ps
All services should show running (healthy) or Exited (0) (for init containers).
4. Access the Platform
| Service | URL | Credentials |
|---|---|---|
| Hub Dashboard | http://localhost:8080 | Auth0 login |
| Registry API | http://localhost:8081 | JWT token |
| MinIO Console | http://localhost:9001 | minioadmin / minioadmin |
| LavinMQ Admin | http://localhost:15672 | guest / guest |
Volume Configuration
The Docker Compose file defines persistent volumes for all stateful services:
| Volume | Service | Purpose |
|---|---|---|
postgres-data | postgres | Database files |
redis-data | redis | Cache persistence |
minio-data | minio | S3 object storage |
registry-data | registry | Registry artifact storage |
worker-workspace | hub-ingestion-worker | Temporary workspace for code processing |
scan-workspace | scan-worker | Temporary workspace for security analysis |
lavinmq-data | lavinmq | Message queue persistence |
Backing Up Volumes
# Backup PostgreSQL data
docker compose exec postgres pg_dumpall -U mcphub > backup.sql
# Backup MinIO data
docker compose exec minio mc mirror /data /backup
Resetting Volumes
Destroying volumes permanently deletes all data including databases, cached artifacts, and analysis results.
docker compose -f docker-compose.local.yml down
docker volume rm $(docker volume ls -q --filter "name=mcp-hub-platform")
docker compose -f docker-compose.local.yml up -d
Environment Variables
Hub Web
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | – | PostgreSQL connection string |
REDIS_URL | – | Redis connection string |
AMQP_URL | – | AMQP broker connection string |
AMQP_EXCHANGE | mcp.jobs | AMQP exchange name |
S3_ENDPOINT | – | S3/MinIO endpoint URL |
S3_ACCESS_KEY_ID | – | S3 access key |
S3_SECRET_ACCESS_KEY | – | S3 secret key |
S3_BUCKET | mcp-hub-sources | S3 bucket for source uploads |
S3_REGION | us-east-1 | S3 region |
S3_USE_PATH_STYLE | true | Use path-style URLs (required for MinIO) |
REGISTRY_URL | – | Registry internal URL |
REGISTRY_SERVICE_TOKEN | – | Token for hub-to-registry communication |
AUTH0_DOMAIN | – | Auth0 tenant domain |
AUTH0_CLIENT_ID | – | Auth0 client ID |
AUTH0_CLIENT_SECRET | – | Auth0 client secret |
AUTH0_CALLBACK_URL | – | Auth0 callback URL |
SESSION_SECRET | – | Session encryption secret (min 32 chars) |
ADMIN_USERS | – | Comma-separated admin email addresses |
LOG_LEVEL | info | Log verbosity: debug, info, warn, error |
SERVER_PORT | 8080 | HTTP listen port |
Scan Worker
| Variable | Default | Description |
|---|---|---|
AMQP_URL | – | AMQP broker connection string |
S3_ENDPOINT | – | S3/MinIO endpoint URL |
S3_ACCESS_KEY_ID | – | S3 access key |
S3_SECRET_ACCESS_KEY | – | S3 secret key |
S3_BUCKET_SOURCES | mcp-hub-sources | Bucket for source tarballs |
S3_BUCKET_ANALYSIS | mcp-hub-analysis | Bucket for analysis results |
S3_REGION | us-east-1 | S3 region |
SCAN_MODE | deep | Analysis mode: fast or deep |
SCAN_TIMEOUT | 30m | Maximum time per analysis job |
MAX_CONCURRENT | 5 | Maximum concurrent analysis jobs |
MCP_SCAN_WORKER_HEALTH_PORT | 8083 | Health check endpoint port |
LOG_LEVEL | info | Log verbosity |
Registry
| Variable | Default | Description |
|---|---|---|
MCP_REGISTRY_SERVER_LISTEN | :8081 | Listen address |
MCP_REGISTRY_DB_DSN | – | PostgreSQL connection string |
MCP_REGISTRY_STORAGE_TYPE | s3 | Storage backend type |
MCP_REGISTRY_STORAGE_S3_BUCKET | mcp-registry | S3 bucket name |
MCP_REGISTRY_STORAGE_S3_ENDPOINT | – | S3 endpoint |
MCP_REGISTRY_STORAGE_S3_ACCESS_KEY | – | S3 access key |
MCP_REGISTRY_STORAGE_S3_SECRET_KEY | – | S3 secret key |
MCP_REGISTRY_AUTH_MODE | oss | Auth mode: oss or enterprise |
MCP_REGISTRY_PUBLIC_READ_CATALOG | true | Allow unauthenticated catalog reads |
MCP_REGISTRY_PUBLIC_DOWNLOAD_ARTIFACTS | true | Allow unauthenticated downloads |
Health Checks
All services include Docker health checks:
| Service | Health Check | Interval |
|---|---|---|
| postgres | pg_isready -U mcphub | 5s |
| redis | redis-cli -p 6390 ping | 5s |
| minio | curl -f http://localhost:9000/minio/health/live | 5s |
| lavinmq | lavinmqctl status | 10s |
| hub-web | /app/bin/mcp-hub version | 10s |
| hub-ingestion-worker | /app/bin/mcp-hub version | 30s |
| hub-results-worker | /app/bin/mcp-hub version | 30s |
| scan-worker | wget --spider -q http://localhost:8083/healthz | 30s |
| registry | wget --spider -q http://localhost:8081/healthz | 5s |
Startup Dependencies
Services start in dependency order:
- postgres, redis, minio, lavinmq (infrastructure)
- minio-init (waits for minio healthy, creates buckets)
- hub-migrate (waits for postgres healthy, runs migrations)
- registry (waits for postgres, minio, redis healthy)
- hub-web, hub-ingestion-worker, hub-results-worker (wait for all infrastructure + registry + migrations)
- scan-worker (waits for minio, lavinmq, minio-init)
Production Hardening
Change Default Credentials
Replace all default credentials before deploying to production:
# PostgreSQL
POSTGRES_PASSWORD=<generate-strong-password>
# MinIO
MINIO_ROOT_USER=<generate-username>
MINIO_ROOT_PASSWORD=<generate-strong-password>
# Session secret (minimum 32 characters)
SESSION_SECRET=<generate-random-string-64-chars>
# Registry service token
REGISTRY_SERVICE_TOKEN=<generate-random-token>
The default credentials (minioadmin, guest/guest, etc.) are for local development only. Using them in production is a critical security vulnerability.
Enable TLS
For production, place a reverse proxy (Nginx, Caddy, Traefik) in front of the hub-web and registry services to terminate TLS:
# Example: add Caddy as reverse proxy
caddy:
image: caddy:2
ports:
- "443:443"
- "80:80"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
Resource Limits
Add resource limits to prevent any single service from consuming all host resources:
services:
hub-web:
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
scan-worker:
deploy:
resources:
limits:
cpus: '4.0'
memory: 4G
reservations:
cpus: '1.0'
memory: 1G
Persistent Storage
For production, use named volumes with a backup strategy or mount host directories:
volumes:
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: /data/postgres
Network Isolation
Use Docker networks to restrict communication between services:
networks:
mcp-network:
driver: bridge
internal: false # Set to true to block external access
db-network:
driver: bridge
internal: true # Database only accessible within this network
Log Management
Configure centralized logging:
services:
hub-web:
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
Common Operations
Viewing Logs
# All services
docker compose -f docker-compose.local.yml logs -f
# Specific service
docker compose -f docker-compose.local.yml logs -f hub-web
# Last 100 lines
docker compose -f docker-compose.local.yml logs --tail 100 scan-worker
Scaling Workers
# Scale scan workers for more analysis throughput
docker compose -f docker-compose.local.yml up -d --scale scan-worker=3
Restarting a Service
docker compose -f docker-compose.local.yml restart hub-web
Updating Images
docker compose -f docker-compose.local.yml pull
docker compose -f docker-compose.local.yml up -d