Skip to content

Docker Deployment Guide - SOLVE-IT MCP Server

This guide covers running the SOLVE-IT MCP Server using Docker and Docker Compose.

Table of Contents


Quick Start

Pull and Run (HTTP Mode)

# Pull the latest image
docker pull 3soos3/solve-it-mcp:latest

# Run in HTTP mode (for Kubernetes/web clients)
docker run -p 8000:8000 \
  -e MCP_TRANSPORT=http \
  3soos3/solve-it-mcp:latest

# Test the server (Kubernetes standard endpoint)
curl http://localhost:8000/healthz

Run with Docker Compose

# Production mode (HTTP transport)
docker-compose up -d

# Development mode (STDIO transport with volume mounts)
docker-compose -f docker-compose.dev.yml up

Docker Images

Available Registries

Images are published to two registries with different purposes:

🐳 Docker Hub (For General Users)

  • Registry: docker.io/3soos3/solve-it-mcp
  • Purpose: General use, easy deployment
  • Tags: Clean list (latest, sha-xxx, version tags only)
  • Artifacts: NO Cosign signatures/SBOM (keeps UI clean)
  • Pull: docker pull 3soos3/solve-it-mcp:latest
  • Benefits: No GitHub account needed, familiar to most developers, works everywhere
  • Note: Rate limits apply (100 pulls/6h for anonymous users)

📦 GitHub Container Registry (For CI/CD & Forensic Compliance)

  • Registry: ghcr.io/3soos3/solve-it-mcp
  • Purpose: CI/CD pipelines, forensic verification, compliance requirements
  • Tags: Full tag list + Cosign artifacts (.sig, .sbom, .att)
  • Artifacts: Cryptographic signatures and SBOM for verification
  • Pull: docker pull ghcr.io/3soos3/solve-it-mcp:latest
  • Speed: Fast (GitHub CDN), no rate limits for public packages
  • Benefits: Chain-of-custody verification, automated CI/CD workflows

Which registry should I use? - Docker Hub: General users, production deployments, ease of use - GHCR: CI/CD pipelines, security teams needing cryptographic verification, compliance audits

Image Tags

Both registries have the same tags:

Tag Description Use Case
latest Latest stable build Production (auto-updates)
stable Manual stable marker Production (manually marked as stable)
v0.2025-10-0.1.0 Full version tag Production (specific version)
sha-abc1234 Git commit SHA Reproducible builds, debugging

Note: GHCR also includes .sig and .sbom artifacts (hidden in Docker Hub).

Multi-Architecture Support

Images are available for: - linux/amd64 - Intel/AMD 64-bit (most common) - linux/arm64 - ARM 64-bit (Apple Silicon, AWS Graviton) - linux/arm/v7 - ARM 32-bit (Raspberry Pi)

Docker automatically pulls the correct architecture for your platform.

Image Size

  • Production image: ~60 MB (multi-stage build, Alpine-optimized)
  • Development image: ~450 MB (includes dev tools)

Transport Modes

The server supports two transport modes, controlled by the MCP_TRANSPORT environment variable.

HTTP Mode (Default in Docker)

Recommended for: - Kubernetes deployments - Web-based MCP clients - Load-balanced environments - Health check monitoring

docker run -p 8000:8000 \
  -e MCP_TRANSPORT=http \
  -e HTTP_PORT=8000 \
  3soos3/solve-it-mcp:latest

Health Endpoints: - GET /healthz - Liveness probe (Kubernetes standard) - GET /readyz - Readiness probe (Kubernetes standard) - GET /health - Legacy liveness probe (deprecated, use /healthz) - GET /ready - Legacy readiness probe (deprecated, use /readyz) - POST /mcp/v1 - Main MCP endpoint (JSON or SSE)

STDIO Mode

Recommended for: - MCP clients (like Claude Desktop) - Direct process communication - Local development

docker run -i \
  -e MCP_TRANSPORT=stdio \
  3soos3/solve-it-mcp:latest

Note: STDIO mode requires -i (interactive) flag and doesn't expose HTTP endpoints.


Configuration

Environment Variables

Core Settings

Variable Default Description
MCP_TRANSPORT http Transport mode: http or stdio
LOG_LEVEL INFO Logging level: DEBUG, INFO, WARNING, ERROR
LOG_FORMAT json Log format: json or text
SOLVEIT_DATA_PATH /app/solve-it-main/data Path to SOLVE-IT knowledge base

HTTP Settings

Variable Default Description
HTTP_HOST 0.0.0.0 Bind address (use 0.0.0.0 for Docker)
HTTP_PORT 8000 HTTP server port
HTTP_WORKERS 1 Number of worker processes
CORS_ORIGINS * Allowed CORS origins (comma-separated)

OpenTelemetry Settings

Variable Default Description
OTEL_ENABLED true Enable OpenTelemetry
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4317 OTel collector endpoint
ENVIRONMENT production Environment: development, staging, production
OTEL_TRACE_SAMPLE_RATE varies Trace sampling rate (0.0-1.0)

