Cloud Deployment Guide: HTTP-based MCP Integration

November 23, 2025 · View on GitHub

This guide demonstrates how to deploy mcpui-test-server and agui-test-server as independent long-running processes in a cloud environment, communicating via HTTP.

Overview

Instead of using stdio (process spawning), both servers run as independent services and communicate over HTTP:

┌─────────────────────────┐
│  agui-test-server       │
│  HTTP Client            │
└──────────┬──────────────┘

           │ HTTP/HTTPS
           │ (network)

┌──────────▼──────────────┐
│  mcpui-test-server      │
│  HTTP Server            │
└─────────────────────────┘

Configuration

mcpui-test-server (.env)

PORT=3100
HOST=0.0.0.0
NODE_ENV=production
SERVER_NAME=mcpui-test-server
SERVER_VERSION=1.0.0
LOG_LEVEL=info
LOG_PRETTY=false
CORS_ORIGIN=*
SESSION_TIMEOUT=3600000

agui-test-server (.env)

PORT=3000
HOST=0.0.0.0
NODE_ENV=production

# Agent configuration
AGENT_MODE=llm
DEFAULT_AGENT=litellm

# LLM Provider
LLM_PROVIDER=litellm
LITELLM_ENDPOINT=http://litellm:4000/v1
LITELLM_MODEL=deepseek-chat
LITELLM_API_KEY=your-api-key

# MCP Integration - HTTP Transport
MCP_SERVER_URL=http://mcpui-test-server:3100/mcp

# Logging
LOG_LEVEL=info
LOG_PRETTY=false

# CORS
CORS_ORIGIN=*

Deployment Options

Option 1: Docker Compose

Create docker-compose.yml:

version: '3.8'

services:
  # MCP-UI Server - Provides MCP tools via HTTP
  mcpui-test-server:
    build: ./mcpui-test-server
    container_name: mcpui-test-server
    ports:
      - "3100:3100"
    environment:
      - PORT=3100
      - HOST=0.0.0.0
      - NODE_ENV=production
      - LOG_LEVEL=info
      - CORS_ORIGIN=*
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3100/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    restart: unless-stopped
    networks:
      - app-network

  # AG-UI Server - Agent server that uses MCP tools
  agui-test-server:
    build: ./agui-test-server
    container_name: agui-test-server
    ports:
      - "3000:3000"
    environment:
      - PORT=3000
      - HOST=0.0.0.0
      - NODE_ENV=production
      - AGENT_MODE=llm
      - LLM_PROVIDER=litellm
      - LITELLM_ENDPOINT=http://litellm:4000/v1
      - LITELLM_MODEL=deepseek-chat
      - LITELLM_API_KEY=${LITELLM_API_KEY}
      # HTTP MCP Transport
      - MCP_SERVER_URL=http://mcpui-test-server:3100/mcp
      - LOG_LEVEL=info
    depends_on:
      mcpui-test-server:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    restart: unless-stopped
    networks:
      - app-network

  # Optional: LiteLLM Proxy (if using LiteLLM)
  litellm:
    image: ghcr.io/berriai/litellm:latest
    container_name: litellm
    ports:
      - "4000:4000"
    environment:
      - LITELLM_MASTER_KEY=sk-1234
    command: 
      - "--model"
      - "deepseek/deepseek-chat"
      - "--api_key"
      - "${DEEPSEEK_API_KEY}"
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Dockerfiles:

mcpui-test-server/Dockerfile:

FROM node:20-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --production

# Copy source
COPY . .

# Build TypeScript
RUN npm run build

# Expose port
EXPOSE 3100

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3100/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"

# Start server
CMD ["node", "dist/server.js"]

agui-test-server/Dockerfile:

FROM node:20-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --production

# Copy source
COPY . .

# Build TypeScript
RUN npm run build

# Expose port
EXPOSE 3000

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"

# Start server
CMD ["node", "dist/server.js"]

Running:

# Build and start all services
docker-compose up -d

# View logs
docker-compose logs -f

# Check health
curl http://localhost:3100/health
curl http://localhost:3000/health

