# SimpleMCP V2
# Built locally by the CLI on first run — do not run this image directly.
# The CLI manages all container lifecycle (start, stop, port mapping, volumes).

# Pull uv binary from the official image
FROM ghcr.io/astral-sh/uv:latest AS uv

FROM python:3.11-slim

# Build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    curl \
    socat \
    && rm -rf /var/lib/apt/lists/*

# Copy uv binary directly from the official image — no install script needed.
# Licensed MIT OR Apache 2.0; bundling is permitted.
COPY --from=uv /uv /usr/local/bin/uv

WORKDIR /app

# Copy and install core Python dependencies.
COPY requirements.txt .
RUN uv pip install --system --no-cache -r requirements.txt

# Install Playwright and its browsers + OS dependencies.
# Done at image build time so kits using Playwright don't incur a download
# penalty on first run. Chromium only — Firefox/WebKit not needed.
RUN uv pip install --system --no-cache playwright \
    && python -m playwright install --with-deps chromium

# Copy core engine files only.
# Demo artifacts (example.db, client.py, sample kits) are excluded via .dockerignore.
COPY utils/ ./utils/
COPY server.py .
COPY config.py .

# Bake in the kits __init__.py (auto-discovery logic).
# NOTE: The CLI volume-mounts the host kits directory over /app/kits at runtime,
# which hides this file. The CLI is responsible for ensuring __init__.py is always
# present in the host kits directory (it writes one on `simplemcp install` if absent).
COPY kits/__init__.py ./kits/__init__.py

# Bootstrap script — runs on every container start before the main process.
# Parses each kit's `requirements = [...]` metadata using ast and installs
# any missing packages via uv pip.
COPY bootstrap.py .

# ── Ports ────────────────────────────────────────────────────────────────────
# Port 8000 is the default for SimpleMCP protocol mode and stdio mode.
# In MCP mode the CLI assigns each kit a unique host port and maps them
# explicitly with -p flags at `docker run` time; kit processes use ports
# starting from 8001 upward inside the container.
EXPOSE 8000

# ── Kit dependency cache ──────────────────────────────────────────────────────
# Kit deps are installed into /app/lib by bootstrap.py and persisted via a
# host bind-mount (~/.simplemcp/packages/). We use sitecustomize.py to append
# /app/lib AFTER system site-packages so kit-installed packages (e.g. pydantic
# pulled in by crawl4ai) never shadow the system packages that FastAPI depends on.
# Using PYTHONPATH="/app/lib" would prepend it and cause import conflicts on Linux.
RUN python -c "f=open('/usr/local/lib/python3.11/site-packages/sitecustomize.py','w'); f.write('import sys\nif \"/app/lib\" not in sys.path:\n    sys.path.append(\"/app/lib\")\n'); f.close()"
# Silence the urllib3/chardet version mismatch warning emitted by crawl4ai's
# bundled requests copy — it's harmless but noisy in container logs.
ENV PYTHONWARNINGS="ignore::Warning:requests"
VOLUME /app/lib

# ── Health check ─────────────────────────────────────────────────────────────
# Allows the CLI to wait for the container to be ready before returning.
# Only meaningful in SimpleMCP/MCP HTTP modes; stdio mode ignores it.
HEALTHCHECK --interval=5s --timeout=5s --start-period=120s --retries=10 \
    CMD curl -f http://localhost:8000/list_kits || exit 1

# ── Entrypoint ───────────────────────────────────────────────────────────────
# bootstrap.py runs first on every start, installs any kit requirements,
# then execs the real server process so it becomes PID 1.
#
# The CLI overrides the tail command at runtime depending on mode:
#
#   SimpleMCP mode (default):
#     docker run ... simplemcp-image
#
#   MCP mode (one process per kit, spawned inside the container by the CLI):
#     docker exec ... env MCP_MODE=true uvicorn server:app --host 0.0.0.0 --port <kit_port>
#
#   stdio mode (launched directly by the stdio client as its command):
#     docker run -i ... simplemcp-image python bootstrap.py python server.py
#
ENTRYPOINT ["python", "bootstrap.py"]
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000"]
