Skip to content
Merged
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
89 changes: 41 additions & 48 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,39 @@ name: CI/CD Pipeline

on:
push:
branches: [ master, release ]
branches: [master, release]
pull_request:
branches: [ master ]
branches: [master]
release:
types: [ published ]
types: [published]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
lint:
name: Code Style & Linting
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Create virtual environment
run: python -m venv venv
python-version: "3.12"

- name: Install dependencies
run: |
source venv/bin/activate
pip install --upgrade pip
pip install black flake8
pip install -e .
pip install \
"git+https://github.com/vicentebolea/vtk-knowledge" \
"git+https://github.com/vicentebolea/vtk-validate"
pip install -e ".[dev]"

- name: Run Black
run: |
source venv/bin/activate
black --check --diff src/ tests/
- name: ruff lint
run: ruff check src/vtk_mcp/

- name: Run Flake8
run: |
source venv/bin/activate
flake8 src/
- name: ruff format check
run: ruff format --check src/vtk_mcp/

actionlint:
runs-on: ubuntu-latest
Expand All @@ -52,53 +43,56 @@ jobs:

- name: Install actionlint
run: |
# Download and install actionlint
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
echo "${PWD}" >> "$GITHUB_PATH"

- name: Run actionlint
run: actionlint

test:
name: Run Tests
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
needs: [lint, actionlint]
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
python-version: ["3.10", "3.11", "3.12"]

steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Create virtual environment
run: python -m venv venv

- name: Install dependencies
run: |
source venv/bin/activate
pip install --upgrade pip
pip install -e ".[test]"
pip install \
"git+https://github.com/vicentebolea/vtk-knowledge" \
"git+https://github.com/vicentebolea/vtk-validate"
pip install -e ".[dev]"

- name: Run unit tests
run: |
source venv/bin/activate
pytest -m unit -v
run: pytest -m unit -v

- name: Run client tests
run: |
source venv/bin/activate
pytest tests/test_client_no_server.py -v
run: pytest tests/test_client_no_server.py -v

- name: Run integration tests
run: |
source venv/bin/activate
pytest -m integration -v
run: pytest -m integration -v

uv-smoke:
name: uv smoke test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: uv sync resolves all dependencies
run: uv sync --extra dev

- name: Import check
run: uv run python -c "from vtk_mcp.config import Settings; Settings()"

docker-deploy:
name: Build and Push Deployment Image
Expand All @@ -109,8 +103,7 @@ jobs:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
submodules: recursive

Expand Down
50 changes: 35 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,51 @@
FROM python:3.11-slim
FROM python:3.12-slim

LABEL org.opencontainers.image.title="VTK MCP Gateway"
LABEL org.opencontainers.image.description="Production MCP gateway for VTK LLM tooling"
LABEL org.opencontainers.image.source="https://github.com/kitware/vtk-mcp"
LABEL org.opencontainers.image.source="https://github.com/Kitware/vtk-mcp"
LABEL org.opencontainers.image.licenses="MIT"

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_NO_CACHE_DIR=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

# Install runtime dependencies — no VTK runtime, no LiteLLM
RUN pip install vtk-knowledge vtk-validate vtk-mcp

# Bundle the knowledge artifact (built separately and passed at build time)
# VTK version to pre-cache at image build time
ARG VTK_VERSION=9.3.0
ARG KNOWLEDGE_ARTIFACT_URL=""
RUN if [ -n "$KNOWLEDGE_ARTIFACT_URL" ]; then \
curl -fSL "$KNOWLEDGE_ARTIFACT_URL" -o /app/data/vtk-knowledge.jsonl; \
fi
ENV VTK_MCP_VTK_VERSION=${VTK_VERSION}

COPY data/ /app/data/
WORKDIR /app

# Install uv for fast dependency installation
RUN pip install uv

# Install vtk-* sibling packages from GitHub (not on PyPI)
RUN uv pip install --system \
"git+https://github.com/vicentebolea/vtk-knowledge" \
"git+https://github.com/vicentebolea/vtk-validate"

# Install vtk-mcp with optional retrieval support
COPY . /app/
RUN uv pip install --system -e ".[retrieval]"

# Pre-download the vtk-knowledge JSONL artifact and vtk-index embedded
# Qdrant storage so the image is ready to serve without network access.
RUN python - <<'EOF'
import logging
logging.basicConfig(level=logging.INFO)
import os
vtk_version = os.environ["VTK_MCP_VTK_VERSION"]
from vtk_knowledge import VTKAPIIndex
VTKAPIIndex.from_artifact(vtk_version)
try:
from vtk_index import Retriever
Retriever.from_artifact(vtk_version)
except Exception as e:
logging.warning("vtk-index embedded storage skipped: %s", e)
EOF

ENV VTK_MCP_KNOWLEDGE_ARTIFACT_PATH=/app/data/vtk-knowledge.jsonl
ENV VTK_MCP_VTK_VERSION=${VTK_VERSION}
ENV VTK_MCP_TRANSPORT=stdio
ENV VTK_MCP_ENABLE_VALIDATION=true
ENV VTK_MCP_ENABLE_RETRIEVAL=true