# Stop services
docker-compose down

Option 2: Kubernetes

Create kubernetes/:

mcpui-server-deployment.yaml:

apiVersion: v1
kind: Service
metadata:
  name: mcpui-test-server
  labels:
    app: mcpui-test-server
spec:
  type: ClusterIP
  ports:
    - port: 3100
      targetPort: 3100
      protocol: TCP
      name: http
  selector:
    app: mcpui-test-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcpui-test-server
  labels:
    app: mcpui-test-server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mcpui-test-server
  template:
    metadata:
      labels:
        app: mcpui-test-server
    spec:
      containers:
      - name: mcpui-test-server
        image: your-registry/mcpui-test-server:1.0.0
        ports:
        - containerPort: 3100
          name: http
        env:
        - name: PORT
          value: "3100"
        - name: HOST
          value: "0.0.0.0"
        - name: NODE_ENV
          value: "production"
        - name: LOG_LEVEL
          value: "info"
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3100
          initialDelaySeconds: 10
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 3100
          initialDelaySeconds: 5
          periodSeconds: 10

agui-server-deployment.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: agui-config
data:
  PORT: "3000"
  HOST: "0.0.0.0"
  NODE_ENV: "production"
  AGENT_MODE: "llm"
  LLM_PROVIDER: "litellm"
  LITELLM_ENDPOINT: "http://litellm:4000/v1"
  LITELLM_MODEL: "deepseek-chat"
  MCP_SERVER_URL: "http://mcpui-test-server:3100/mcp"
  LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
  name: agui-secrets
type: Opaque
stringData:
  LITELLM_API_KEY: "your-api-key-here"
---
apiVersion: v1
kind: Service
metadata:
  name: agui-test-server
  labels:
    app: agui-test-server
spec:
  type: LoadBalancer
  ports:
    - port: 3000
      targetPort: 3000
      protocol: TCP
      name: http
  selector:
    app: agui-test-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: agui-test-server
  labels:
    app: agui-test-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: agui-test-server
  template:
    metadata:
      labels:
        app: agui-test-server
    spec:
      containers:
      - name: agui-test-server
        image: your-registry/agui-test-server:1.0.0
        ports:
        - containerPort: 3000
          name: http
        envFrom:
        - configMapRef:
            name: agui-config
        - secretRef:
            name: agui-secrets
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 10

Deploying:

# Create namespace
kubectl create namespace compliance-servers

# Apply configurations
kubectl apply -f kubernetes/ -n compliance-servers

# Check status
kubectl get pods -n compliance-servers
kubectl get services -n compliance-servers

# View logs
kubectl logs -f deployment/agui-test-server -n compliance-servers
kubectl logs -f deployment/mcpui-test-server -n compliance-servers

# Test connectivity
kubectl port-forward service/agui-test-server 3000:3000 -n compliance-servers
curl http://localhost:3000/health

Option 3: Cloud Platform (AWS ECS, Google Cloud Run, Azure Container Instances)

AWS ECS Task Definition Example:

