Files
grist-mcp-server/docs/plans/2025-12-29-docker-deployment-design.md
Bill efe3ddf27b docs: add Docker deployment design
Design for containerizing grist-mcp with:
- Multi-stage Dockerfile with Python 3.14
- SSE transport for remote server operation
- Docker Compose for local deployment
- Single adaptive CI workflow for Gitea and GitHub
- Semantic version tagging
2025-12-29 19:35:54 -05:00

2.5 KiB

Docker Deployment Design

Overview

Make grist-mcp deployable via Docker Compose with CI workflows for automated image builds on version tag pushes.

Requirements

  • Docker Compose for local deployment
  • Single CI workflow that works on both Gitea and GitHub
  • SSE transport (replacing stdio) for remote server operation
  • Port 3000 default, configurable via environment variable
  • Python 3.14
  • Semantic version tagging (1.2.3, 1.2, 1, latest)
  • Config mounted at runtime (not baked into image)

Files to Create

Dockerfile

Multi-stage build:

Stage 1 (builder):

  • Base: python:3.14-slim
  • Install uv
  • Copy pyproject.toml and uv.lock
  • Install dependencies

Stage 2 (runtime):

  • Base: python:3.14-slim
  • Copy virtual environment from builder
  • Copy source code
  • Non-root user (appuser) for security
  • Expose port 3000
  • CMD: run server via uv

docker-compose.yaml

services:
  grist-mcp:
    build: .
    ports:
      - "${PORT:-3000}:3000"
    volumes:
      - ./config.yaml:/app/config.yaml:ro
    env_file:
      - .env
    restart: unless-stopped

.env.example

PORT=3000
GRIST_MCP_TOKEN=your-agent-token-here

.github/workflows/build.yaml

Single workflow that detects platform (Gitea vs GitHub) at runtime:

  • Trigger: Push of version tags (v*.*.*)
  • Platform detection: Check GITEA_ACTIONS environment variable
  • Registry:
    • Gitea: ${{ github.server_url }}/${{ github.repository }}
    • GitHub: ghcr.io/${{ github.repository }}
  • Authentication:
    • Gitea: ${{ secrets.REGISTRY_TOKEN }}
    • GitHub: ${{ secrets.GITHUB_TOKEN }}
  • Tags generated: 1.2.3, 1.2, 1, latest

Files to Modify

pyproject.toml

Add dependencies:

  • starlette - ASGI framework for SSE
  • uvicorn - ASGI server
  • sse-starlette - SSE support

src/grist_mcp/main.py

Replace stdio transport with SSE:

  1. Create Starlette ASGI app with routes:
    • GET /sse - SSE connection endpoint
    • POST /messages - Client message endpoint
  2. Run with uvicorn on configurable port (default 3000)
  3. Keep existing config/auth flow unchanged

.gitignore

Ensure .env is ignored.

Implementation Order

  1. Update dependencies and main.py for SSE transport
  2. Create Dockerfile
  3. Create docker-compose.yaml and .env.example
  4. Create CI workflow
  5. Test locally with docker compose up

Secrets to Configure

  • Gitea: Create REGISTRY_TOKEN secret with registry push access
  • GitHub: Uses automatic GITHUB_TOKEN