Sampling defaults: - Development: 100% (1.0) - Staging: 50% (0.5) - Production: 10% (0.1)

Kubernetes Metadata (Auto-injected)

Variable Default Description
K8S_POD_NAME unknown Pod name (from downward API)
K8S_NODE_NAME unknown Node name (from downward API)
K8S_NAMESPACE default Namespace (from downward API)

Example Configurations

Minimal Production

docker run -p 8000:8000 \
  -e MCP_TRANSPORT=http \
  -e LOG_LEVEL=INFO \
  -e OTEL_ENABLED=false \
  3soos3/solve-it-mcp:latest

Full Observability

docker run -p 8000:8000 \
  -e MCP_TRANSPORT=http \
  -e OTEL_ENABLED=true \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 \
  -e ENVIRONMENT=production \
  -e LOG_FORMAT=json \
  3soos3/solve-it-mcp:latest

Development (STDIO)

docker run -i \
  -e MCP_TRANSPORT=stdio \
  -e LOG_LEVEL=DEBUG \
  -e LOG_FORMAT=text \
  -e OTEL_ENABLED=false \
  3soos3/solve-it-mcp:latest

Docker Compose

Production Setup

File: docker-compose.yml

# Start services
docker-compose up -d

# View logs
docker-compose logs -f

# Check health
curl http://localhost:8000/health

# Stop services
docker-compose down

Features: - HTTP/SSE transport - JSON logging - OpenTelemetry enabled - Health checks - Resource limits (512MB memory, 1 CPU) - Non-root user - Auto-restart policy

Development Setup

File: docker-compose.dev.yml

# Start development environment
docker-compose -f docker-compose.dev.yml up

# Run with volume mounts for hot-reload
docker-compose -f docker-compose.dev.yml up

Features: - STDIO transport - Volume mounts for live code editing - DEBUG logging (text format) - OpenTelemetry disabled - Interactive mode - No auto-restart

Custom Compose Files

Override specific settings by creating a docker-compose.override.yml:

version: '3.8'
services:
  solveit-mcp:
    environment:
      LOG_LEVEL: DEBUG
      CORS_ORIGINS: https://myapp.com
    ports:
      - "9000:8000"  # Use different port

Docker Compose automatically merges override files.


Building Images

Using the Build Script

The repository includes a helper script for building multi-arch images:

# Build and push to Docker Hub
./scripts/build-and-push.sh

# Build locally (no push)
./scripts/build-and-push.sh --no-push

# Build for specific platform
./scripts/build-and-push.sh --platform linux/amd64 --no-push

# Build and tag as latest
./scripts/build-and-push.sh --latest

# Add custom tags
./scripts/build-and-push.sh --tag v1.0.0 --tag production

Manual Build (Single Architecture)

# Build for local platform
docker build -t solve-it-mcp:local .

# Build with custom SOLVE-IT version
docker build \
  --build-arg SOLVE_IT_VERSION=v0.2025-10 \
  -t solve-it-mcp:0.2025-10 .

# Build using local SOLVE-IT data
docker build \
  --build-arg SOLVE_IT_SOURCE=local \
  -t solve-it-mcp:local-data .

Note: For local SOLVE-IT data, place the dataset in ./solve-it-main/ before building.

Multi-Architecture Build

Requires Docker Buildx:

# Create builder
docker buildx create --name mcp-builder --use

# Build for all platforms (example pushes to GHCR for CI/CD)
docker buildx build \
  --platform linux/amd64,linux/arm64,linux/arm/v7 \
  --tag ghcr.io/3soos3/solve-it-mcp:latest \
  --tag 3soos3/solve-it-mcp:latest \
  --push \
  .

Development Image

# Build development image
docker build -f Dockerfile.dev -t solve-it-mcp:dev .

# Run with volume mounts
docker run -i \
  -v $(pwd)/src:/app/src:ro \
  solve-it-mcp:dev

Troubleshooting

Common Issues

1. Container Exits Immediately

Problem: Container starts but exits right away.

Solution: Check logs:

docker logs <container-id>

# Or with compose
docker-compose logs

Common causes: - Invalid transport mode (use http or stdio) - Missing required environment variables - Port already in use

2. Health Check Failing

Problem: /healthz endpoint returns errors or timeouts.

Solution:

# Check if HTTP mode is enabled
docker exec <container-id> env | grep MCP_TRANSPORT

# Should show: MCP_TRANSPORT=http

# Test from inside container (Kubernetes standard)
docker exec <container-id> curl -f http://localhost:8000/healthz

# Or test legacy endpoint (deprecated)
docker exec <container-id> curl -f http://localhost:8000/health

Health checks only work in HTTP mode. In STDIO mode, health checks are disabled.

Note: Use /healthz and /readyz (Kubernetes standard) instead of /health and /ready (deprecated).

3. Permission Denied

Problem: Cannot write to mounted volumes.

Solution: The container runs as UID 1000. Ensure your volume directories have correct permissions:

# Fix permissions
sudo chown -R 1000:1000 ./local-data/

# Or run with current user
docker run --user $(id -u):$(id -g) ...

