Copy # vCON MCP with Self-Hosted Supabase
#
# Usage:
# Start: docker compose up -d
# Stop: docker compose down
# Logs: docker compose logs -f
# Status: docker compose ps
name: vcon-mcp
services:
# ===========================================
# Ofelia Job Scheduler
# ===========================================
ofelia:
container_name: vcon-mcp-ofelia
image: mcuadros/ofelia:latest
restart: unless-stopped
depends_on:
vcon-mcp:
condition: service_healthy
command: daemon --docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# ===========================================
# vCON MCP Server - Main Application
# ===========================================
vcon-mcp:
container_name: vcon-mcp
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-mcp:main
restart: unless-stopped
ports:
- "3002:3000"
depends_on:
vcon-supabase-kong:
condition: service_started
environment:
- SUPABASE_URL=http://vcon-supabase-kong:8000
- SUPABASE_SERVICE_ROLE_KEY=${SERVICE_ROLE_KEY}
- SUPABASE_ANON_KEY=${ANON_KEY}
- MCP_HTTP_STATELESS=true
- MCP_TRANSPORT=http
- MCP_HTTP_HOST=0.0.0.0
- MCP_HTTP_PORT=3000
#
# Embedding Configuration - Choose ONE provider:
#
# Option 1: Azure OpenAI
- AZURE_OPENAI_EMBEDDING_ENDPOINT=https://your-resource.openai.azure.com
- AZURE_OPENAI_EMBEDDING_API_VERSION=2023-05-15
- AZURE_OPENAI_EMBEDDING_API_KEY=your-azure-api-key
#
# Option 2: OpenAI (uncomment and configure)
# - OPENAI_API_KEY=your-openai-api-key
#
# Option 3: Hugging Face (uncomment and configure)
# - HUGGINGFACE_API_KEY=your-huggingface-api-key
#
# Tool categories: read, write, schema, analytics, infra
# Only enable read operations for production deployments
- MCP_ENABLED_CATEGORIES=read
- VCON_API_KEYS=your-vcon-api-key
labels:
ofelia.enabled: "true"
ofelia.job-exec.embed-vcons.schedule: "0 */10 * * *"
ofelia.job-exec.embed-vcons.command: "/app/docker-entrypoint.sh script embed-vcons --continuous --limit=500"
ofelia.job-exec.embed-vcons.no-overlap: "true"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
# ===========================================
# Supabase Core Services
# ===========================================
# PostgreSQL Database
vcon-supabase-db:
container_name: vcon-supabase-db
image: supabase/postgres:15.8.1.085
restart: unless-stopped
volumes:
- ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
- ./volumes/db/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:Z
- ./volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:Z
- ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z
- ./volumes/db/data:/var/lib/postgresql/data:Z
- ./volumes/db/_supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:Z
- ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z
- ./volumes/db/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:Z
- vcon-db-config:/etc/postgresql-custom
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10
environment:
POSTGRES_HOST: /var/run/postgresql
PGPORT: ${POSTGRES_PORT}
POSTGRES_PORT: ${POSTGRES_PORT}
PGPASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: ${POSTGRES_DB}
POSTGRES_DB: ${POSTGRES_DB}
JWT_SECRET: ${JWT_SECRET}
JWT_EXP: ${JWT_EXPIRY}
command:
- postgres
- -c
- config_file=/etc/postgresql/postgresql.conf
- -c
- log_min_messages=fatal
# Kong API Gateway
vcon-supabase-kong:
container_name: vcon-supabase-kong
image: kong:2.8.1
restart: unless-stopped
ports:
- "${KONG_HTTP_PORT}:8000/tcp"
volumes:
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
depends_on:
vcon-supabase-auth:
condition: service_healthy
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
KONG_DNS_ORDER: LAST,A,CNAME
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
DASHBOARD_USERNAME: ${DASHBOARD_USERNAME}
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
# GoTrue - Authentication Server
vcon-supabase-auth:
container_name: vcon-supabase-auth
image: supabase/gotrue:v2.184.0
restart: unless-stopped
depends_on:
vcon-supabase-db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9999/health"]
timeout: 5s
interval: 5s
retries: 3
environment:
GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999
API_EXTERNAL_URL: ${API_EXTERNAL_URL}
GOTRUE_DB_DRIVER: postgres
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
GOTRUE_SITE_URL: ${SITE_URL}
GOTRUE_URI_ALLOW_LIST: ${ADDITIONAL_REDIRECT_URLS}
GOTRUE_DISABLE_SIGNUP: ${DISABLE_SIGNUP}
GOTRUE_JWT_ADMIN_ROLES: service_role
GOTRUE_JWT_AUD: authenticated
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
GOTRUE_JWT_SECRET: ${JWT_SECRET}
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM}
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
GOTRUE_SMTP_HOST: ${SMTP_HOST}
GOTRUE_SMTP_PORT: ${SMTP_PORT}
GOTRUE_SMTP_USER: ${SMTP_USER}
GOTRUE_SMTP_PASS: ${SMTP_PASS}
GOTRUE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME}
GOTRUE_MAILER_URLPATHS_INVITE: ${MAILER_URLPATHS_INVITE}
GOTRUE_MAILER_URLPATHS_CONFIRMATION: ${MAILER_URLPATHS_CONFIRMATION}
GOTRUE_MAILER_URLPATHS_RECOVERY: ${MAILER_URLPATHS_RECOVERY}
GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE: ${MAILER_URLPATHS_EMAIL_CHANGE}
GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM}
# PostgREST - Database REST API
vcon-supabase-rest:
container_name: vcon-supabase-rest
image: postgrest/postgrest:v14.1
restart: unless-stopped
depends_on:
vcon-supabase-db:
condition: service_healthy
environment:
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
PGRST_DB_ANON_ROLE: anon
PGRST_JWT_SECRET: ${JWT_SECRET}
PGRST_DB_USE_LEGACY_GUCS: "false"
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXPIRY}
command: ["postgrest"]
# Storage API
vcon-supabase-storage:
container_name: vcon-supabase-storage
image: supabase/storage-api:v1.33.0
restart: unless-stopped
volumes:
- ./volumes/storage:/var/lib/storage:z
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5000/status"]
timeout: 5s
interval: 5s
retries: 3
depends_on:
vcon-supabase-db:
condition: service_healthy
vcon-supabase-rest:
condition: service_started
environment:
ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY}
POSTGREST_URL: http://vcon-supabase-rest:3000
PGRST_JWT_SECRET: ${JWT_SECRET}
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
REQUEST_ALLOW_X_FORWARDED_PATH: "true"
FILE_SIZE_LIMIT: 52428800
STORAGE_BACKEND: file
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
TENANT_ID: stub
REGION: stub
GLOBAL_S3_BUCKET: stub
ENABLE_IMAGE_TRANSFORMATION: "false"
volumes:
vcon-db-config: