Skip to content
Development
Skill

/blender-to-unity

Hand off a model from Blender (via BlenderMCP) into Unity (via MCP for Unity) — export the current Blender model, import it through import_model_file, and place it in the open scene. Use when the user has BlenderMCP and MCP for Unity both connected and wants to bring a Blender

From plugin
unity-mcp
16k3 skills

Claude Code

$ npx -y skills add CoplayDev/unity-mcp --skill blender-to-unity --agent claude-code

SKILL.md

blender-to-unity.SKILL.md
name: blender-to-unity
description: Hand off a model from Blender (via BlenderMCP) into Unity (via MCP for Unity) — export the current Blender model, import it through import_model_file, and place it in the open scene. Use when the user has BlenderMCP and MCP for Unity both connected and wants to bring a Blender model into Unity. Does NOT drive Blender's own generators; BlenderMCP owns how the model got into Blender.

Blender → Unity Model Handoff

Bring whatever model is currently in Blender into the open Unity scene. The seam is the local filesystem: Blender exports a file, Unity imports it. The two servers never talk directly.

Preconditions

  • Both `mcp__blender__*` tools and MCP for Unity tools are connected.
  • A model exists in the Blender scene (confirm with `mcp__blender__get_scene_info` /

`mcp__blender__get_object_info`). If empty, stop and tell the user — this skill does not generate models.

  • **`import_model_file` is in the `asset_gen` tool group, which is off by default** (only `core`

loads). Enable it first with `manage_tools` (enable the `asset_gen` group), **or** call the C# handler straight through `batch_execute` — `{"tool":"import_model_file","params":{"sourcePath":...,"name":...,"outputFolder":...}}` (camelCase) — which dispatches by name regardless of group gating.

Steps

1. **Resolve the Unity project path.** Read `mcpforunity://editor/state` for the project root (the editor dataPath's parent). Decide the export format:

  • **GLB (glTFast) when the model has a rig, animation, PBR (metallic/roughness), emission,

or transparency** — glTFast carries all of these automatically, no post-processing (see [references/bridge-fidelity.md](references/bridge-fidelity.md)). Multi-material zones survive either format, so they alone don't force GLB.

  • **FBX otherwise** — when glTFast isn't installed, the model is plain geometry, or you

specifically need the built-in importer's humanoid-avatar pipeline. FBX drops emission/metallic (Step 5 restores emission) and surfaces animation only with `animation_type` set (Step 3). 2. **Export from Blender to a temp path** via `mcp__blender__execute_blender_code`:

   import bpy, os, tempfile
   out = os.path.join(tempfile.gettempdir(), "blender_to_unity.fbx")
   # Export the selection if any, else the whole scene:
   bpy.ops.export_scene.fbx(filepath=out, use_selection=bool(bpy.context.selected_objects),
                            apply_unit_scale=True, bake_space_transform=True)
   print(out)

(glTF branch: `out_glb = os.path.join(tempfile.gettempdir(), "blender_to_unity.glb")`, then `bpy.ops.export_scene.gltf(filepath=out_glb, export_format='GLB', use_active_scene=True)` — its default `use_active_scene=False` can silently export a *different* open scene.) 3. **Import into Unity** with `import_model_file`: `import_model_file(source_path=<temp path>, name=<asset name>, target_size=<final size in meters>)`. For a **rigged/animated FBX**, also pass `animation_type="generic"` (or `"humanoid"`; `"legacy"` targets the old Animation-component system) — the importer defaults to `"none"`, which deliberately imports the mesh with **zero animation clips**. GLB ignores this (glTFast imports animation itself), so it's an FBX-only knob. It returns `{ asset_path, asset_guid }`. Pass `target_size` as the intended final size, but treat it only as a hint: it rescales at import solely when the project's **Auto-normalize** pref is on, and even then is unreliable for Blender FBX (see the **Scale** note). Step 4 does the reliable normalization. 4. **Place it in the scene, normalized to size.** Ensure the scene has a camera + directional light (`manage_scene` / `manage_gameobject`). Instantiate the model at the chosen position via `manage_gameobject(action="create", prefab_path=<asset_path>, name=<asset name>, position=[x,y,z])`. Then normalize its size deterministically — Blender FBX commonly imports ~100× too large — by measuring the placed model's world bounds and scaling so its largest dimension equals your target size. Run via `execute_code` (substitute your object name and target meters):

   var go = GameObject.Find("<asset name>");
   var rs = go.GetComponentsInChildren<Renderer>();
   var b = rs[0].bounds; for (int i = 1; i < rs.Length; i++) b.Encapsulate(rs[i].bounds);
   float maxDim = Mathf.Max(b.size.x, Mathf.Max(b.size.y, b.size.z));
   float target = 2f; // intended size in meters
   if (maxDim > 0.0001f) go.transform.localScale *= target / maxDim;

5. **Restore emission FBX dropped (FBX path).** Blender scenes commonly store their color/glow in *material emission* (and other Principled-node inputs). FBX carries base/diffuse color but **not emission**, so neon / "Tron" scenes import as dark bodies with black accents. If the import looks flat vs. Blender, restore it: a. Dump the emissive materials from Blender via `execute_blender_code`:

      import bpy, json
      out = {}
      for m in bpy.data.materials:
          if not (m.use_nodes and m.node_tree): continue
          col, s = (0, 0, 0), 0.0
          p = next((n for n in m.node_tree.nodes if n.type == 'BSDF_PRINCIPLED'), None)
          es = next((k for k in ('Emission Color', 'Emission') if p and k in p.inputs), None)  # 4.x / 3.x name
          if es:
              col = tuple(p.inputs[es].default_value)[:3]
              s = float(p.inputs['Emission Strength'].default_value)
          e = next((n for n in m.node_tree.nodes if n.type == 'EMISSION'), None)
          if e and s == 0:
              col = tuple(e.inputs['Color'].default_value)[:3]; s = float(e.inputs['Strength'].default_value)
          if s > 0 and sum(col) > 0.01:
              out[m.name] = [round(col[0], 3), round(col[1], 3), round(col[2], 3), round(s, 3)]
      print(json.dumps(out))

b. In Unity (`execute_code`): extract the FBX's materials

Read more
@coplaydev
Ships withunity-mcp

Unity MCP acts as a bridge between AI assistants and your Unity Editor. Give your LLM tools to manage assets, control scenes, edit scripts, and automate tasks within Unity.

Stars on GitHub

Momentum

stars in total
15.8k
Star history of CoplayDev/unity-mcp on GitHub, a chart by star-history.com

Other skills on unity-mcp.

mcp-source

mcp-source

Switch MCP for Unity package source in connected Unity projects. Use /mcp-source [main|beta|branch|local] to swap between…

@coplaydev@coplaydevInstall Skill
unity-mcp-skill

unity-mcp-skill

Orchestrate Unity Editor via MCP (Model Context Protocol) tools and resources. Use when working with Unity projects through MCP…

@coplaydev@coplaydevInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about blender-to-unity.

Which coding agents can use blender-to-unity?
blender-to-unity installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.