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
This commit is contained in:
2025-12-29 19:35:54 -05:00
parent ed612694fe
commit efe3ddf27b

View File

@@ -0,0 +1,107 @@
# 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
```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`