setup.py•10.8 kB
#!/usr/bin/env python3
"""
AnyDocs MCP Server - Setup and Initialization Script
This script handles the initial setup and configuration of the AnyDocs MCP server,
including dependency installation, database initialization, and configuration validation.
Usage:
python scripts/setup.py [options]
Options:
--dev Setup development environment
--prod Setup production environment
--force Force reinstall dependencies
--no-db Skip database initialization
--config PATH Custom configuration file path
--help Show this help message
"""
import argparse
import os
import sys
import subprocess
import shutil
from pathlib import Path
from typing import List, Optional
# Add src to Python path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
try:
import yaml
except ImportError:
yaml = None
class SetupManager:
"""Manages the setup and initialization process."""
def __init__(self, project_root: Path):
self.project_root = project_root
self.src_dir = project_root / "src"
self.config_dir = project_root
self.data_dir = project_root / "data"
self.logs_dir = project_root / "logs"
def check_python_version(self) -> bool:
"""Check if Python version is compatible."""
min_version = (3, 8)
current_version = sys.version_info[:2]
if current_version < min_version:
print(f"❌ Python {min_version[0]}.{min_version[1]}+ is required. Current: {current_version[0]}.{current_version[1]}")
return False
print(f"✅ Python version: {current_version[0]}.{current_version[1]}")
return True
def create_directories(self) -> None:
"""Create necessary directories."""
directories = [
self.data_dir,
self.logs_dir,
self.data_dir / "cache",
self.data_dir / "uploads",
self.data_dir / "backups",
self.logs_dir / "archive"
]
for directory in directories:
directory.mkdir(parents=True, exist_ok=True)
print(f"📁 Created directory: {directory}")
def install_dependencies(self, dev: bool = False, force: bool = False) -> bool:
"""Install Python dependencies."""
requirements_file = "requirements-dev.txt" if dev else "requirements.txt"
requirements_path = self.project_root / requirements_file
if not requirements_path.exists():
print(f"❌ Requirements file not found: {requirements_path}")
return False
cmd = [sys.executable, "-m", "pip", "install"]
if force:
cmd.append("--force-reinstall")
cmd.extend(["-r", str(requirements_path)])
print(f"📦 Installing dependencies from {requirements_file}...")
try:
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("✅ Dependencies installed successfully")
return True
except subprocess.CalledProcessError as e:
print(f"❌ Failed to install dependencies: {e}")
print(f"Error output: {e.stderr}")
return False
def copy_config_files(self) -> None:
"""Copy configuration template files."""
config_files = [
(".env.example", ".env"),
("config.yaml", "config.yaml")
]
for src_name, dst_name in config_files:
src_path = self.project_root / src_name
dst_path = self.project_root / dst_name
if src_path.exists() and not dst_path.exists():
shutil.copy2(src_path, dst_path)
print(f"📋 Copied {src_name} to {dst_name}")
elif dst_path.exists():
print(f"⚠️ {dst_name} already exists, skipping")
else:
print(f"❌ Template file not found: {src_name}")
def validate_config(self, config_path: Optional[Path] = None) -> bool:
"""Validate configuration files."""
if config_path is None:
config_path = self.project_root / "config.yaml"
if not config_path.exists():
print(f"⚠️ Configuration file not found: {config_path}")
return False
if yaml is None:
print("⚠️ PyYAML not installed, skipping config validation")
return True
try:
with open(config_path, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
# Basic validation
required_sections = ['app', 'server', 'database']
for section in required_sections:
if section not in config:
print(f"❌ Missing required config section: {section}")
return False
print("✅ Configuration file is valid")
return True
except yaml.YAMLError as e:
print(f"❌ Invalid YAML configuration: {e}")
return False
except Exception as e:
print(f"❌ Error validating configuration: {e}")
return False
def initialize_database(self) -> bool:
"""Initialize the database."""
try:
# Import after dependencies are installed
from anydocs_mcp.database.manager import DatabaseManager
from anydocs_mcp.config.settings import Settings
print("🗄️ Initializing database...")
# Load settings
settings = Settings()
# Initialize database manager
db_manager = DatabaseManager(
database_url=settings.database.url,
echo=settings.database.echo
)
db_manager.initialize_database()
print("✅ Database initialized successfully")
return True
except ImportError as e:
print(f"❌ Failed to import database modules: {e}")
print("💡 Make sure dependencies are installed first")
return False
except Exception as e:
print(f"❌ Failed to initialize database: {e}")
return False
def setup_git_hooks(self) -> None:
"""Setup git pre-commit hooks (if in development mode)."""
git_dir = self.project_root / ".git"
if not git_dir.exists():
print("⚠️ Not a git repository, skipping git hooks setup")
return
try:
subprocess.run(["pre-commit", "install"],
cwd=self.project_root,
check=True,
capture_output=True)
print("✅ Git pre-commit hooks installed")
except (subprocess.CalledProcessError, FileNotFoundError):
print("⚠️ Failed to install pre-commit hooks (pre-commit not installed?)")
def run_health_check(self) -> bool:
"""Run a basic health check."""
try:
# Try to import the main module
from anydocs_mcp.server import AnyDocsMCPServer
print("✅ Main modules can be imported")
return True
except ImportError as e:
print(f"❌ Failed to import main modules: {e}")
return False
def print_next_steps(self, dev: bool = False) -> None:
"""Print next steps for the user."""
print("\n" + "="*60)
print("🎉 Setup completed successfully!")
print("="*60)
print("\n📋 Next steps:")
print("\n1. Edit configuration files:")
print(" - .env (environment variables)")
print(" - config.yaml (application settings)")
print("\n2. Add your API keys and credentials to .env")
print("\n3. Start the server:")
if dev:
print(" python start.py --mode hybrid --debug")
else:
print(" python start.py")
print("\n4. Access the web interface:")
print(" http://localhost:8000")
print("\n5. Check the documentation:")
print(" README.md")
print("\n" + "="*60)
def main():
"""Main setup function."""
parser = argparse.ArgumentParser(
description="AnyDocs MCP Server Setup Script",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python scripts/setup.py --dev # Development setup
python scripts/setup.py --prod # Production setup
python scripts/setup.py --force # Force reinstall
python scripts/setup.py --no-db # Skip database init
"""
)
parser.add_argument("--dev", action="store_true",
help="Setup development environment")
parser.add_argument("--prod", action="store_true",
help="Setup production environment")
parser.add_argument("--force", action="store_true",
help="Force reinstall dependencies")
parser.add_argument("--no-db", action="store_true",
help="Skip database initialization")
parser.add_argument("--config", type=Path,
help="Custom configuration file path")
args = parser.parse_args()
# Determine project root
project_root = Path(__file__).parent.parent
setup_manager = SetupManager(project_root)
print("🚀 AnyDocs MCP Server Setup")
print(f"📁 Project root: {project_root}")
print("="*60)
# Check Python version
if not setup_manager.check_python_version():
sys.exit(1)
# Create directories
setup_manager.create_directories()
# Install dependencies
dev_mode = args.dev or (not args.prod)
if not setup_manager.install_dependencies(dev=dev_mode, force=args.force):
print("❌ Setup failed during dependency installation")
sys.exit(1)
# Copy configuration files
setup_manager.copy_config_files()
# Validate configuration
if not setup_manager.validate_config(args.config):
print("⚠️ Configuration validation failed, but continuing...")
# Initialize database
if not args.no_db:
if not setup_manager.initialize_database():
print("⚠️ Database initialization failed, but continuing...")
# Setup git hooks (dev only)
if dev_mode:
setup_manager.setup_git_hooks()
# Run health check
if not setup_manager.run_health_check():
print("⚠️ Health check failed, but setup completed")
# Print next steps
setup_manager.print_next_steps(dev=dev_mode)
if __name__ == "__main__":
main()