Skip to content

Add Dockerfile for Docker MCP Registry#198

Open
ramikassab wants to merge 6 commits intoahujasid:mainfrom
ramikassab:main
Open

Add Dockerfile for Docker MCP Registry#198
ramikassab wants to merge 6 commits intoahujasid:mainfrom
ramikassab:main

Conversation

@ramikassab
Copy link

@ramikassab ramikassab commented Mar 7, 2026

Summary

Adds a Dockerfile to enable containerized deployment via the Docker MCP Registry.

  • Uses uvx to run blender-mcp, consistent with the project's recommended installation approach
  • Sets BLENDER_HOST=host.docker.internal so the container can reach Blender on the host
  • Sets BLENDER_PORT=9876 matching the default
  • Disables telemetry by default (DISABLE_TELEMETRY=true) for containerized environments
  • Runs as non-root user (appuser) for security

Test plan

  • docker build -t blender-mcp . builds successfully
  • docker run --rm blender-mcp starts the MCP server (connects to Blender if addon is running)
  • Validated and built with Docker MCP Registry tooling (task validate, task build --tools)
  • Gateway discovers all 22 tools and 1 prompt

Summary by CodeRabbit

  • Chores
    • Containerized deployment added for simplified, reproducible installs.
    • Container runs the app via a preconfigured runtime and includes the 1.5.5 app release by default.
    • Runs as a non-root application user for improved security.
    • Networking and telemetry environment settings are preset for the container runtime.

localhost inside a container cannot reach the host Blender instance.
Default to host.docker.internal so the server connects to the host.
Create a dedicated appuser and switch to it before ENTRYPOINT
so the server runs unprivileged.
Set DISABLE_TELEMETRY=true so the containerized server does not
phone home. Users can override with -e DISABLE_TELEMETRY=false.
uvx needs a writable cache directory at ~/.cache/uv.
@qodo-code-review
Copy link

Review Summary by Qodo

Add Dockerfile for Docker MCP Registry integration

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Adds Dockerfile for containerized deployment via Docker MCP Registry
• Configures container to connect to host Blender instance
• Runs container as non-root user for improved security
• Disables telemetry by default in containerized environments
Diagram
flowchart LR
  A["Python 3.12 Base Image"] --> B["Install uv Package Manager"]
  B --> C["Create Non-Root appuser"]
  C --> D["Configure Environment Variables"]
  D --> E["Set ENTRYPOINT to uvx blender-mcp"]
  F["BLENDER_HOST: host.docker.internal"] -.-> D
  G["BLENDER_PORT: 9876"] -.-> D
  H["DISABLE_TELEMETRY: true"] -.-> D
Loading

Grey Divider

File Changes

1. Dockerfile ✨ Enhancement +13/-0

Docker containerization with security and host connectivity

• Creates Docker image based on Python 3.12-slim with uv package manager
• Establishes non-root user (appuser) with home directory for security
• Sets environment variables for Blender connectivity and telemetry control
• Configures entrypoint to run blender-mcp via uvx

Dockerfile


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 7, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Runs external blender-mcp🐞 Bug ⛯ Reliability
Description
The image never installs this repository’s code; it runs uvx blender-mcp, so the container may
execute a different blender-mcp version than the PR’s source. This undermines reproducibility and
can cause hard-to-debug behavior differences across rebuilds/runs.
Code

Dockerfile[R3-13]

+RUN pip install --no-cache-dir uv
+
+RUN groupadd --system appuser && useradd --system --gid appuser --create-home appuser
+
+ENV BLENDER_HOST=host.docker.internal
+ENV BLENDER_PORT=9876
+ENV DISABLE_TELEMETRY=true
+
+USER appuser
+
+ENTRYPOINT ["uvx", "blender-mcp"]
Evidence
The Dockerfile only installs uv and then uses uvx to run blender-mcp, without
copying/installing the local project. The repository defines a specific package version and console
script entrypoint, implying the Docker image should run that code/version rather than whatever uvx
resolves at runtime.

