#!/bin/bash
################################################################################
# Deployment Script for KYC MCP Server
# This script handles the deployment of the application with health checks
# and automatic rollback on failure
################################################################################
set -euo pipefail
# Configuration
APP_DIR="/opt/kyc-mcp-server"
BACKUP_DIR="/opt/kyc-mcp-server-backups"
MAX_BACKUPS=5
HEALTH_CHECK_TIMEOUT=60
HEALTH_CHECK_INTERVAL=5
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# Error handler
error_exit() {
log_error "$1"
exit 1
}
# Check prerequisites
check_prerequisites() {
log_step "Checking prerequisites..."
# Check if running as correct user
if [ "$EUID" -eq 0 ]; then
error_exit "Do not run this script as root"
fi
# Check if Docker is installed
if ! command -v docker &> /dev/null; then
error_exit "Docker is not installed. Run ec2-setup.sh first."
fi
# Check if Docker Compose is installed
if ! command -v docker-compose &> /dev/null; then
error_exit "Docker Compose is not installed. Run ec2-setup.sh first."
fi
# Check if in correct directory
if [ ! -f "$APP_DIR/docker-compose.yml" ]; then
error_exit "docker-compose.yml not found in $APP_DIR"
fi
# Check if .env file exists
if [ ! -f "$APP_DIR/.env" ]; then
error_exit ".env file not found in $APP_DIR. Copy from .env.example and configure."
fi
log_info "Prerequisites check passed"
}
# Create backup
create_backup() {
log_step "Creating backup of current deployment..."
mkdir -p "$BACKUP_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DIR/backup_$TIMESTAMP"
# Backup current state
mkdir -p "$BACKUP_PATH"
# Backup environment file
if [ -f "$APP_DIR/.env" ]; then
cp "$APP_DIR/.env" "$BACKUP_PATH/.env"
fi
# Backup docker-compose file
if [ -f "$APP_DIR/docker-compose.yml" ]; then
cp "$APP_DIR/docker-compose.yml" "$BACKUP_PATH/docker-compose.yml"
fi
# Export current Docker images
if docker ps -a | grep -q kyc-mcp-server; then
docker save kyc-mcp-server:latest -o "$BACKUP_PATH/kyc-mcp-server.tar" 2>/dev/null || true
fi
# Backup Redis data
if docker ps | grep -q kyc-redis; then
docker exec kyc-redis redis-cli SAVE || true
docker cp kyc-redis:/data/dump.rdb "$BACKUP_PATH/redis-dump.rdb" 2>/dev/null || true
fi
log_info "Backup created at $BACKUP_PATH"
# Cleanup old backups
cleanup_old_backups
echo "$BACKUP_PATH"
}
# Cleanup old backups
cleanup_old_backups() {
log_info "Cleaning up old backups (keeping last $MAX_BACKUPS)..."
cd "$BACKUP_DIR"
ls -t | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm -rf
log_info "Old backups cleaned up"
}
# Pull latest code
pull_code() {
log_step "Pulling latest code from repository..."
cd "$APP_DIR"
# Check if git repository
if [ -d .git ]; then
# Stash any local changes
git stash
# Pull latest changes
git pull origin main || git pull origin master
log_info "Code updated successfully"
else
log_warn "Not a git repository. Skipping code pull."
fi
}
# Build Docker images
build_images() {
log_step "Building Docker images..."
cd "$APP_DIR"
# Build with no cache for clean build
docker-compose build --no-cache
log_info "Docker images built successfully"
}
# Stop current containers
stop_containers() {
log_step "Stopping current containers..."
cd "$APP_DIR"
if docker ps | grep -q kyc-mcp-server; then
docker-compose down
log_info "Containers stopped"
else
log_warn "No running containers found"
fi
}
# Start containers
start_containers() {
log_step "Starting containers..."
cd "$APP_DIR"
docker-compose up -d
log_info "Containers started"
}
# Wait for service to be ready
wait_for_service() {
log_step "Waiting for service to be ready..."
local elapsed=0
local container_name="kyc-mcp-server"
while [ $elapsed -lt $HEALTH_CHECK_TIMEOUT ]; do
# Check if container is running
if docker ps | grep -q "$container_name"; then
# Check container health
local health_status=$(docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null || echo "none")
if [ "$health_status" = "healthy" ]; then
log_info "Service is healthy"
return 0
elif [ "$health_status" = "none" ]; then
# No health check defined, check if container is running
if docker ps | grep -q "$container_name"; then
log_info "Container is running (no health check defined)"
sleep 5 # Give it a bit more time
return 0
fi
fi
fi
echo -n "."
sleep $HEALTH_CHECK_INTERVAL
elapsed=$((elapsed + HEALTH_CHECK_INTERVAL))
done
echo ""
log_error "Service failed to become healthy within ${HEALTH_CHECK_TIMEOUT}s"
return 1
}
# Perform health check
health_check() {
log_step "Performing health checks..."
local container_name="kyc-mcp-server"
# Check if container is running
if ! docker ps | grep -q "$container_name"; then
log_error "Container is not running"
return 1
fi
# Check container logs for errors
local logs=$(docker logs --tail 50 "$container_name" 2>&1)
if echo "$logs" | grep -qi "error\|exception\|failed"; then
log_warn "Errors found in container logs:"
echo "$logs" | grep -i "error\|exception\|failed" | tail -10
fi
# Check Redis connection
if docker ps | grep -q kyc-redis; then
if docker exec kyc-redis redis-cli ping | grep -q PONG; then
log_info "Redis is healthy"
else
log_error "Redis is not responding"
return 1
fi
fi
log_info "Health checks passed"
return 0
}
# Rollback to previous version
rollback() {
local backup_path=$1
log_error "Deployment failed. Rolling back to previous version..."
if [ -z "$backup_path" ] || [ ! -d "$backup_path" ]; then
log_error "No backup found for rollback"
return 1
fi
cd "$APP_DIR"
# Stop current containers
docker-compose down
# Restore environment file
if [ -f "$backup_path/.env" ]; then
cp "$backup_path/.env" "$APP_DIR/.env"
fi
# Restore Docker image
if [ -f "$backup_path/kyc-mcp-server.tar" ]; then
docker load -i "$backup_path/kyc-mcp-server.tar"
fi
# Restore Redis data
if [ -f "$backup_path/redis-dump.rdb" ]; then
docker-compose up -d redis
sleep 5
docker cp "$backup_path/redis-dump.rdb" kyc-redis:/data/dump.rdb
docker-compose restart redis
fi
# Start containers
docker-compose up -d
log_info "Rollback completed"
}
# Show deployment summary
show_summary() {
log_step "Deployment Summary"
echo "=========================================="
echo "Application: KYC MCP Server"
echo "Deployment Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
# Show running containers
echo ""
echo "Running Containers:"
docker ps --filter "name=kyc" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# Show resource usage
echo ""
echo "Resource Usage:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" \
$(docker ps --filter "name=kyc" -q)
echo ""
echo "=========================================="
log_info "Deployment completed successfully!"
echo "=========================================="
}
# Main deployment function
main() {
log_info "Starting deployment of KYC MCP Server..."
# Check prerequisites
check_prerequisites
# Create backup
BACKUP_PATH=$(create_backup)
# Pull latest code
pull_code
# Build images
build_images
# Stop current containers
stop_containers
# Start new containers
start_containers
# Wait for service to be ready
if ! wait_for_service; then
rollback "$BACKUP_PATH"
error_exit "Deployment failed and rolled back"
fi
# Perform health checks
if ! health_check; then
rollback "$BACKUP_PATH"
error_exit "Health checks failed and rolled back"
fi
# Show summary
show_summary
log_info "Deployment completed successfully!"
}
# Handle script arguments
case "${1:-deploy}" in
deploy)
main
;;
rollback)
if [ -z "${2:-}" ]; then
error_exit "Usage: $0 rollback <backup_path>"
fi
rollback "$2"
;;
health-check)
health_check
;;
*)
echo "Usage: $0 {deploy|rollback <backup_path>|health-check}"
exit 1
;;
esac
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/CTD-Techs/CTD-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server