An MCP server and a companion Blockbench plugin that let Claude control Blockbench.
With it, Claude builds models, unwraps UVs, paints textures, adds bones and animations, checks the result with screenshots, and exports the model to any format Blockbench supports. Besides Minecraft-style cube models, it can make low-poly, hand-painted characters. It can also turn a model into pixel art sprites for 2D games.
Every change goes into Blockbench's undo history. Press Ctrl+Z to revert any step you don't like.
| Version | 1.8.0 · Changelog |
| Blockbench | 5.2 or later recommended. 5.1.4 also works, but 5.2-only tools return a "requires 5.2" error there. |
| Client | Claude Desktop and Claude Code. Developed on Windows. |
| Node.js | 18 or later |
| Tools | 69 |
If you use version 1.6.0 or older, update. In older versions, while Blockbench and the MCP server were running, any website open in your browser could connect to the bridge and run code on your computer. 1.6.1 closes this. Details: Security.
| Area | Coverage |
|---|---|
| Modeling | Cubes, meshes, planes, locators, bounding boxes. Groups act as bones in animations. mirror and mirror_elements for symmetric parts. Mesh primitives: plane, pyramid, cylinder, cone, sphere, torus, icosphere, octahedron, dodecahedron. |
| Low-poly | Limbs and tubes from cross-sections (add_loft). Extrude, inset, loop cut, bevel, solidify, subdivide (edit_mesh). Taper, bend, twist, smooth (transform_mesh). |
| Texturing | Template generation, layers and layer groups, gradients, noise, fur strands (strands), jagged edges (jagged_edge), painting on cube and mesh faces. Light, AO and edge baking (bake_texture). Hue-shifted color ramps and palette locking (palette). |
| UV | Mesh unwrapping with islands, seams and per-part density (unwrap_mesh). Cube UV, auto UV, UV diagnostics (uv action inspect). |
| Animation | Keyframes (with Molang expressions), mirrored keyframes, 20 motion presets, effect keyframes, IK with poles, baking IK into plain keyframes. |
| Checking | Screenshots, multi-view captures, animation previews, intersection and ground-contact checks during animation, build timelapse GIF (record_build). |
| Reference | Silhouette comparison against a reference image (compare_reference), projecting a reference onto the texture (project_reference), reference models and 3D reference images in the scene. |
| Export | bbmodel, Bedrock geo.json, Java block, glTF/GLB, OBJ, FBX, DAE, STL, OptiFine JEM, animation JSON. |
| Pixel art | Single frames, 4/8/16-direction sets, sprite sheets with Aseprite JSON. |
5.2 also unlocks: texture layer groups, IK with poles, movable reference models in the scene,
reference images shown as 3D panels, Java 26.3 shade_direction_override, the cushion skin template,
Molang variable_placeholders, bounding boxes, the embedded and on_shelf display slots, and glTF
merge_armature. The features field in the get_status output shows which of these your Blockbench
has.
- Download
blockbench_mcp.jsandmcp-server.jsfrom the latest release. Both are also available as a zip. Nonpm installneeded: the server is bundled with its dependencies. - Put both files in a permanent folder. Blockbench loads the plugin from this path; if you move the folder, you have to load the plugin again.
- Install the plugin in Blockbench and register the server with Claude.
git clone https://github.com/RenasDemirbas/BlockBenchMCP.git
cd BlockBenchMCP
npm install
npm run buildThe build creates two files in dist/:
blockbench_mcp.js: the Blockbench pluginmcp-server.js: the MCP server (reads its dependencies fromnode_modules)
For a single-file server with dependencies bundled in, run npm run build:release.
- Open Blockbench and go to File → Plugins.
- In the top-right menu, choose Load Plugin from File.
- Select
blockbench_mcp.jsand accept the security prompt.
Claude Code:
claude mcp add --scope user blockbench -- node /path/to/mcp-server.jsClaude Desktop: add this to the mcpServers section of %APPDATA%\Claude\claude_desktop_config.json:
"blockbench": {
"command": "node",
"args": ["C:\\path\\to\\mcp-server.js"],
"env": { "BB_BRIDGE_PORT": "8188" }
}Then fully quit Claude Desktop from the system tray and reopen it.
Both can run at the same time. The first server to take the port becomes the bridge; the others relay their commands through it.
With Blockbench open, ask Claude to "check the Blockbench status". get_status should return a
connected Blockbench version. If it doesn't, see Troubleshooting.
- Overwrite
blockbench_mcp.jsandmcp-server.jswith the new files (orgit pullandnpm run build). - Restart Blockbench.
- Restart Claude Desktop or your Claude Code session. The running server stays on the old version.
plugin_version in the get_status output should show the new version.
Building the model step by step works better than asking for everything at once. Checking a screenshot after each step and asking for fixes is less work than fixing everything at the end.
- Project and skeleton. Pick a format (
create_project), then build the bone tree (add_groups), for examplebody > head,body > leg_fl. Animations apply to these groups, so don't skip this step. - Geometry. Place cubes inside the groups (
add_cubes). Usemirror: truefor symmetric legs and arms. Useadd_planesfor thin parts like fur or leaves. - Check. Look from the front, side and top with
capture_multi_view. Fix proportions here; changing geometry after painting breaks the UVs. - Texture. First
generate_texture_template, thenpaint_texture/paint_faces. Without the template, many faces share one UV area and painting one repaints the others. - Animation.
create_animation,set_keyframes, andmirror_keyframesfor left-right pairs. Then usevalidate_modelto check for parts intersecting during the animation, andquery_geometryto check that the feet touch the ground. - Export.
project_fileactionsexportandexport_animations. For 2D games,pixel_artactionexport_sheet.
Example request:
Make a wolf model in the Bedrock entity format. First build only the skeleton and the shape with gray cubes, and show me three views. If I approve, move on to the texture and a walk animation.
Recommended order for PS1-style characters with hand-painted textures, in the free format:
- Reference. Compare against the reference image from the same angle with
compare_reference. The tool reports silhouette similarity (IoU) and, for each height band, how much wider or narrower the model is, in units. - Blockout. Use
add_loftfor arms, legs, trousers and torso: give the center and size of each ring and you get a tapering, bending box limb. Use anadd_mesh_primitivecylinder for a hat brim, and a plane +edit_meshsolidify for a cape. - Shaping. Taper/bend/twist with
transform_mesh, extrude/inset/loop cut withedit_mesh. Steps chain withselect: "previous", so extrude → inset → extrude happens in one call. Soften boxy parts withbevel. Runcompare_referenceagain after each step. - UV.
unwrap_mesh {pixel_density: 32-64, density_scale: {"head": 2}}. Limbs unwrap as single strip islands. Pixels painted earlier are carried over to the new layout. - Flat colors. Pick color ramps with
palette {action: "ramp"}and fill flat colors withpaint_faces. On meshes,faces: ["up"]selects the upward-facing faces. Optionally, project the reference onto the texture withproject_referenceas a starting point. - Bake.
bake_texture {layer: "shading"}paints light, AO and edge highlights as hue-shifted pixel-art steps. It writes to its own layer, so baking again doesn't stack shadows. - Cleanup. Lock stray colors to the palette with
palette {action: "quantize"}. - Recording. Call
record_build {action: "start"}at the beginning and every edit becomes a frame.stopat the end writes a part-by-part build GIF.
A ready-made example runs this whole workflow. It builds a four-armed, gas-masked gunslinger and records the build as a GIF. It works in a new tab and doesn't touch your open model:
OUT=C:/output/folder node scripts/examples/build-gunslinger.mjs- 1 unit = 1/16 block. Y is up; the ground is y=0.
- +X is east, -Z is north. Entities are modeled facing north (-Z); the
northcamera preset shows the front. - Rotations are in degrees, order ZYX. +X swings a hanging limb forward.
| Area | Tools |
|---|---|
| Project | get_status, list_formats, create_project, get_project_info, set_project_settings, project_file (open, save, export, export_animations, import, get_json, switch_tab, close) |
| Geometry | add_groups, add_cubes, add_meshes, add_mesh_primitive, add_loft, edit_mesh, transform_mesh, add_planes, add_locators, add_bounding_boxes, list_outline, get_element, update_elements, delete_elements, duplicate_elements, mirror_elements, select_elements |
| Texture | create_texture, generate_texture_template, list_textures, get_texture, import_texture, apply_texture, paint_texture, paint_faces, bake_texture, palette, texture_layers, resize_texture, set_texture_resolution, delete_texture |
| UV | unwrap_mesh, uv (inspect, set_cube, set_mesh, auto) |
| Animation | create_animation, list_animations, get_animation, update_animation, delete_animation, set_keyframes, edit_keyframes, mirror_keyframes, add_effect_keyframes, apply_animation_preset, variable_placeholders, preview_animation, render_animation |
| IK | add_ik_controllers, bake_ik_animation |
| Checking | validate_model, query_geometry, capture_screenshot, capture_multi_view, record_build |
| Reference | compare_reference, project_reference |
| Scene | preview_models, reference_images |
| Pixel art | pixel_art (render, export_sheet, presets) |
| Display | display_transforms (get, set) |
| Other | run_action, eval_code, undo, redo |
Each tool's parameters are described in its MCP schema. Claude reads them on its own.
target: {element: "leg_fl", faces: "all"}paints every cube in a group in one operation. Useelement: "*"for the whole model.- Give gradients
space: "world". Without it, the gradient restarts on every cube and multi-part limbs look banded. Usestopsfor multi-stop gradients. - Painting shadows on a separate layer (
layer) set tomultiplyat 50% opacity makes them easy to adjust later. - Use
jagged_edgefor fur silhouettes andstrandsfor fur texture. - If the texture looks right as an image but wrong on the model, run
uvactioninspectfirst. To see a single face up close,get_texturecrops and enlarges that face's UV region. - If the model looks washed out or shows a grid, the cause is usually not the texture. Check
Blockbench's
brightnessandpixel_gridsettings.
- Keyframe values can be Molang:
"math.sin(query.anim_time*360)*15". - Times snap to the animation's FPS grid (default 24). Use
snap: falsewhen you need the exact value. Useedit_keyframesto retime or delete keyframes later. - If a bone has a rest rotation, keyframe values are added on top of it; they are not absolute angles.
- For quick motion,
apply_animation_preset: float, flap, swing, sway, shake, jump, flicker and more. - Before exporting animations that use IK to Bedrock or Java, convert them to plain rotation keyframes
with
bake_ik_animation.
pixel_art action render doesn't produce a downscaled screenshot; it draws the model by pixel art rules.
Scale snaps to texture pixels, there is no anti-aliasing, shading uses a limited number of color
bands, and a 1 px outline is drawn around the silhouette and where parts meet.
- Views:
side,front,back,top,three_quarter,top_down,isometric(2:1),true_isometric. Useyaw/pitchfor a free angle. - Directions:
directions: 8produces an eight-direction set. On symmetric models,mirror_directions: truecuts render time. - Style:
outlined(default),clean,minecraft,flat. - Palette: the model's own colors by default. Fixed palettes like
pico8,sweetie16,endesga32,db32, or your own hex list also work. Optional Bayer dithering. - Sprite sheet:
pixel_artactionexport_sheetwrites animations as a single PNG plus an Aseprite-compatible JSON. Scale and pivot are computed once for all frames, so frames don't drift.
Ask Claude for the pixel_art action presets output to see every option.
Saving and exporting need absolute paths. get_status returns the home, desktop and temp folders;
get_project_info returns the last-used folder for each file type. Claude builds paths from these.
Claude ──stdio──► MCP server (mcp-server.js)
│ ws://127.0.0.1:8188
▼
Blockbench plugin (blockbench_mcp.js)
The WebSocket server runs on the MCP side and the plugin connects to it, so Blockbench doesn't ask for network permissions. If Blockbench closes, the server keeps running. When Blockbench reopens, the plugin reconnects on its own within a few seconds.
Browser engines slow down timers while a window is in the background. The plugin works around this, so long operations keep running while Blockbench is minimized.
The default port is 8188. To change it, set both the BB_BRIDGE_PORT environment variable and
Settings → General → MCP Bridge Port in Blockbench to the same value.
Another Blockbench plugin can add its own tools. Claude sees them next to the built-in ones as soon as
they are registered, with no server restart. Register through window.BlockbenchMCP and listen for
blockbench_mcp_ready. The event covers a plugin that loads before this one, and re-adds the tool
when the bridge plugin reloads.
let tool;
function addTools() {
tool = BlockbenchMCP.registerTool({
name: 'count_cubes',
title: 'Count cubes',
description: 'Count the cubes in the open project, optionally only those whose name contains a filter.',
inputSchema: { type: 'object', properties: { filter: { type: 'string' } } }, // JSON Schema
annotations: { readOnlyHint: true },
}, ({ filter }) => ({ count: Cube.all.filter((c) => !filter || c.name.includes(filter)).length }));
}
Plugin.register('my_plugin', {
onload() {
if (window.BlockbenchMCP) addTools();
window.addEventListener('blockbench_mcp_ready', addTools);
},
onunload() {
tool?.delete();
window.removeEventListener('blockbench_mcp_ready', addTools);
},
});name: 1–64 characters ofA-Z a-z 0-9 _ - .. A name a built-in or another plugin already uses is refused.descriptionis required. It is all Claude reads to decide when to call the tool.inputSchemais optional and must havetype: "object". The server does not check arguments against it; the handler should.- The handler may be
async. A returned string is sent as text, anything else as JSON. To send images, put a PNG data URL in__image(or an array of them in__images) on the returned object. A thrown error comes back as the tool's error message. Calls time out after 120 seconds. registerToolreturns an object withdelete(), which removes the tool again.
- The bridge listens only on this computer (
127.0.0.1). Other devices on the network can't connect. - Websites can't connect to the bridge (1.6.1). The server accepts only connections without an
Origin header (Node) and the Blockbench window (
file://), and refuses everything else during the handshake. Programs running on your computer can still connect; they already run with your permissions, so this adds no extra risk. eval_codecan't freeze Blockbench. Node modules that open a permission dialog (fs,child_processand similar) are refused before the code runs.allow_native_modules: trueopts out; the Blockbench window must then be in the foreground.- Every change can be undone. Tools write to Blockbench's undo history.
- A
.bbmodelfile you share may contain local paths. Blockbench saves the full path of the animation file, which can include your username. Check the file before sharing it.
npm run build # plugin and server
npm run build:release # single-file server with bundled dependencies (for releases)
npm run typecheckYou don't need to restart Blockbench after changing the plugin:
node scripts/call-tool.mjs eval_code '{"code":"setTimeout(() => Plugins.devReload(), 300); \"ok\"","undo":false}'An open Claude session fixes its tool list when the server starts. To try a new tool without restarting the session:
node scripts/call-tool.mjs pixel_art '{"action":"render","view":"isometric","size":64}' --images e2e-output/tmp| Script | What it tests | Needs |
|---|---|---|
smoke-test.mjs |
MCP protocol and bridge, with a fake plugin | Nothing |
verify-bridge-origin.mjs |
The bridge refuses connections from websites | Nothing |
verify-plugin-api.mjs |
Tools added by other plugins: listing, calls, relay instances, removal, re-adding after a reload. Moves the plugin to port 8191 during the test and back afterwards | Open Blockbench |
e2e-test.mjs |
Full modeling scenario | Open Blockbench |
e2e-pro-test.mjs |
Validation, queries, mirroring, painting | Open Blockbench |
verify-paint-ops.mjs |
Paint operations | Open Blockbench |
verify-field-fixes.mjs |
1.3 fixes | An open project |
verify-v52-features.mjs |
Blockbench 5.2 features | Blockbench 5.2 |
verify-pixel-art.mjs |
Pixel art output (PNG and JSON) | Open Blockbench |
verify-lowpoly-tools.mjs |
Mesh painting, unwrap, edit/loft/transform, bake, palette, reference, recording. Pick sections with node scripts/verify-lowpoly-tools.mjs paint,bake |
Open Blockbench, REF_DIR for the reference tests |
verify-hidden-window-timers.mjs |
Timers while the window is in the background | Minimized Blockbench |
Run any of them with node scripts/<name>.
- "Blockbench is not connected"
- Is Blockbench running?
- Is the plugin installed and enabled under File → Plugins?
- Is the port the same on both sides? (Default 8188.)
- I updated but the old behavior remains. Restart the Claude session. The running server process keeps using the old file.
- Long operations time out while the window is in the background.
timers.unthrottledin theget_statusoutput should betrue. If it'sfalse, bring the Blockbench window to the front. - Logs
- Claude Desktop:
%APPDATA%\Claude\logs\mcp-server-blockbench.log - Blockbench:
Ctrl+Shift+I→ Console →[MCP]lines
- Claude Desktop: