Skip to main content
Glama

Blender MCP renderer

This image runs a Streamable HTTP MCP server with system Python and launches a separate Blender 5.2 background process for each render. It exposes get_gpu_info and an asynchronous render-job API at http://localhost:8080/mcp.

The image includes cloudflared and runs it alongside the MCP server when CLOUDFLARE_TUNNEL_TOKEN is set. It invokes cloudflared tunnel run --token <token>; without the variable, the MCP server starts normally without a tunnel. In the Cloudflare Zero Trust dashboard, configure the tunnel's public hostname to route to http://localhost:8080 from inside the container. MCP clients connect to the public hostname with the /mcp path. Cloudflare documents this token command syntax in its run parameters and the architecture-matched Debian package download in its cloudflared update instructions.

Cloudflare's Free and Pro plans limit request bodies to 100 MB, while this tool's 100 MiB file limit becomes about 140 MB after base64 encoding and JSON overhead. Business supports 200 MB; Enterprise upload limits can be raised. See Cloudflare's 413 upload limits if you need to send files near the tool's full limit.

Start

CPU-only:

docker compose up --build -d

On an NVIDIA Docker host with the NVIDIA Container Toolkit configured:

docker compose -f compose.yaml -f compose.gpu.yaml up --build -d

The GPU override is optional. Without GPU passthrough, Cycles uses CPU. Eevee and Workbench are reported as unavailable and render requests for them return an error. On a GPU host, the service detects GPUs visible inside the container; Cycles selects OptiX when Blender reports an OptiX device and otherwise falls back to CPU.

To build and publish the RunPod image as gongfan99/blender-render-mcp:latest, first authenticate with Docker Hub using docker login, then run deploy.bat from Windows.

Set MCP_BEARER_TOKEN in the environment before starting Compose to require Authorization: Bearer <token>. When it is unset, the MCP endpoint is open. The local port mapping binds only to 127.0.0.1. For RunPod, provide CLOUDFLARE_TUNNEL_TOKEN as a container environment variable; the same image runs both the MCP server and tunnel connector, so no second image or service is needed.

Related MCP server: blender-2d-mcp

Tools

get_gpu_info reports NVIDIA devices visible through nvidia-smi, Blender's version and OptiX detection, its OpenGL renderer, FFmpeg support, and engine availability. Eevee and Workbench require both a visible NVIDIA GPU and a hardware OpenGL context; software renderers such as llvmpipe do not count.

Rendering uses asynchronous jobs. submit_render_job queues an H.264 animation, while submit_frame_render_job queues selected still frames as PNG files in a ZIP archive. Both return a job ID without waiting for Blender. Use get_render_job_status to poll either job; it returns queued, running, completed, or failed, elapsed and running time, processed and total frame counts, and any error. Download completed animation jobs with download_render_result and frame jobs with download_render_frames.

submit_render_job accepts:

Argument

Type

Behavior

blend_file_base64

string

Base64-encoded .blend file, maximum 100 MiB decoded.

engine

cycles, eevee, workbench or omitted

Omitted preserves the saved scene engine.

frame_start, frame_end

integer or omitted

Omitted preserves saved frame range.

resolution_x, resolution_y

integer or omitted

Omitted preserves saved resolution.

resolution_percentage

integer or omitted

Omitted preserves saved percentage.

samples

integer or omitted

Omitted preserves saved sampling settings.

The submit response includes job_id, status_tool, and download_tool. Check get_render_job_status with that ID until the job finishes. processed_frames and total_frames are available after Blender opens the project and reports its frame range; total_frames can initially be null when the saved range is used. The server runs one Blender render at a time; additional jobs remain queued. Up to four jobs may be queued or running by default.

submit_frame_render_job accepts the same engine, resolution, and sample overrides as submit_render_job, plus a required frames list. The list must contain 1–100 unique integer frame numbers within the scene's saved frame range. The worker renders each requested frame once, preserves the scene's output resolution unless overridden, and returns numbered PNGs (for example, frame_000024.png) in rendered_frames.zip. The ZIP archive is capped at 250 MiB. Use the returned download_tool after status becomes completed to retrieve it as an embedded application/zip resource.

MCP call sequence:

submit_render_job({"blend_file_base64": "...", "engine": "cycles"})
get_render_job_status({"job_id": "<returned id>"})
download_render_result({"job_id": "<returned id>"})

For selected still frames:

submit_frame_render_job({"blend_file_base64": "...", "frames": [1, 24, 48], "engine": "eevee"})
get_render_job_status({"job_id": "<returned id>"})
download_render_frames({"job_id": "<returned id>"})

Animation MP4s use H.264 and are capped at 250 MiB; selected-frame PNG archives are also capped at 250 MiB. A job may render the saved animation frame range, so keep the range and output dimensions reasonable. Pack external textures and other assets into the .blend file before uploading; only the .blend bytes are sent. Blender's automatic Python execution is disabled for uploaded projects.

Jobs and results are held on the server's local filesystem for 24 hours by default. They are process-local and are lost if the container restarts; use one server instance for submit, status polling, and download.

Blender renders use the scene's saved settings except the requested engine/device, output format, and output path. Animation jobs use MPEG-4/H.264; selected-frame jobs save PNG images and package them in a ZIP archive.

Configuration

Variable

Default

Purpose

MCP_BEARER_TOKEN

unset

Optional bearer token; unset means open access.

CLOUDFLARE_TUNNEL_TOKEN

unset

Token for the remotely managed Cloudflare Tunnel; when set, starts cloudflared in this container.

MCP_PORT

8080

HTTP listen port inside the container.

BLENDER_EXECUTABLE

/home/headless/blender/blender

Blender executable path.

MAX_RENDER_SECONDS

1800

Maximum duration of one render process.

MAX_ACTIVE_RENDER_JOBS

4

Maximum queued and running jobs. Completed jobs do not count toward this limit.

JOB_RETENTION_SECONDS

86400

Time completed and failed jobs remain available before cleanup.

JOB_STORAGE_DIR

system temp directory + blender-mcp-jobs

Local directory for uploaded projects, progress, logs, and render results.

The decoded .blend input limit is fixed at 100 MiB; MP4 and PNG ZIP outputs are each limited to 250 MiB, and frame-list jobs accept at most 100 frames. Only one Blender render runs at a time in each container.

Smoke tests

Run the unit tests with Python 3.10 or later after installing requirements.txt:

python -m unittest discover -s tests -v

For a live CPU-only test, create a tiny sample file with Blender in the image, then run the MCP client smoke test. It checks that Eevee and Workbench jobs fail clearly without a GPU and that Cycles returns a valid embedded MP4:

docker run --rm --entrypoint /home/headless/blender/blender \
  -v "$PWD:/workspace" -w /workspace blender-render-mcp:local \
  --background --python tests/create_sample_blend.py -- /workspace/tests/cpu_sample.blend
python tests/smoke_mcp.py --blend tests/cpu_sample.blend --check-cpu-denials --frame 1

On an NVIDIA host, start Compose with compose.gpu.yaml and run the same smoke test with --check-gpu-engines to render through Cycles, Eevee, and Workbench. Add --frame 1 to also verify a selected-frame PNG ZIP render; the requested frame must be within the blend's saved frame range. Add --token "$MCP_BEARER_TOKEN" when the container requires authentication.

Related MCP Connectors

Related MCP Servers