MCP Streamable HTTP service for offline ephemeral Python execution.
- No runtime package installs — no
uv run --scriptdependency resolution, nodependenciestool arg, PEP 723dependencies = [...]is rejected. - Allowlisted packages are installed only at image build time into
/opt/code-tools-env(seepackages.txt). - Offline execution (
sandbox_backend: native): each script runs underunshare --net(empty netns). RequiresCAP_SYS_ADMIN. Deploy a NetworkPolicy deny-egress on the pod (helmextraDeploy) so CNI blocks egress even if a script joins the pod netns viasetns. - Tool results are JSON (
stdout/stderr/exit_code/artifacts), not a concatenated text dump.
docker run --rm -p 8000:8000 -p 9999:9999 \
--cap-add SYS_ADMIN \
mcp-python:testCAP_SYS_ADMIN is enough for unshare --net. Full bubblewrap --unshare-all
would need --privileged on most hosts — we intentionally use unshare --net
instead.
Chart sets deployment.securityContext.capabilities.add: [SYS_ADMIN, …] and
sandbox_backend: native. Also add a NetworkPolicy deny-egress on the
code-tools pods as defense in depth.
Contract: MCP tools execute_python, check_environment, validate_code.
Endpoint: POST http://<host>:8000/mcp (stateless Streamable HTTP, JSON).
Metrics: GET http://<host>:9999/metrics (Prometheus via redup-servicekit).
Tool args: execute_python takes code (required), timeout,
and optional files: [{path, content_base64}, …] written under
INPUTS_DIR for that call only. validate_code takes code. There is
no dependencies argument.
Input files: relative path under INPUTS_DIR + content_base64. Hosts
may populate content_base64. Example (client supplies bytes)::
files=[{"path": "data.zip", "content_base64": "<base64>"}]
# in code:
Path(os.environ["INPUTS_DIR"], "data.zip").read_bytes()
Output binaries: write files under ARTIFACTS_DIR (set in the process env).
They are returned in the JSON artifacts[] field as content_base64.
config/config.yaml:
service:
console_log_level: INFO
host: "0.0.0.0"
port: 8000
path: /mcp
max_workers: 4
hpa_max_workers: 2
McpPythonRunner:
sandbox_backend: native # unshare --net; needs CAP_SYS_ADMIN
python_version: "3.13"
runtime_python: "/opt/code-tools-env/bin/python"
packages_file: "/config/packages.txt"
default_timeout: 30
max_timeout: 300
max_output_bytes: 1048576
max_artifact_bytes: 5242880
max_artifacts_total_bytes: 10485760
json_response: true
stateless_http: trueOverride via servicekit env substitution (section___key):
export McpPythonRunner___sandbox_backend=native
export McpPythonRunner___runtime_python=/opt/code-tools-env/bin/python
export service___port=8000sandbox_backend=native needs CAP_SYS_ADMIN (see Docker run / Helm
securityContext above). If the capability is missing, unshare --net fails
and tool calls return a non-zero exit — fix the securityContext, do not silently
fall back to networked execution.
docker run --rm -p 8000:8000 -p 9999:9999 \
redup4ai/redup.mcp-python-runner:0.1.0-3.13-slimMCP URL: http://127.0.0.1:8000/mcp. Metrics: http://127.0.0.1:9999/metrics.
Requires Python 3.13+ and a preinstalled scientific stack (or point
--runtime-python at a venv that already has packages.txt installed):
uv sync
uv run python -m redup_mcp_python_runner.service config/config.yamlDesktop MCP clients (stdio):
uv run redup-mcp-python-runner --transport stdio --sandbox-backend noneuv sync --dev
uv run pytest tests -qMIT — see LICENSE.
Derived from mcp-python-exec-sandbox
(Copyright (c) 2025 mcp-python-executor contributors), MIT. See NOTICE.