Dockerfile[1-13]
pyproject.toml[1-24]
uv.lock[29-38]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Docker image does not install/copy this repository’s code; it runs `uvx blender-mcp`, which can execute a different version of the package than the PR’s code and breaks reproducibility.
### Issue Context
The repo already defines the console script entrypoint (`blender-mcp = blender_mcp.server:main`) and a project version. The Docker image should run that code/version.
### Fix Focus Areas
- Dockerfile[1-13]
- pyproject.toml[1-24]
### Suggested direction
- Add `WORKDIR /app` and `COPY . /app`
- Install the project at build time (e.g., `pip install .` or use `uv` to `sync` from `uv.lock` in frozen mode)
- Change the entrypoint to run the installed script (e.g., `ENTRYPOINT ["blender-mcp"]`)
- If you intentionally want to run the published artifact instead of the repo code, pin it explicitly (e.g., `uvx blender-mcp==1.5.5`) so runtime behavior matches the intended version.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unpinned base/uv 🐞 Bug ⛨ Security
Description
The base image and uv installation are unpinned, so rebuilds may silently change Python/uv
behavior and security posture over time. This reduces reproducibility for registry builds.
Code

Dockerfile[R1-3]

+FROM python:3.12-slim
+
+RUN pip install --no-cache-dir uv
Evidence
The Dockerfile uses a floating base tag and installs uv without a version constraint, which makes
builds non-deterministic across time.

Dockerfile[1-3]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Docker builds are not reproducible because the base image tag and `uv` version are not pinned.
### Issue Context
This Dockerfile is intended for distribution via a registry workflow; deterministic rebuilds are important.
### Fix Focus Areas
- Dockerfile[1-3]
### Suggested direction
- Pin the Python base image to an immutable digest (e.g., `python:3.12-slim@sha256:...`) or a specific patch tag.
- Pin `uv` (e.g., `pip install --no-cache-dir uv==<version>`), and consider documenting how/when to update it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Hardcoded BLENDER_HOST 🐞 Bug ✓ Correctness
Description
The image sets BLENDER_HOST=host.docker.internal, overriding the repo’s documented default of
localhost. This default may be wrong for some deployments unless users override the env var at
runtime.
Code

Dockerfile[R7-8]

+ENV BLENDER_HOST=host.docker.internal
+ENV BLENDER_PORT=9876
Evidence
Repo docs and code indicate the default Blender host is localhost unless overridden; the
Dockerfile forces an override for all container runs, changing default behavior compared to the
documented/default configuration.

