Skip to content

Deployment Guide

Deploy the Natural Language Agent as an HTTP/HTTPS service. Choose your method:

For Claude Desktop integration (stdio mode), see the Quick Start.


Docker Compose

The recommended deployment method using pre-built containers.

Quick Start

# Clone repository
git clone https://github.com/pgEdge/pgedge-postgres-mcp.git
cd pgedge-postgres-mcp

# Configure
cp .env.example .env
# Edit .env with your settings

# Start all services
docker-compose up -d

Available Containers

Container Port Description
mcp-server 8080 MCP server with PostgreSQL access
web-client 8081 React web interface

Configuration

All settings are in the .env file:

# Database Connection
PGEDGE_DB_HOST=host.docker.internal
PGEDGE_DB_PORT=5432
PGEDGE_DB_NAME=mydb
PGEDGE_DB_USER=postgres
PGEDGE_DB_PASSWORD=secret
PGEDGE_DB_SSLMODE=prefer

# LLM Provider
PGEDGE_LLM_PROVIDER=anthropic  # or openai, ollama
PGEDGE_LLM_MODEL=claude-sonnet-4-20250514
PGEDGE_ANTHROPIC_API_KEY=sk-ant-...

# Authentication
INIT_USERS=admin:password123
# Or for API tokens: INIT_TOKENS=token1,token2

# Optional: Embeddings
PGEDGE_EMBEDDING_ENABLED=true
PGEDGE_EMBEDDING_PROVIDER=voyage
PGEDGE_EMBEDDING_MODEL=voyage-3

API Key Security

For production, mount API key files instead of using environment variables:

volumes:
  - ~/.anthropic-api-key:/app/.anthropic-api-key:ro

Data Persistence

The MCP server stores persistent data in a dedicated directory:

  • Authentication tokens (tokens.json)
  • User credentials (users.json)
  • Conversation history (conversations.db)
  • User preferences

The Docker Compose configuration mounts a named volume (mcp-data) to /app/data, ensuring data persists across container restarts.

To use a custom host path instead of a named volume:

volumes:
  # Mount host directory instead of named volume
  - ./data:/app/data

Permissions

Ensure the host directory has appropriate permissions (owned by UID 1001) or the container may fail to start:

mkdir -p ./data && chown 1001:1001 ./data

You can also configure a custom data directory location via environment variable:

PGEDGE_DATA_DIR=/var/lib/pgedge/data

Container Management

# View logs
docker-compose logs -f mcp-server

# Restart services
docker-compose restart

# Stop services
docker-compose down

# Rebuild after code changes
docker-compose build && docker-compose up -d

Connecting to Host PostgreSQL

Use host.docker.internal instead of localhost:

PGEDGE_DB_HOST=host.docker.internal

On Linux, you may need to use the Docker bridge IP (172.17.0.1).


Native Binary

Build

git clone https://github.com/pgEdge/pgedge-postgres-mcp.git
cd pgedge-postgres-mcp
make build

Basic HTTP Server

# Set database connection
export PGHOST=localhost PGPORT=5432 PGDATABASE=mydb
export PGUSER=myuser PGPASSWORD=mypass

# Start HTTP server
./bin/pgedge-postgres-mcp -http

HTTPS with TLS

# Self-signed certificate (testing only)
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt \
  -days 365 -nodes -subj "/CN=localhost"

# Start HTTPS server
./bin/pgedge-postgres-mcp -http -tls -cert server.crt -key server.key

For production, use certificates from Let's Encrypt or your CA:

./bin/pgedge-postgres-mcp -http -tls \
  -cert /etc/letsencrypt/live/domain.com/fullchain.pem \
  -key /etc/letsencrypt/live/domain.com/privkey.pem

Command Line Options

Flag Description
-http Enable HTTP mode
-addr :PORT Listen address (default: :8080)
-tls Enable HTTPS
-cert PATH TLS certificate file
-key PATH TLS private key file
-no-auth Disable authentication (dev only)
-config PATH Configuration file path

Systemd Service

For Linux production deployments.

Create Service File

/etc/systemd/system/pgedge-postgres-mcp.service:

[Unit]
Description=pgEdge Natural Language Agent
After=network.target postgresql.service

[Service]
Type=simple
User=pgedge
Group=pgedge
WorkingDirectory=/opt/pgedge
ExecStart=/opt/pgedge/bin/pgedge-postgres-mcp -config /etc/pgedge/config.yaml
Restart=always
RestartSec=10

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

Enable and Start

sudo systemctl daemon-reload
sudo systemctl enable pgedge-postgres-mcp
sudo systemctl start pgedge-postgres-mcp
sudo systemctl status pgedge-postgres-mcp

View Logs

journalctl -u pgedge-postgres-mcp -f

Reverse Proxy

For production, run behind nginx with TLS termination.

Nginx Configuration

server {
    listen 443 ssl http2;
    server_name mcp.example.com;

    ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name mcp.example.com;
    return 301 https://$host$request_uri;
}

Health Checks

All deployment methods expose a health endpoint:

curl http://localhost:8080/health

Response:

{"status": "ok", "server": "pgedge-postgres-mcp", "version": "1.0.0"}


Troubleshooting

Port Already in Use

lsof -i :8080
# Kill the process or use a different port with -addr

Database Connection Failed

# Test connection directly
psql -h localhost -U postgres -d mydb -c "SELECT 1"

# Check environment variables
env | grep PG

Docker Can't Reach Host Database

  • macOS/Windows: Use host.docker.internal
  • Linux: Use 172.17.0.1 or configure Docker network

Certificate Issues

# Verify certificate matches key
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# Both should match

# Check expiration
openssl x509 -in server.crt -noout -dates

See Also