Skip to main content
Glama

Kotlin MCP Server

by normaltusker
validate_docker.py12.6 kB
#!/usr/bin/env python3 """ Docker Configuration Validator for Kotlin MCP Server Validates Docker setup files and provides recommendations """ import json import os import subprocess import sys from pathlib import Path from typing import Dict, List, Tuple class DockerValidator: """Validates Docker configuration and setup""" def __init__(self) -> None: self.project_root = Path(__file__).parent self.issues: List[str] = [] self.warnings: List[str] = [] self.recommendations: List[str] = [] def check_docker_files(self) -> bool: """Check if Docker configuration files exist and are valid""" print("🐳 Checking Docker configuration files...") # Check Dockerfile dockerfile_path = self.project_root / "Dockerfile" if not dockerfile_path.exists(): self.issues.append("Dockerfile not found") return False # Validate Dockerfile content dockerfile_content = dockerfile_path.read_text() required_elements = [ "FROM python:", "WORKDIR /app", "COPY requirements.txt", "RUN pip install", "COPY . .", "CMD", ] for element in required_elements: if element not in dockerfile_content: self.issues.append(f"Dockerfile missing: {element}") # Check for security best practices if "USER mcpuser" not in dockerfile_content: self.warnings.append("Dockerfile should use non-root user") if "HEALTHCHECK" not in dockerfile_content: self.recommendations.append("Add HEALTHCHECK to Dockerfile") print("✅ Dockerfile validation complete") return True def check_docker_compose(self) -> bool: """Check docker-compose.yml configuration""" print("🔧 Checking Docker Compose configuration...") compose_path = self.project_root / "docker-compose.yml" if not compose_path.exists(): self.issues.append("docker-compose.yml not found") return False try: import yaml # type: ignore with open(compose_path) as f: compose_config = yaml.safe_load(f) # Check required services if "services" not in compose_config: self.issues.append("No services defined in docker-compose.yml") return False services = compose_config["services"] # Check for main service main_service_exists = any("kotlin-mcp" in name for name in services.keys()) if not main_service_exists: self.issues.append("No kotlin-mcp service found in docker-compose.yml") # Check for volume mounts for service_name, service_config in services.items(): if "volumes" not in service_config: self.warnings.append(f"Service {service_name} has no volume mounts") print("✅ Docker Compose validation complete") return True except ImportError: self.warnings.append("PyYAML not installed - skipping detailed compose validation") return True except Exception as e: self.issues.append(f"Error parsing docker-compose.yml: {e}") return False def check_dockerignore(self) -> bool: """Check .dockerignore file""" print("📋 Checking .dockerignore...") dockerignore_path = self.project_root / ".dockerignore" if not dockerignore_path.exists(): self.recommendations.append("Create .dockerignore file to optimize builds") return True content = dockerignore_path.read_text() recommended_ignores = ["__pycache__/", ".git/", "*.log", ".venv/", ".pytest_cache/"] for ignore_pattern in recommended_ignores: if ignore_pattern not in content: self.recommendations.append(f"Add '{ignore_pattern}' to .dockerignore") print("✅ .dockerignore validation complete") return True def check_requirements_compatibility(self) -> bool: """Check if requirements.txt is compatible with Docker""" print("📦 Checking Python requirements compatibility...") req_path = self.project_root / "requirements.txt" if not req_path.exists(): self.issues.append("requirements.txt not found") return False content = req_path.read_text() # Check for potentially problematic packages problematic_packages = { "opencv-python": "Consider using opencv-python-headless for Docker", "tkinter": "GUI packages may not work in headless containers", "pyqt": "GUI packages may not work in headless containers", } for package, warning in problematic_packages.items(): if package in content.lower(): self.warnings.append(f"{package}: {warning}") # Check for version pinning lines = [ line.strip() for line in content.split("\n") if line.strip() and not line.startswith("#") ] unpinned = [ line for line in lines if ">=" not in line and "==" not in line and "~=" not in line ] if unpinned: self.recommendations.append(f"Consider pinning versions for: {', '.join(unpinned[:3])}") print("✅ Requirements compatibility check complete") return True def check_docker_installation(self) -> Tuple[bool, str]: """Check if Docker is installed and accessible""" print("🔍 Checking Docker installation...") try: result = subprocess.run( ["docker", "--version"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: version = result.stdout.strip() print(f"✅ Docker found: {version}") return True, version else: return False, "Docker command failed" except FileNotFoundError: return False, "Docker not installed" except subprocess.TimeoutExpired: return False, "Docker command timed out" except Exception as e: return False, f"Error checking Docker: {e}" def check_docker_compose_installation(self) -> Tuple[bool, str]: """Check if Docker Compose is available""" print("🔧 Checking Docker Compose installation...") # Try docker-compose command try: result = subprocess.run( ["docker-compose", "--version"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: version = result.stdout.strip() print(f"✅ Docker Compose found: {version}") return True, version except (FileNotFoundError, subprocess.TimeoutExpired): pass # Try docker compose command (newer versions) try: result = subprocess.run( ["docker", "compose", "version"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: version = result.stdout.strip() print(f"✅ Docker Compose (plugin) found: {version}") return True, version except (FileNotFoundError, subprocess.TimeoutExpired): pass return False, "Docker Compose not found" def validate_build_context(self) -> bool: """Validate Docker build context""" print("📁 Validating build context...") required_files = ["kotlin_mcp_server.py", "requirements.txt", "pyproject.toml"] for file_name in required_files: if not (self.project_root / file_name).exists(): self.issues.append(f"Required file missing: {file_name}") # Check for large files that should be ignored large_dirs = ["__pycache__", ".git", "htmlcov", ".pytest_cache"] for dir_name in large_dirs: if (self.project_root / dir_name).exists(): self.recommendations.append(f"Ensure {dir_name} is in .dockerignore") print("✅ Build context validation complete") return len(self.issues) == 0 def generate_setup_commands(self) -> List[str]: """Generate Docker setup commands based on platform""" commands = [] # Detect platform import platform system = platform.system().lower() if system == "darwin": # macOS commands.extend( [ "# macOS Docker Installation:", "brew install --cask docker", "# Or download from: https://docs.docker.com/desktop/mac/install/", "", ] ) elif system == "linux": commands.extend( [ "# Linux Docker Installation:", "sudo apt update", "sudo apt install docker.io docker-compose", "sudo systemctl start docker", "sudo systemctl enable docker", "sudo usermod -aG docker $USER", "# Log out and back in for group changes to take effect", "", ] ) elif system == "windows": commands.extend( [ "# Windows Docker Installation:", "# Download Docker Desktop from: https://docs.docker.com/desktop/windows/install/", "# Or use chocolatey: choco install docker-desktop", "", ] ) commands.extend( [ "# Build and run the Kotlin MCP Server:", "./docker-setup.sh build", "./docker-setup.sh start", "", "# Or manually:", "docker build -t kotlin-mcp-server .", "docker-compose up -d kotlin-mcp-server", ] ) return commands def run_validation(self) -> bool: """Run complete Docker validation""" print("🚀 Starting Docker validation for Kotlin MCP Server") print("=" * 60) success = True # Check Docker installation docker_installed, docker_msg = self.check_docker_installation() if not docker_installed: self.warnings.append(f"Docker: {docker_msg}") compose_installed, compose_msg = self.check_docker_compose_installation() if not compose_installed: self.warnings.append(f"Docker Compose: {compose_msg}") # Check configuration files success &= self.check_docker_files() success &= self.check_docker_compose() success &= self.check_dockerignore() success &= self.check_requirements_compatibility() success &= self.validate_build_context() # Print results print("\n" + "=" * 60) print("📊 VALIDATION RESULTS") print("=" * 60) if self.issues: print("❌ ISSUES FOUND:") for issue in self.issues: print(f" • {issue}") print() if self.warnings: print("⚠️ WARNINGS:") for warning in self.warnings: print(f" • {warning}") print() if self.recommendations: print("💡 RECOMMENDATIONS:") for rec in self.recommendations: print(f" • {rec}") print() if not docker_installed or not compose_installed: print("🛠️ SETUP COMMANDS:") for cmd in self.generate_setup_commands(): print(f" {cmd}") print() if success and not self.issues: print("🎉 Docker configuration is valid!") if docker_installed and compose_installed: print("✅ Ready to build and run with Docker!") else: print("📦 Install Docker to proceed with containerized deployment") else: print("🔧 Please fix the issues above before proceeding") return success and not self.issues def main() -> int: """Main validation function""" validator = DockerValidator() success = validator.run_validation() return 0 if success else 1 if __name__ == "__main__": sys.exit(main())

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/normaltusker/kotlin-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server