{
  "family": "compliance-servers",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "1024",
  "memory": "2048",
  "containerDefinitions": [
    {
      "name": "mcpui-test-server",
      "image": "your-ecr-registry/mcpui-test-server:1.0.0",
      "portMappings": [
        {
          "containerPort": 3100,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {"name": "PORT", "value": "3100"},
        {"name": "HOST", "value": "0.0.0.0"},
        {"name": "NODE_ENV", "value": "production"}
      ],
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3100/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/mcpui-test-server",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    },
    {
      "name": "agui-test-server",
      "image": "your-ecr-registry/agui-test-server:1.0.0",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {"name": "PORT", "value": "3000"},
        {"name": "HOST", "value": "0.0.0.0"},
        {"name": "NODE_ENV", "value": "production"},
        {"name": "AGENT_MODE", "value": "llm"},
        {"name": "MCP_SERVER_URL", "value": "http://localhost:3100/mcp"}
      ],
      "secrets": [
        {
          "name": "LITELLM_API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:litellm-api-key"
        }
      ],
      "dependsOn": [
        {
          "containerName": "mcpui-test-server",
          "condition": "HEALTHY"
        }
      ],
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/agui-test-server",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ]
}

Monitoring and Observability

Health Checks

Both servers expose /health endpoints:

# Check mcpui-test-server
curl http://mcpui-server:3100/health
# Response: {"status":"ok","timestamp":"...","uptime":123.45,"sessions":5}

# Check agui-test-server
curl http://agui-server:3000/health
# Response: {"status":"ok","timestamp":"...","uptime":123.45,"sessions":5}

Logging

Configure structured JSON logging in production:

LOG_LEVEL=info
LOG_PRETTY=false

Logs include:

  • HTTP MCP transport connection events
  • MCP session establishment
  • Tool calls and results
  • Error conditions

Metrics

Monitor these key metrics:

  • HTTP response times
  • MCP session count
  • Tool call success/failure rates
  • Memory and CPU usage
  • Network connectivity between services

Alerting

Set up alerts for:

  • Health check failures
  • HTTP 5xx errors
  • MCP connection failures
  • High latency (>5s for tool calls)
  • Memory/CPU limits reached

Security Best Practices

1. Network Security

# Use internal networking
networks:
  internal:
    driver: bridge
    internal: true  # No external access
  
  external:
    driver: bridge

2. API Authentication

Add API key authentication:

// mcpui-test-server middleware
app.use('/mcp', (req, res, next) => {
  const apiKey = req.headers['x-api-key'];
  if (!apiKey || apiKey !== process.env.MCP_API_KEY) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
});

Configure in agui-test-server:

MCP_SERVER_URL=http://mcpui-test-server:3100/mcp
MCP_API_KEY=your-secure-api-key

3. TLS/HTTPS

Use HTTPS in production:

MCP_SERVER_URL=https://mcpui-server.internal:3100/mcp

4. Rate Limiting

import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100
});

app.use('/mcp', limiter);

Troubleshooting

Connection Issues

# Test network connectivity
docker exec agui-test-server curl http://mcpui-test-server:3100/health

# Check DNS resolution
docker exec agui-test-server nslookup mcpui-test-server

# View logs
docker logs agui-test-server | grep "HTTP transport"
docker logs mcpui-test-server | grep "MCP"

Common Issues

Issue: Connection refused

Solution: Ensure mcpui-test-server is running and healthy before starting agui-test-server
Check: docker-compose depends_on with condition: service_healthy

Issue: Session timeout

Solution: Increase SESSION_TIMEOUT in mcpui-test-server
Default: 3600000 (1 hour)

Issue: High latency

Solution: 
- Ensure both services are in same network/region
- Check network policies and firewalls
- Monitor service resources (CPU/memory)

Performance Tuning

Scaling

Horizontal Scaling:

# Scale mcpui-test-server
docker-compose up -d --scale mcpui-test-server=3

# Kubernetes
kubectl scale deployment mcpui-test-server --replicas=5

Load Balancing:

# Add load balancer for mcpui-test-server
services:
  mcpui-lb:
    image: nginx:alpine
    ports:
      - "3100:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - mcpui-test-server

Caching

Consider adding Redis for session caching:

services:
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"

Testing Deployment

# 1. Start services
docker-compose up -d

# 2. Wait for health checks
sleep 10

# 3. Test MCP connection
curl -X POST http://localhost:3100/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'

# 4. Test AG-UI endpoint
curl -X POST http://localhost:3000/agent \
  -H "Content-Type: application/json" \
  -d '{"threadId":"test","runId":"run_1","messages":[{"id":"1","role":"user","content":"hello"}]}'

# 5. Check logs for HTTP transport
docker logs agui-test-server 2>&1 | grep "HTTP transport"

Summary

This deployment approach provides:

  • ✅ Independent, scalable services
  • ✅ Network-based communication (suitable for cloud)
  • ✅ Easy horizontal scaling
  • ✅ Standard cloud deployment patterns
  • ✅ Proper health monitoring
  • ✅ Clean separation of concerns

Both servers run as long-running processes, communicating over HTTP, which is ideal for cloud deployments.