Dockerfile[7-9]
README.md[81-92]
src/blender_mcp/server.py[25-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Docker image forces `BLENDER_HOST=host.docker.internal`, overriding the documented/code default (`localhost`). This changes default behavior and can cause connection failures in environments where `host.docker.internal` is not the right target.
### Issue Context
The repo already documents `host.docker.internal` as an *example* override, while the code defaults to `localhost`.
### Fix Focus Areas
- Dockerfile[7-8]
- README.md[81-92]
### Suggested direction
- Consider removing the `ENV BLENDER_HOST=...` line so the code default applies.
- Alternatively, make it configurable via `ARG BLENDER_HOST` with a default and/or provide clear README/container-run docs showing the recommended value per deployment.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

Introduces a new Dockerfile that builds a Python 3.12-slim image, installs the uv package, creates a non-root app user, sets Blender networking and telemetry environment variables, and uses an ENTRYPOINT to run uvx with blender-mcp==1.5.5.

Changes

Cohort / File(s) Summary
Docker Configuration
Dockerfile
Adds a new Dockerfile: uses python:3.12-slim, installs uv via pip without cache, creates a non-root appuser, sets Blender networking/telemetry env vars, and sets ENTRYPOINT to run uvx with blender-mcp==1.5.5.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 In a tiny image I hop and sing,
Python light, with uv in spring,
Non-root hops keep safety near,
Blender flags whisper clear,
ENTRYPOINT hums — the container's cheer.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a Dockerfile for Docker MCP Registry deployment, which matches the PR objective and the file-level summary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Line 3: The Dockerfile currently runs "pip install --no-cache-dir uv" which
installs the published tool at container startup instead of baking the
repository source into the image; change the build to COPY the repository
sources into the image (e.g., into /app) and run pip install against the local
package (e.g., pip install . or pip install /app) so the image contains the PR
code rather than resolving the package at runtime; update the RUN step that
calls "pip install --no-cache-dir uv" to instead install the local package and
remove reliance on the uv/uvx tool alias at startup.
- Line 7: The Dockerfile sets ENV BLENDER_HOST=host.docker.internal which works
on Docker Desktop but fails on Linux Docker Engine unless host.docker.internal
is mapped; update the run/Compose documentation and any README or deployment
instructions to show how Linux users must add the host-gateway mapping (e.g.,
include the docker run flag --add-host=host.docker.internal:host-gateway and the
Compose extra_hosts entry "- \"host.docker.internal:host-gateway\"") so
containers can reach the host when BLENDER_HOST uses host.docker.internal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1bc1c485-4b06-4290-a58a-1a270e48570c

📥 Commits

Reviewing files that changed from the base of the PR and between 7636d13 and f901df5.

📒 Files selected for processing (1)
  • Dockerfile

@@ -0,0 +1,13 @@
FROM python:3.12-slim

RUN pip install --no-cache-dir uv
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

git ls-files | head -20

Repository: ahujasid/blender-mcp

Length of output: 368


🏁 Script executed:

fd -t f "^(pyproject\.toml|README\.md|Dockerfile)$" --max-one-result

Repository: ahujasid/blender-mcp

Length of output: 297


🏁 Script executed:

cat Dockerfile

Repository: ahujasid/blender-mcp

Length of output: 344


🌐 Web query:

uv uvx tool run documentation astral

💡 Result:

Astral uv docs for uvx / uv tool run (running Python CLI tools in an isolated, ephemeral env):

  • Tools concept guide (recommended starting point): explains what “tools” are, how uvx is exactly an alias of uv tool run, caching behavior, and how it differs from uv run. [1]
  • CLI reference (uv tool run / uvx): full command syntax and options, including version pinning like <package>@<version> and behavior when a tool is already installed. [2]
  • uv overview page: quick examples of uvx <tool> and uv tool install to contrast ephemeral execution vs installation. [3]

Sources: [1] Tools | uv (Astral docs) https://docs.astral.sh/uv/concepts/tools/ • [2] Commands / CLI reference | uv https://docs.astral.sh/uv/reference/cli/ • [3] uv documentation home https://docs.astral.sh/uv/


🏁 Script executed:

cat pyproject.toml

Repository: ahujasid/blender-mcp

Length of output: 909


Bake the local package into the image instead of resolving it at startup.

This Dockerfile never copies or installs the repository sources, so the resulting image is not actually built from this PR. uvx is an alias for uv tool run and executes the command from a cached, disposable tool environment, which means cold starts depend on registry/network availability and will run whatever published blender-mcp version is available instead of the code you just built.

Proposed fix
 FROM python:3.12-slim
 
 RUN pip install --no-cache-dir uv
 
 RUN groupadd --system appuser && useradd --system --gid appuser --create-home appuser
+
+WORKDIR /app
+COPY pyproject.toml README.md /app/
+COPY src /app/src/
+RUN pip install --no-cache-dir /app
 
 ENV BLENDER_HOST=host.docker.internal
 ENV BLENDER_PORT=9876
 ENV DISABLE_TELEMETRY=true
 
 USER appuser
 
-ENTRYPOINT ["uvx", "blender-mcp"]
+ENTRYPOINT ["blender-mcp"]

Also applies to: 13-13

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` at line 3, The Dockerfile currently runs "pip install
--no-cache-dir uv" which installs the published tool at container startup
instead of baking the repository source into the image; change the build to COPY
the repository sources into the image (e.g., into /app) and run pip install
against the local package (e.g., pip install . or pip install /app) so the image
contains the PR code rather than resolving the package at runtime; update the
RUN step that calls "pip install --no-cache-dir uv" to instead install the local
package and remove reliance on the uv/uvx tool alias at startup.


RUN groupadd --system appuser && useradd --system --gid appuser --create-home appuser

ENV BLENDER_HOST=host.docker.internal
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Docker host.docker.internal Linux Docker Engine support networking

💡 Result:

Does host.docker.internal work on Linux with Docker Engine?

Yes—but not automatically like on Docker Desktop.

What’s supported (Linux Docker Engine)

  • Docker Engine added support for host.docker.internal on Linux (via the “host-gateway” mechanism) in the 20.10 line. (docs.docker.com)
  • To make it work, you typically map it explicitly to the host gateway IP:

docker run

docker run --add-host=host.docker.internal:host-gateway …

docker compose

services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"

Docker Desktop note

  • On Docker Desktop, host.docker.internal is provided as a special DNS name that resolves to the host automatically. (docs.docker.com)

Alternative approach (Linux-only)

  • If you actually want the container to share the host network stack, use host networking (--network host / network_mode: host). This is a Linux host feature. (docs.docker.com)

Citations:


🌐 Web query:

Docker Desktop vs Linux Docker Engine host.docker.internal host-gateway

💡 Result:

Key difference: where the Docker daemon runs

  • Docker Desktop (macOS/Windows, and Desktop for Linux) runs the Linux Docker Engine inside a lightweight VM, not directly on your host OS. Docker Desktop provides special DNS names under docker.internal, including host.docker.internal, which is made to resolve to “the host” from inside containers. [1][2]
  • Docker Engine on Linux (native, no Desktop) runs directly on the Linux host. There is no built-in DNS name host.docker.internal unless you add it yourself. The standard pattern is to map it to the container network’s host-side gateway using host-gateway. [3]

host.docker.internal: Desktop vs native Linux Engine

Docker Desktop

  • host.docker.internal works out of the box (Docker Desktop provides it). [1][2]

Native Docker Engine on Linux

  • Use the special keyword host-gateway to create the mapping:
    docker run --add-host=host.docker.internal:host-gateway …
    Docker documents host-gateway as a special value for --add-host. [3]
  • In Docker Compose:
    services:
      app:
        extra_hosts:
          - "host.docker.internal:host-gateway"
    (This relies on the same Engine feature.) [3]

What host-gateway actually targets (Linux Engine)

  • host-gateway resolves to the gateway IP address for the container’s network (commonly the host-side bridge interface, e.g. docker0 on the default bridge). Docker also lets you override what it resolves to via dockerd --host-gateway-ip / host-gateway-ip in daemon config. [3]

Version note

  • The host-gateway mechanism is associated with Docker Engine v20.10+ era behavior (and has release-notes history around --add-host=…:host-gateway). [4]

Sources: Docker Desktop networking/how-tos and internals [1][2], Docker dockerd reference documenting host-gateway and host-gateway-ip [3], Docker Engine 20.10 release notes [4].


Add documentation for Linux Docker Engine users to map host.docker.internal.

host.docker.internal works automatically on Docker Desktop but requires explicit configuration on Linux Docker Engine. Without the host-gateway mapping, containers will fail to reach the host on Linux systems. Update run/Compose documentation to include the required mappings for Linux users:

docker run --add-host=host.docker.internal:host-gateway …
extra_hosts:
  - "host.docker.internal:host-gateway"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` at line 7, The Dockerfile sets ENV
BLENDER_HOST=host.docker.internal which works on Docker Desktop but fails on
Linux Docker Engine unless host.docker.internal is mapped; update the
run/Compose documentation and any README or deployment instructions to show how
Linux users must add the host-gateway mapping (e.g., include the docker run flag
--add-host=host.docker.internal:host-gateway and the Compose extra_hosts entry
"- \"host.docker.internal:host-gateway\"") so containers can reach the host when
BLENDER_HOST uses host.docker.internal.

uvx blender-mcp without a version pin can pull a different version
than what the repo commit represents. Pin to 1.5.5 to match.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
Dockerfile (1)

13-13: ⚠️ Potential issue | 🟠 Major

Install the CLI during build instead of resolving it in ENTRYPOINT.

uvx is just uv tool run; it executes tools from a temporary environment, and uv’s docs explicitly call out installation as the better fit when a tool should already be available inside a Docker image. Keeping this in ENTRYPOINT leaves first start dependent on package resolution and cache population. (docs.astral.sh)

Possible direction
 RUN pip install --no-cache-dir uv
@@
+ENV PATH="/home/appuser/.local/bin:${PATH}"
 USER appuser
+RUN uv tool install blender-mcp==1.5.5
 
-ENTRYPOINT ["uvx", "blender-mcp==1.5.5"]
+ENTRYPOINT ["blender-mcp"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` at line 13, The ENTRYPOINT currently runs the tool via uvx
("uvx", "blender-mcp==1.5.5") which defers package resolution to container
start; instead install the CLI at image-build time and make the installed binary
the entrypoint. Add a build-step that installs blender-mcp==1.5.5 (for example
via pip install blender-mcp==1.5.5 or the project's recommended install command)
and then change the ENTRYPOINT to the installed executable (replace the "uvx"
ENTRYPOINT with the direct CLI name), ensuring any required PATH or permissions
are set so the executable runs as the container's ENTRYPOINT.
🧹 Nitpick comments (1)
Dockerfile (1)

3-3: Pin uv too if this image is meant to be reproducible.

blender-mcp is pinned, but RUN pip install --no-cache-dir uv still pulls whatever uv release is current at build time. That means rebuilds can drift even when the app version stays fixed. Astral documents version-specific installs and also publishes a dedicated Docker image for uv, so it’s worth pinning the toolchain as well. (docs.astral.sh)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` at line 3, The Dockerfile currently installs uv without a version
in the RUN pip install --no-cache-dir uv step, allowing builds to drift; update
that instruction to pin the uv toolchain (either by specifying an exact pip
package version like uv==<version> or by switching to Astral's published uv base
image/tag) and include the chosen version/tag in the Dockerfile so rebuilds are
reproducible and deterministic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Dockerfile`:
- Line 13: The ENTRYPOINT currently runs the tool via uvx ("uvx",
"blender-mcp==1.5.5") which defers package resolution to container start;
instead install the CLI at image-build time and make the installed binary the
entrypoint. Add a build-step that installs blender-mcp==1.5.5 (for example via
pip install blender-mcp==1.5.5 or the project's recommended install command) and
then change the ENTRYPOINT to the installed executable (replace the "uvx"
ENTRYPOINT with the direct CLI name), ensuring any required PATH or permissions
are set so the executable runs as the container's ENTRYPOINT.

---

Nitpick comments:
In `@Dockerfile`:
- Line 3: The Dockerfile currently installs uv without a version in the RUN pip
install --no-cache-dir uv step, allowing builds to drift; update that
instruction to pin the uv toolchain (either by specifying an exact pip package
version like uv==<version> or by switching to Astral's published uv base
image/tag) and include the chosen version/tag in the Dockerfile so rebuilds are
reproducible and deterministic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b507b72e-b7b0-4085-8176-8f221ef1db85

📥 Commits

Reviewing files that changed from the base of the PR and between f901df5 and 8c86572.

📒 Files selected for processing (1)
  • Dockerfile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant