forked from IBM/mcp-context-forge
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContainerfile
More file actions
155 lines (127 loc) · 6.02 KB
/
Copy pathContainerfile
File metadata and controls
155 lines (127 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
###############################################################################
# Rust builder stage - builds Rust plugins in manylinux2014 container
# To build WITH Rust: docker build --build-arg ENABLE_RUST=true .
# To build WITHOUT Rust (default): docker build .
###############################################################################
ARG ENABLE_RUST=false
###########################
# Frontend builder stage
###########################
FROM node:lts-alpine AS frontend-builder
WORKDIR /app
# Copy package.json and package-lock.json
COPY package.json package-lock.json ./
# Install frontend dependencies
RUN npm install --frozen-lockfile
# Copy frontend source files
COPY mcpgateway/admin_ui/ mcpgateway/admin_ui/
COPY vite.config.js ./
# Run Vite build (cleans old bundles and generates fresh manifest)
RUN npm run vite:build
FROM quay.io/pypa/manylinux2014:2026.03.06-3 AS rust-builder-base
ARG ENABLE_RUST
# Set shell with pipefail for safety
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Only build if ENABLE_RUST=true
RUN if [ "$ENABLE_RUST" != "true" ]; then \
echo "⏭️ Rust builds disabled (set --build-arg ENABLE_RUST=true to enable)"; \
mkdir -p /build/rust-wheels; \
exit 0; \
fi
# Install Rust toolchain (only if ENABLE_RUST=true)
RUN if [ "$ENABLE_RUST" = "true" ]; then \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable; \
fi
ENV PATH="/root/.cargo/bin:$PATH"
WORKDIR /build
# Copy only Rust plugin files (only if ENABLE_RUST=true)
COPY plugins_rust/ /build/plugins_rust/
# Build each Rust plugin independently using Python 3.12 from manylinux image
# Each plugin has its own Cargo.toml and is built separately
RUN if [ "$ENABLE_RUST" = "true" ]; then \
mkdir -p /build/rust-wheels && \
/opt/python/cp312-cp312/bin/python -m pip install --upgrade pip maturin && \
for plugin_dir in /build/plugins_rust/*/; do \
if [ -f "$plugin_dir/Cargo.toml" ]; then \
plugin_name=$(basename "$plugin_dir"); \
echo "🦀 Building Rust plugin: $plugin_name"; \
(cd "$plugin_dir" && /opt/python/cp312-cp312/bin/maturin build --release --compatibility manylinux2014 --out /build/rust-wheels) || exit 1; \
fi; \
done && \
echo "✅ Rust plugins built successfully"; \
else \
echo "⏭️ Skipping Rust plugin build"; \
fi
FROM rust-builder-base AS rust-builder
###############################################################################
# Main application stage
###############################################################################
FROM registry.access.redhat.com/ubi10/ubi-minimal:10.1-1772441549
LABEL maintainer="Mihai Criveti" \
name="mcp/mcpgateway" \
version="1.0.0-RC-2" \
description="ContextForge: An enterprise-ready Model Context Protocol Gateway"
ARG PYTHON_VERSION=3.12
ARG GRPC_PYTHON_BUILD_SYSTEM_OPENSSL='False'
# Install Python and build dependencies
# hadolint ignore=DL3041
RUN microdnf update -y && \
microdnf install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-devel gcc git openssl-devel postgresql-devel gcc-c++ && \
microdnf clean all
# Set default python3 to the specified version
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTHON_VERSION} 1
WORKDIR /app
# ----------------------------------------------------------------------------
# s390x architecture does not support BoringSSL when building wheel grpcio.
# Force Python whl to use OpenSSL.
# NOTE: ppc64le has the same OpenSSL requirement
# ----------------------------------------------------------------------------
RUN if [ "$(uname -m)" = "s390x" ] || [ "$(uname -m)" = "ppc64le" ]; then \
echo "Building for $(uname -m)."; \
echo "export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL='True'" > /etc/profile.d/use-openssl.sh; \
else \
echo "export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL='False'" > /etc/profile.d/use-openssl.sh; \
fi
RUN chmod 644 /etc/profile.d/use-openssl.sh
# Copy project files into container
COPY . /app
# Copy frontend build artifacts from frontend-builder stage
COPY --from=frontend-builder /app/mcpgateway/static/ /app/mcpgateway/static/
# Copy Rust plugin wheels from builder (if any exist)
COPY --from=rust-builder /build/rust-wheels/ /tmp/rust-wheels/
# Create virtual environment, upgrade pip and install dependencies using uv for speed
# Including observability packages for OpenTelemetry support and Rust plugins (if built)
# Granian is included as an optional high-performance alternative to Gunicorn
ARG ENABLE_RUST=false
RUN python3 -m venv /app/.venv && \
. /etc/profile.d/use-openssl.sh && \
/app/.venv/bin/python3 -m pip install --upgrade pip setuptools pdm uv && \
/app/.venv/bin/python3 -m uv pip install ".[redis,postgres,observability,granian]" && \
if [ "$ENABLE_RUST" = "true" ] && ls /tmp/rust-wheels/*.whl 1> /dev/null 2>&1; then \
echo "🦀 Installing Rust plugins..."; \
/app/.venv/bin/python3 -m pip install /tmp/rust-wheels/*.whl && \
/app/.venv/bin/python3 -c "from pii_filter_rust.pii_filter_rust import PIIDetectorRust; print('✓ Rust PII filter installed successfully')"; \
else \
echo "⏭️ Rust plugins not available - using Python implementations"; \
fi && \
rm -rf /tmp/rust-wheels
# update the user permissions
RUN chown -R 1001:0 /app && \
chmod -R g=u /app
# Expose the application port
EXPOSE 4444
# Set the runtime user
USER 1001
# Ensure virtual environment binaries are in PATH and project modules resolve
# even when containers run an alternate Python entrypoint.
ENV PATH="/app/.venv/bin:$PATH" \
PYTHONPATH="/app"
# HTTP server selection via HTTP_SERVER environment variable:
# - gunicorn : Python-based with Uvicorn workers (default)
# - granian : Rust-based HTTP server (alternative)
#
# Examples:
# docker run -e HTTP_SERVER=gunicorn mcpgateway # Default
# docker run -e HTTP_SERVER=granian mcpgateway # Alternative
ENV HTTP_SERVER=gunicorn
CMD ["./docker-entrypoint.sh"]