Reorganize Docker configuration into environment-specific directories:
- deploy/dev/: Development with hot reload and source mounting
- deploy/test/: Ephemeral testing with branch isolation and dynamic ports
- deploy/prod/: Production with resource limits, logging, and restart policy
Key improvements in test compose:
- Dynamic ports (no fixed 3000/8484) for parallel test runs
- Branch-isolated container/network names via TEST_INSTANCE_ID
- service_healthy condition instead of service_started
- Increased retry counts for stability
Move unit tests from tests/ to tests/unit/ for clearer separation
from integration tests. Update pyproject.toml testpaths and Makefile
test target to reflect the new structure.
- Replace Starlette routing with direct ASGI dispatcher to avoid
double-response issues with SSE transport
- Simplify integration test fixtures by removing async client fixture
- Consolidate integration tests into single test functions per file
to prevent SSE connection cleanup issues between tests
- Fix add_records assertion to expect 'inserted_ids' (actual API response)
- Update running instructions to show SSE endpoints
- Replace stdio-based MCP client config with URL-based SSE config
- Add examples for local and remote deployment
Add --chown=appuser:appuser to COPY commands in runtime stage to ensure
the appuser can read the copied files. Without this, Python fails with
PermissionError when importing modules.
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
- Server now authenticates from GRIST_MCP_TOKEN env var or token parameter
- Removed unused code (_set_agent, nonlocal check)
- Added AuthError handling in main.py
- Updated test to pass token explicitly