diff --git a/.dockerignore b/.dockerignore index 0eff9ad..785a55b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -43,6 +43,7 @@ README.md # Tests tests/ simulator_tests/ +test_simulation_files/ pytest.ini # Development @@ -52,9 +53,3 @@ examples/ scripts/bump_version.py code_quality_checks.sh run_integration_tests.sh - -# Context files (our planning documents) -contexte/ - -# PR files -pr/ diff --git a/docker/README.md b/docker/README.md index 5889715..da26b5f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -24,9 +24,13 @@ nano .env # Build the Docker image docker build -t zen-mcp-server:latest . -# Or use the build script +# Or use the build script (Bash) chmod +x docker/scripts/build.sh ./docker/scripts/build.sh + +# Build with PowerShell +docker/scripts/build.ps1 + ``` ### 4. Usage Options @@ -54,6 +58,9 @@ docker run --rm -i \ chmod +x docker/scripts/deploy.sh ./docker/scripts/deploy.sh +# Or use PowerShell script +docker/scripts/deploy.ps1 + # Interactive stdio mode docker-compose exec zen-mcp python server.py ``` diff --git a/docker/scripts/build.ps1 b/docker/scripts/build.ps1 new file mode 100644 index 0000000..d7896e1 --- /dev/null +++ b/docker/scripts/build.ps1 @@ -0,0 +1,70 @@ +#!/usr/bin/env pwsh +#Requires -Version 5.1 +[CmdletBinding()] +param() + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Colors for output (using Write-Host with colors) +function Write-ColorText { + param( + [Parameter(Mandatory)] + [string]$Text, + [string]$Color = "White", + [switch]$NoNewline + ) + if ($NoNewline) { + Write-Host $Text -ForegroundColor $Color -NoNewline + } else { + Write-Host $Text -ForegroundColor $Color + } +} + +Write-ColorText "=== Building Zen MCP Server Docker Image ===" -Color Green + +# Check if .env file exists +if (!(Test-Path ".env")) { + Write-ColorText "Warning: .env file not found. Copying from .env.example" -Color Yellow + if (Test-Path ".env.example") { + Copy-Item ".env.example" ".env" + Write-ColorText "Please edit .env file with your API keys before running the server" -Color Yellow + } else { + Write-ColorText "Error: .env.example not found" -Color Red + exit 1 + } +} + +# Build the Docker image +Write-ColorText "Building Docker image..." -Color Green +try { + docker-compose build --no-cache + if ($LASTEXITCODE -ne 0) { + throw "Docker build failed" + } +} catch { + Write-ColorText "Error: Failed to build Docker image" -Color Red + exit 1 +} + +# Verify the build +Write-ColorText "Verifying build..." -Color Green +$images = docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" | Select-String "zen-mcp-server" + +if ($images) { + Write-ColorText "✓ Docker image built successfully" -Color Green + Write-ColorText "Image details:" -Color Green + $images | ForEach-Object { Write-Host $_.Line } +} else { + Write-ColorText "✗ Failed to build Docker image" -Color Red + exit 1 +} + +Write-ColorText "=== Build Complete ===" -Color Green +Write-ColorText "Next steps:" -Color Yellow +Write-Host " 1. Edit .env file with your API keys" +Write-ColorText " 2. Run: " -Color White -NoNewline +Write-ColorText "docker-compose up -d" -Color Green + +Write-ColorText "Or use the deploy script: " -Color White -NoNewline +Write-ColorText ".\deploy.ps1" -Color Green diff --git a/docker/scripts/deploy.ps1 b/docker/scripts/deploy.ps1 new file mode 100644 index 0000000..97ed1d2 --- /dev/null +++ b/docker/scripts/deploy.ps1 @@ -0,0 +1,208 @@ +#!/usr/bin/env pwsh +#Requires -Version 5.1 +[CmdletBinding()] +param( + [switch]$SkipHealthCheck, + [int]$HealthCheckTimeout = 60 +) + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Colors for output +function Write-ColorText { + param( + [Parameter(Mandatory)] + [string]$Text, + [string]$Color = "White", + [switch]$NoNewline + ) + if ($NoNewline) { + Write-Host $Text -ForegroundColor $Color -NoNewline + } else { + Write-Host $Text -ForegroundColor $Color + } +} + +Write-ColorText "=== Deploying Zen MCP Server ===" -Color Green + +# Function to check if required environment variables are set +function Test-EnvironmentVariables { + # At least one of these API keys must be set + $requiredVars = @( + "GEMINI_API_KEY", + "GOOGLE_API_KEY", + "OPENAI_API_KEY", + "XAI_API_KEY", + "DIAL_API_KEY", + "OPENROUTER_API_KEY" + ) + + $hasApiKey = $false + foreach ($var in $requiredVars) { + $value = [Environment]::GetEnvironmentVariable($var) + if (![string]::IsNullOrWhiteSpace($value)) { + $hasApiKey = $true + break + } + } + + if (!$hasApiKey) { + Write-ColorText "Error: At least one API key must be set in your .env file" -Color Red + Write-ColorText "Required variables (at least one):" -Color Yellow + $requiredVars | ForEach-Object { Write-Host " $_" } + exit 1 + } +} + +# Load environment variables from .env file +if (Test-Path ".env") { + Write-ColorText "Loading environment variables from .env..." -Color Green + + # Read .env file and set environment variables + Get-Content ".env" | ForEach-Object { + if ($_ -match '^([^#][^=]*?)=(.*)$') { + $name = $matches[1].Trim() + $value = $matches[2].Trim() + # Remove quotes if present + $value = $value -replace '^["'']|["'']$', '' + [Environment]::SetEnvironmentVariable($name, $value, "Process") + } + } + Write-ColorText "✓ Environment variables loaded from .env" -Color Green +} else { + Write-ColorText "Error: .env file not found" -Color Red + Write-ColorText "Please copy .env.example to .env and configure your API keys" -Color Yellow + exit 1 +} + +# Check required environment variables +Test-EnvironmentVariables + +# Function to wait for service health with exponential backoff +function Wait-ForHealth { + param( + [int]$MaxAttempts = 6, + [int]$InitialDelay = 2 + ) + + $attempt = 1 + $delay = $InitialDelay + + while ($attempt -le $MaxAttempts) { + try { + # Get container ID for zen-mcp service + $containerId = docker-compose ps -q zen-mcp + if ([string]::IsNullOrWhiteSpace($containerId)) { + $status = "unavailable" + } else { + $status = docker inspect -f "{{.State.Health.Status}}" $containerId 2>$null + if ($LASTEXITCODE -ne 0) { + $status = "unavailable" + } + } + + if ($status -eq "healthy") { + return $true + } + + Write-ColorText "Waiting for service to be healthy... (attempt $attempt/$MaxAttempts, retrying in ${delay}s)" -Color Yellow + Start-Sleep -Seconds $delay + $delay = $delay * 2 + $attempt++ + } catch { + Write-ColorText "Error checking health status: $_" -Color Red + $attempt++ + Start-Sleep -Seconds $delay + } + } + + Write-ColorText "Service failed to become healthy after $MaxAttempts attempts" -Color Red + Write-ColorText "Checking logs:" -Color Yellow + docker-compose logs zen-mcp + return $false +} + +# Create logs directory if it doesn't exist +if (!(Test-Path "logs")) { + Write-ColorText "Creating logs directory..." -Color Green + New-Item -ItemType Directory -Path "logs" -Force | Out-Null +} + +# Stop existing containers +Write-ColorText "Stopping existing containers..." -Color Green +try { + docker-compose down + if ($LASTEXITCODE -ne 0) { + Write-ColorText "Warning: Failed to stop existing containers (they may not be running)" -Color Yellow + } +} catch { + Write-ColorText "Warning: Error stopping containers: $_" -Color Yellow +} + +# Start the services +Write-ColorText "Starting Zen MCP Server..." -Color Green +try { + docker-compose up -d + if ($LASTEXITCODE -ne 0) { + throw "Failed to start services" + } +} catch { + Write-ColorText "Error: Failed to start services" -Color Red + Write-ColorText "Checking logs:" -Color Yellow + docker-compose logs zen-mcp + exit 1 +} + +# Wait for health check (unless skipped) +if (!$SkipHealthCheck) { + Write-ColorText "Waiting for service to be healthy..." -Color Green + + # Simple timeout approach for health check + $timeout = $HealthCheckTimeout + $elapsed = 0 + $healthy = $false + + while ($elapsed -lt $timeout) { + try { + $containerId = docker-compose ps -q zen-mcp + if (![string]::IsNullOrWhiteSpace($containerId)) { + $status = docker inspect -f "{{.State.Health.Status}}" $containerId 2>$null + if ($status -eq "healthy") { + $healthy = $true + break + } + } + } catch { + # Continue checking + } + + Start-Sleep -Seconds 2 + $elapsed += 2 + } + + if (!$healthy) { + Write-ColorText "Service failed to become healthy within timeout" -Color Red + Write-ColorText "Checking logs:" -Color Yellow + docker-compose logs zen-mcp + exit 1 + } +} + +Write-ColorText "✓ Zen MCP Server deployed successfully" -Color Green +Write-ColorText "Service Status:" -Color Green +docker-compose ps + +Write-ColorText "=== Deployment Complete ===" -Color Green +Write-ColorText "Useful commands:" -Color Yellow +Write-ColorText " View logs: " -Color White -NoNewline +Write-ColorText "docker-compose logs -f zen-mcp" -Color Green + +Write-ColorText " Stop service: " -Color White -NoNewline +Write-ColorText "docker-compose down" -Color Green + +Write-ColorText " Restart service: " -Color White -NoNewline +Write-ColorText "docker-compose restart zen-mcp" -Color Green + +Write-ColorText " PowerShell logs: " -Color White -NoNewline +Write-ColorText "Get-Content logs\mcp_server.log -Wait" -Color Green diff --git a/docker/scripts/deploy.sh b/docker/scripts/deploy.sh index 572c83a..fba78a6 100644 --- a/docker/scripts/deploy.sh +++ b/docker/scripts/deploy.sh @@ -27,20 +27,6 @@ check_env_vars() { printf ' %s\n' "${required_vars[@]}" exit 1 fi - local missing_vars=() - - for var in "${required_vars[@]}"; do - if [[ -z "${!var:-}" ]]; then - missing_vars+=("$var") - fi - done - - if [[ ${#missing_vars[@]} -gt 0 ]]; then - echo -e "${RED}Error: Missing required environment variables:${NC}" - printf ' %s\n' "${missing_vars[@]}" - echo -e "${YELLOW}Please set these variables in your .env file${NC}" - exit 1 - fi } # Load environment variables