Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Version control
.git
.github

# Python caches
__pycache__
*.pyc
*.pyo
.pytest_cache
.ruff_cache

# Virtual environments
.venv
venv
env

# IDE / editor
.vscode
.idea
*.swp
*.swo

# Build artifacts
dist/
*.egg-info
build/

# Documentation
docs/_build/
docs/build/

# Project-specific ignores
mcp_server.log
.ignore/
TODO.md
.pre-commit-config.yaml
.readthedocs.yaml

# Docker (prevent recursive context)
Dockerfile
docker-compose.yml
.dockerignore
65 changes: 65 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# =============================================================================
# Dockerfile for sktime-mcp
#
# Multi-stage build:
# 1. Builder – installs build tools and Python dependencies
# 2. Runtime – slim image with only the installed packages
#
# Usage:
# docker build -t sktime-mcp .
# docker run -i sktime-mcp # stdio transport (default)
# docker run -i -e SKTIME_MCP_LOG_LEVEL=DEBUG sktime-mcp
# =============================================================================

# ---------------------------------------------------------------------------
# Stage 1: Builder
# ---------------------------------------------------------------------------
FROM python:3.12-slim AS builder

# Avoid interactive prompts during package install
ENV DEBIAN_FRONTEND=noninteractive

# Install minimal build dependencies required by some scientific packages
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
gfortran \
libopenblas-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /build

# Copy only dependency-related files first to maximise Docker layer caching
COPY pyproject.toml README.md LICENSE ./
COPY src/ src/

# Install the project in production mode (no dev/test extras)
RUN pip install --no-cache-dir --prefix=/install .

# ---------------------------------------------------------------------------
# Stage 2: Runtime
# ---------------------------------------------------------------------------
FROM python:3.12-slim AS runtime

# Runtime library needed by numpy/scipy linked against OpenBLAS
RUN apt-get update && apt-get install -y --no-install-recommends \
libopenblas0 \
&& rm -rf /var/lib/apt/lists/*

# Copy installed Python packages from the builder stage
COPY --from=builder /install /usr/local

# Create a non-root user for security
RUN useradd --create-home --shell /bin/bash mcp
USER mcp
WORKDIR /home/mcp

# Environment defaults (overridable at runtime)
ENV SKTIME_MCP_LOG_LEVEL=WARNING
ENV PYTHONUNBUFFERED=1

# Health-check: verify the package is importable
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import sktime_mcp; print('ok')" || exit 1

# MCP servers communicate over stdio, so the entrypoint is the CLI command
ENTRYPOINT ["sktime-mcp"]
20 changes: 14 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
.PHONY: check test lint format help format-fix install-hooks
.PHONY: check test lint format help format-fix install-hooks docker-build docker-run

help:
@echo "Available commands:"
@echo " make check - Run all CI checks (format check, lint, test)"
@echo " make lint - Run ruff linter"
@echo " make format - Run ruff format checker (check only)"
@echo " make test - Run pytest"
@echo " make format-fix - Auto-fix formatting and fixable lint issues"
@echo " make check - Run all CI checks (format check, lint, test)"
@echo " make lint - Run ruff linter"
@echo " make format - Run ruff format checker (check only)"
@echo " make test - Run pytest"
@echo " make format-fix - Auto-fix formatting and fixable lint issues"
@echo " make docker-build - Build the Docker image"
@echo " make docker-run - Run the MCP server in Docker (stdio)"

check: format lint test

Expand All @@ -26,3 +28,9 @@ format-fix:
install-hooks:
pip install pre-commit
pre-commit install

docker-build:
docker build -t sktime-mcp .

docker-run: docker-build
docker run -i --rm sktime-mcp
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,44 @@ For development (editable install from source):
pip install -e ".[dev]"
```

### 🐳 Docker

Run without installing anything locally (only Docker required):

```bash
# Build the image
docker build -t sktime-mcp .

# Run the MCP server (stdio transport)
docker run -i sktime-mcp
```

Or use Docker Compose:

```bash
docker compose build
docker compose run sktime-mcp
```

**Claude Desktop** β€” use Docker as the MCP server command:

```json
{
"mcpServers": {
"sktime": {
"command": "docker",
"args": ["run", "-i", "--rm", "sktime-mcp"]
}
}
}
```

Environment variables can be passed at runtime:

```bash
docker run -i -e SKTIME_MCP_LOG_LEVEL=DEBUG sktime-mcp
```

For a more detailed first-time setup flow, including MCP server verification and troubleshooting, see [Beginner Setup](#-beginner-setup-firsttime-users).

## 🧭 Beginner Setup (First‑Time Users)
Expand Down Expand Up @@ -527,7 +565,10 @@ sktime-mcp/
β”‚ └── tools/ # MCP tool implementations
β”œβ”€β”€ docs/ # Sphinx documentation source
β”œβ”€β”€ examples/ # Usage examples
└── tests/ # Test suite
β”œβ”€β”€ tests/ # Test suite
β”œβ”€β”€ Dockerfile # Multi-stage container build
β”œβ”€β”€ docker-compose.yml # Compose service definition
└── .dockerignore # Docker build context filter
```

## πŸ§ͺ Running Tests
Expand Down
38 changes: 38 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# =============================================================================
# Docker Compose for sktime-mcp
#
# Usage:
# docker compose build # build the image
# docker compose run sktime-mcp # run with stdio (interactive, for MCP clients)
#
# Notes:
# - MCP uses stdio transport, so `docker compose run` (with TTY) is the
# correct invocation rather than `docker compose up` (which is for daemons).
# - The models volume persists saved models across container restarts.
# =============================================================================

services:
sktime-mcp:
build:
context: .
dockerfile: Dockerfile
image: sktime-mcp:latest
container_name: sktime-mcp

# stdin_open + tty are required for stdio-based MCP transport
stdin_open: true
tty: false # MCP JSON-RPC needs raw stdin, not a pseudo-TTY

environment:
- SKTIME_MCP_LOG_LEVEL=${SKTIME_MCP_LOG_LEVEL:-WARNING}
- SKTIME_MCP_AUTO_FORMAT=${SKTIME_MCP_AUTO_FORMAT:-true}
- SKTIME_MCP_JOB_MAX_AGE_HOURS=${SKTIME_MCP_JOB_MAX_AGE_HOURS:-24}
- SKTIME_MCP_JOB_CLEANUP_INTERVAL=${SKTIME_MCP_JOB_CLEANUP_INTERVAL:-3600}

volumes:
# Persist saved models outside the container
- sktime-models:/home/mcp/models

volumes:
sktime-models:
driver: local