import os import subprocess # Path to the MCP docker-compose projects, relative to the main app file. MCP_TOOLS_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'tools') MCP_COMPOSE_DIR = os.path.join(MCP_TOOLS_DIR, 'danbooru-mcp') MCP_REPO_URL = 'https://git.liveaodh.com/aodhan/danbooru-mcp' CHAR_MCP_COMPOSE_DIR = os.path.join(MCP_TOOLS_DIR, 'character-mcp') CHAR_MCP_REPO_URL = 'https://git.liveaodh.com/aodhan/character-mcp.git' def _ensure_mcp_repo(): """Clone or update the danbooru-mcp source repository inside tools/. - If ``tools/danbooru-mcp/`` does not exist, clone from MCP_REPO_URL. - If it already exists, run ``git pull`` to fetch the latest changes. Errors are non-fatal. """ os.makedirs(MCP_TOOLS_DIR, exist_ok=True) try: if not os.path.isdir(MCP_COMPOSE_DIR): print(f'Cloning danbooru-mcp from {MCP_REPO_URL} …') subprocess.run( ['git', 'clone', MCP_REPO_URL, MCP_COMPOSE_DIR], timeout=120, check=True, ) print('danbooru-mcp cloned successfully.') else: print('Updating danbooru-mcp via git pull …') subprocess.run( ['git', 'pull'], cwd=MCP_COMPOSE_DIR, timeout=60, check=True, ) print('danbooru-mcp updated.') except FileNotFoundError: print('WARNING: git not found on PATH — danbooru-mcp repo will not be cloned/updated.') except subprocess.CalledProcessError as e: print(f'WARNING: git operation failed for danbooru-mcp: {e}') except subprocess.TimeoutExpired: print('WARNING: git timed out while cloning/updating danbooru-mcp.') except Exception as e: print(f'WARNING: Could not clone/update danbooru-mcp repo: {e}') def ensure_mcp_server_running(): """Ensure the danbooru-mcp repo is present/up-to-date, then start the Docker container if it is not already running. Uses ``docker compose up -d`` so the image is built automatically on first run. Errors are non-fatal — the app will still start even if Docker is unavailable. Skipped when ``SKIP_MCP_AUTOSTART=true`` (set by docker-compose, where the danbooru-mcp service is managed by compose instead). """ if os.environ.get('SKIP_MCP_AUTOSTART', '').lower() == 'true': print('SKIP_MCP_AUTOSTART set — skipping danbooru-mcp auto-start.') return _ensure_mcp_repo() try: result = subprocess.run( ['docker', 'ps', '--filter', 'name=danbooru-mcp', '--format', '{{.Names}}'], capture_output=True, text=True, timeout=10, ) if 'danbooru-mcp' in result.stdout: print('danbooru-mcp container already running.') return # Container not running — start it via docker compose print('Starting danbooru-mcp container via docker compose …') subprocess.run( ['docker', 'compose', 'up', '-d'], cwd=MCP_COMPOSE_DIR, timeout=120, ) print('danbooru-mcp container started.') except FileNotFoundError: print('WARNING: docker not found on PATH — danbooru-mcp will not be started automatically.') except subprocess.TimeoutExpired: print('WARNING: docker timed out while starting danbooru-mcp.') except Exception as e: print(f'WARNING: Could not ensure danbooru-mcp is running: {e}') def _ensure_character_mcp_repo(): """Clone or update the character-mcp source repository inside tools/. - If ``tools/character-mcp/`` does not exist, clone from CHAR_MCP_REPO_URL. - If it already exists, run ``git pull`` to fetch the latest changes. Errors are non-fatal. """ os.makedirs(MCP_TOOLS_DIR, exist_ok=True) try: if not os.path.isdir(CHAR_MCP_COMPOSE_DIR): print(f'Cloning character-mcp from {CHAR_MCP_REPO_URL} …') subprocess.run( ['git', 'clone', CHAR_MCP_REPO_URL, CHAR_MCP_COMPOSE_DIR], timeout=120, check=True, ) print('character-mcp cloned successfully.') else: print('Updating character-mcp via git pull …') subprocess.run( ['git', 'pull'], cwd=CHAR_MCP_COMPOSE_DIR, timeout=60, check=True, ) print('character-mcp updated.') except FileNotFoundError: print('WARNING: git not found on PATH — character-mcp repo will not be cloned/updated.') except subprocess.CalledProcessError as e: print(f'WARNING: git operation failed for character-mcp: {e}') except subprocess.TimeoutExpired: print('WARNING: git timed out while cloning/updating character-mcp.') except Exception as e: print(f'WARNING: Could not clone/update character-mcp repo: {e}') def ensure_character_mcp_server_running(): """Ensure the character-mcp repo is present/up-to-date, then start the Docker container if it is not already running. Uses ``docker compose up -d`` so the image is built automatically on first run. Errors are non-fatal — the app will still start even if Docker is unavailable. Skipped when ``SKIP_MCP_AUTOSTART=true`` (set by docker-compose, where the character-mcp service is managed by compose instead). """ if os.environ.get('SKIP_MCP_AUTOSTART', '').lower() == 'true': print('SKIP_MCP_AUTOSTART set — skipping character-mcp auto-start.') return _ensure_character_mcp_repo() try: result = subprocess.run( ['docker', 'ps', '--filter', 'name=character-mcp', '--format', '{{.Names}}'], capture_output=True, text=True, timeout=10, ) if 'character-mcp' in result.stdout: print('character-mcp container already running.') return # Container not running — start it via docker compose print('Starting character-mcp container via docker compose …') subprocess.run( ['docker', 'compose', 'up', '-d'], cwd=CHAR_MCP_COMPOSE_DIR, timeout=120, ) print('character-mcp container started.') except FileNotFoundError: print('WARNING: docker not found on PATH — character-mcp will not be started automatically.') except subprocess.TimeoutExpired: print('WARNING: docker timed out while starting character-mcp.') except Exception as e: print(f'WARNING: Could not ensure character-mcp is running: {e}')