ENTRYPOINT ["python", "-m", "vtk_mcp"]
77 changes: 41 additions & 36 deletions deploy.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,46 +1,51 @@
LABEL org.opencontainers.image.title="VTK MCP Server with Embeddings"
LABEL org.opencontainers.image.description="Model Context Protocol server for VTK with vector search embeddings"
LABEL org.opencontainers.image.source="https://github.com/kitware/vtk-mcp"
LABEL org.opencontainers.image.authors="Vicente Adolfo Bolea Sanchez <vicente.bolea@kitware.com>"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.documentation="https://github.com/kitware/vtk-mcp/blob/main/README.md"

FROM python:3.12-slim AS embeddings

# Download embeddings database from GHCR
COPY --from=ghcr.io/kitware/vtk-mcp/embeddings-database:latest /vtk-examples-embeddings.tar.gz /tmp/

# Extract the database
RUN mkdir -p /app/db && \
tar -xzf /tmp/vtk-examples-embeddings.tar.gz -C /app/db && \
rm /tmp/vtk-examples-embeddings.tar.gz

FROM python:3.12-slim

LABEL org.opencontainers.image.title="VTK MCP Gateway"
LABEL org.opencontainers.image.description="Production MCP gateway for VTK LLM tooling"
LABEL org.opencontainers.image.source="https://github.com/Kitware/vtk-mcp"
LABEL org.opencontainers.image.licenses="MIT"

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_NO_CACHE_DIR=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

# Install system dependencies for VTK
RUN apt update && \
apt install --no-install-recommends --no-install-suggests -y \
libgl1-mesa-dev \
libxrender-dev/stable \
git && \
rm -rf /var/lib/apt/lists/*
# VTK version to pre-cache at image build time
ARG VTK_VERSION=9.3.0
ENV VTK_MCP_VTK_VERSION=${VTK_VERSION}

WORKDIR /app

# Copy application code
COPY . .

# Copy embeddings database from first stage
COPY --from=embeddings /app/db /app/db

# Install Python dependencies (including RAG dependencies)
RUN pip install --upgrade pip && \
pip install --verbose .

# Start server with database path configured
CMD ["vtk-mcp-server", "--transport", "http", "--host", "0.0.0.0", "--port", "8000", "--database-path", "/app/db/vtk-examples"]
# Install uv for fast dependency installation
RUN pip install uv

# Install vtk-* sibling packages from GitHub (not on PyPI)
RUN uv pip install --system \
"git+https://github.com/vicentebolea/vtk-knowledge" \
"git+https://github.com/vicentebolea/vtk-validate"

# Install vtk-mcp with optional retrieval support
COPY . /app/
RUN uv pip install --system -e ".[retrieval]"

# Pre-download the vtk-knowledge JSONL artifact and vtk-index embedded
# Qdrant storage so the image is ready to serve without network access.
RUN python - <<'EOF'
import logging
logging.basicConfig(level=logging.INFO)
import os
vtk_version = os.environ["VTK_MCP_VTK_VERSION"]
from vtk_knowledge import VTKAPIIndex
VTKAPIIndex.from_artifact(vtk_version)
try:
from vtk_index import Retriever
Retriever.from_artifact(vtk_version)
except Exception as e:
logging.warning("vtk-index embedded storage skipped: %s", e)
EOF

ENV VTK_MCP_TRANSPORT=stdio
ENV VTK_MCP_ENABLE_VALIDATION=true
ENV VTK_MCP_ENABLE_RETRIEVAL=true

ENTRYPOINT ["python", "-m", "vtk_mcp"]
42 changes: 30 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "vtk-mcp"
version = "1.0.0"
Expand Down Expand Up @@ -37,31 +41,34 @@ vtk-mcp = "vtk_mcp.__main__:main"
retrieval = [
"vtk-index>=1.0.0",
]
test = [
dev = [
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"pytest-mock>=3.10.0",
"responses>=0.23.0",
"httpx>=0.24.0",
"ruff>=0.8.0",
]

[project.urls]
Homepage = "https://github.com/kitware/vtk-mcp"
Repository = "https://github.com/kitware/vtk-mcp"
Issues = "https://github.com/kitware/vtk-mcp/issues"
Homepage = "https://github.com/Kitware/vtk-mcp"
Repository = "https://github.com/Kitware/vtk-mcp"
Issues = "https://github.com/Kitware/vtk-mcp/issues"

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.hatch.build.targets.wheel]
packages = ["src/vtk_mcp"]

[tool.setuptools.packages.find]
where = ["src"]
[tool.uv.sources]
vtk-knowledge = { git = "https://github.com/vicentebolea/vtk-knowledge" }
vtk-validate = { git = "https://github.com/vicentebolea/vtk-validate" }
vtk-index = { git = "https://github.com/vicentebolea/vtk-index" }

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = "test_*.py"
python_classes = "Test*"
python_functions = "test_*"
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
pythonpath = ["src"]
addopts = [
"-v",
"--tb=short",
Expand All @@ -79,3 +86,14 @@ filterwarnings = [
"ignore::DeprecationWarning",
"ignore::PendingDeprecationWarning",
]

[tool.ruff]
line-length = 120
target-version = "py310"

[tool.ruff.lint]
select = ["E", "F", "I", "W"]
ignore = ["E501"]

[tool.ruff.lint.isort]
known-first-party = ["vtk_mcp"]
Loading
Loading