4. SOLVE-IT Data Not Found

Problem: Server can't load knowledge base data.

Solution: The data is baked into the image. If using custom data:

# Verify data exists in container
docker exec <container-id> ls -la /app/solve-it-main/data/

# Should show: techniques.json, weaknesses.json, mitigations.json

# If missing, rebuild image or mount data:
docker run -v $(pwd)/solve-it-main:/app/solve-it-main:ro ...

5. Multi-arch Build Fails

Problem: docker buildx build fails or is slow.

Solution:

# Install QEMU for cross-platform builds
docker run --privileged --rm tonistiigi/binfmt --install all

# Use buildkit cache
docker buildx build --cache-from type=registry,ref=ghcr.io/3soos3/solve-it-mcp:buildcache ...

For local testing, build only your platform:

./scripts/build-and-push.sh --platform linux/amd64 --no-push

Debugging

Enable Debug Logging

docker run -e LOG_LEVEL=DEBUG -e LOG_FORMAT=text ...

Access Container Shell

# Running container
docker exec -it <container-id> /bin/bash

# New container
docker run -it --entrypoint /bin/bash 3soos3/solve-it-mcp:latest

Inspect Image Layers

# View image history
docker history 3soos3/solve-it-mcp:latest

# Inspect image metadata
docker inspect 3soos3/solve-it-mcp:latest

Security

Image Security

Non-root user: Container runs as UID 1000 (mcpuser)
Minimal base image: Python 3.12-slim (reduces attack surface)
Multi-stage build: Build tools excluded from runtime
Vulnerability scanning: Trivy scanning in CI/CD
No secrets: No hardcoded credentials or tokens
Read-only filesystem: Compatible with read-only root (optional)

Vulnerability Scanning

Images are automatically scanned in CI/CD. Scan locally:

# Install Trivy
brew install aquasecurity/trivy/trivy  # macOS
# or: apt-get install trivy             # Debian/Ubuntu

# Scan image
trivy image 3soos3/solve-it-mcp:latest

# Scan for CRITICAL/HIGH only
trivy image --severity CRITICAL,HIGH 3soos3/solve-it-mcp:latest

Runtime Security

Docker Run Flags:

docker run \
  --security-opt=no-new-privileges:true \
  --cap-drop=ALL \
  --read-only \
  --tmpfs /tmp \
  -u 1000:1000 \
  3soos3/solve-it-mcp:latest

Docker Compose Security:

services:
  solveit-mcp:
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    read_only: true
    tmpfs:
      - /tmp
    user: "1000:1000"

Network Security

Limit exposed ports:

# Bind to localhost only
docker run -p 127.0.0.1:8000:8000 ...

Configure CORS:

# Production: specific origins only
docker run -e CORS_ORIGINS=https://app.example.com,https://dashboard.example.com ...

# Development: allow all
docker run -e CORS_ORIGINS=* ...

Secrets Management

Never pass secrets via environment variables in production.

Use Docker secrets or volume mounts:

# Docker secrets (Swarm)
echo "my-secret-token" | docker secret create mcp_token -
docker service create --secret mcp_token ...

# Volume mount (single container)
docker run -v /path/to/secrets:/secrets:ro ...

Forensic Verification (GHCR Only)

For forensic investigations requiring chain-of-custody and cryptographic verification, use GHCR images with Cosign.

Prerequisites

Install Cosign:

# macOS
brew install cosign

# Linux
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign

Verify Image Signature

Proves the image was built by the official GitHub Actions workflow:

cosign verify ghcr.io/3soos3/solve-it-mcp:latest \
  --certificate-identity-regexp=github \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com

Output:

{
  "payloadType": "application/vnd.dev.cosign.simplesigning.v1+json",
  "payload": "...",
  "signatures": [...]
}

Download SBOM

See all dependencies (Software Bill of Materials):

# Download SBOM in SPDX format
cosign download sbom ghcr.io/3soos3/solve-it-mcp:latest > sbom.spdx.json

# View dependencies
jq '.packages[] | {name: .name, version: .versionInfo, license: .licenseDeclared}' sbom.spdx.json

View Build Provenance

See source commit, workflow, builder identity:

cosign download attestation ghcr.io/3soos3/solve-it-mcp:latest | jq

Includes: - Source repository and commit SHA - GitHub Actions workflow that built the image - Build timestamp and environment - Cryptographic proof of authenticity

Why Not Docker Hub?

Docker Hub images do NOT include Cosign signatures/SBOM attachments to keep the tag list clean (no .sig/.sbom clutter in UI). For forensic verification, always use GHCR.


Next Steps


Resources

  • Docker Hub: https://hub.docker.com/r/3soos3/solve-it-mcp
  • GitHub Container Registry: https://github.com/3soos3/solve-it-mcp/pkgs/container/solve-it-mcp
  • GitHub: https://github.com/3soos3/solve-it-mcp
  • SOLVE-IT Dataset: https://github.com/SOLVE-IT-DF/solve-it
  • MCP Specification: https://modelcontextprotocol.io