Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f2a5b7b
chore: sync main (v9.6.0) into beta
actions-user Mar 16, 2026
cd719cb
chore: set beta version to 9.6.1-beta.1 after release v9.6.0
actions-user Mar 16, 2026
ec25df8
Merge pull request #944 from CoplayDev/sync/main-v9.6.0-into-beta-231…
github-actions[bot] Mar 16, 2026
1a13390
docs: add manage_build design spec
Scriptwonder Mar 21, 2026
841a0bb
docs: add manage_build implementation plan
Scriptwonder Mar 21, 2026
fe5a53f
fix: address review issues in manage_build plan
Scriptwonder Mar 21, 2026
df8ecff
feat: add max_poll_seconds to polling pipeline for long-running tools
Scriptwonder Mar 21, 2026
ab26f91
Initial upload
Scriptwonder Mar 22, 2026
57a43b6
Polling fix
Scriptwonder Mar 22, 2026
2695103
Doc update
Scriptwonder Mar 22, 2026
222a3c4
Update via AI feedback
Scriptwonder Mar 22, 2026
f9f2ad2
update
Scriptwonder Mar 22, 2026
dadd15b
Merge pull request #957 from Scriptwonder/manage_build
Scriptwonder Mar 22, 2026
71d2952
chore: update Unity package to beta version 9.6.1-beta.2
actions-user Mar 22, 2026
3d33fba
Merge pull request #959 from CoplayDev/beta-version-9.6.1-beta.2-2340…
github-actions[bot] Mar 22, 2026
5a46319
Update
Scriptwonder Mar 23, 2026
475e5b2
Restore original ref on incompatible assignments
Scriptwonder Mar 23, 2026
e38faf3
Merge pull request #960 from Scriptwonder/fix/949-950-953-object-ref-…
Scriptwonder Mar 23, 2026
0428299
chore: update Unity package to beta version 9.6.1-beta.3
actions-user Mar 23, 2026
1000228
Merge pull request #961 from CoplayDev/beta-version-9.6.1-beta.3-2341…
github-actions[bot] Mar 23, 2026
eb16769
Initial commit on QoL patch
Scriptwonder Mar 23, 2026
6a2e601
Update with building moved to manage_build
Scriptwonder Mar 23, 2026
963b517
Update
Scriptwonder Mar 23, 2026
0e64a51
Doc update and duplicate check for LoadSceneAdditive
Scriptwonder Mar 23, 2026
66b1305
Merge pull request #964 from Scriptwonder/QoL-fresh
Scriptwonder Mar 23, 2026
60c923b
chore: update Unity package to beta version 9.6.1-beta.4
actions-user Mar 23, 2026
8accc74
Merge pull request #967 from CoplayDev/beta-version-9.6.1-beta.4-2345…
github-actions[bot] Mar 23, 2026
91af9cc
chore: bump version to 9.6.2
actions-user Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude/skills/unity-mcp-skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ uri="file:///full/path/to/file.cs"

| Category | Key Tools | Use For |
|----------|-----------|---------|
| **Scene** | `manage_scene`, `find_gameobjects` | Scene operations, finding objects |
| **Scene** | `manage_scene`, `find_gameobjects` | Scene operations, finding objects. Multi-scene editing (additive load, close, set active, move GO between scenes), scene templates (`3d_basic`, `2d_basic`, `empty`, `default`), scene validation with `auto_repair`. For build settings, use `manage_build(action="scenes")`. |
| **Objects** | `manage_gameobject`, `manage_components` | Creating/modifying GameObjects |
| **Scripts** | `create_script`, `script_apply_edits`, `validate_script` | C# code management (auto-refreshes on create/edit) |
| **Assets** | `manage_asset`, `manage_prefabs` | Asset operations. **Prefab instantiation** is done via `manage_gameobject(action="create", prefab_path="...")`, not `manage_prefabs`. |
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control, package deployment (`deploy_package`/`restore_package` actions) |
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control, package deployment (`deploy_package`/`restore_package`), undo/redo (`undo`/`redo` actions) |
| **Testing** | `run_tests`, `get_test_job` | Unity Test Framework |
| **Batch** | `batch_execute` | Parallel/bulk operations |
| **Camera** | `manage_camera` | Camera management (Unity Camera + Cinemachine). **Tier 1** (always available): create, target, lens, priority, list, screenshot. **Tier 2** (requires `com.unity.cinemachine`): brain, body/aim/noise pipeline, extensions, blending, force/release. 7 presets: follow, third_person, freelook, dolly, static, top_down, side_scroller. Resource: `mcpforunity://scene/cameras`. Use `ping` to check Cinemachine availability. See [tools-reference.md](references/tools-reference.md#camera-tools). |
Expand Down
49 changes: 48 additions & 1 deletion .claude/skills/unity-mcp-skill/references/tools-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,26 @@ manage_scene(action="get_build_settings") # Build settings
manage_scene(action="create", name="NewScene", path="Assets/Scenes/")
manage_scene(action="load", path="Assets/Scenes/Main.unity")
manage_scene(action="save")

# Scene templates — create with preset objects
manage_scene(action="create", name="Level1", template="3d_basic") # Camera + Light + Ground
manage_scene(action="create", name="Level2", template="2d_basic") # Camera (ortho) + Light
manage_scene(action="create", name="Empty", template="empty") # No default objects
manage_scene(action="create", name="Default", template="default") # Camera + Light (Unity default)

# Multi-scene editing
manage_scene(action="load", path="Assets/Scenes/Level2.unity", additive=True) # Keep current scene
manage_scene(action="get_loaded_scenes") # List all loaded scenes
manage_scene(action="set_active_scene", scene_name="Level2") # Set active scene
manage_scene(action="close_scene", scene_name="Level2") # Unload scene
manage_scene(action="close_scene", scene_name="Level2", remove_scene=True) # Fully remove
manage_scene(action="move_to_scene", target="Player", scene_name="Level2") # Move root GO

# Build settings — use manage_build(action="scenes") instead

# Scene validation
manage_scene(action="validate") # Detect missing scripts, broken prefabs
manage_scene(action="validate", auto_repair=True) # Also auto-fix missing scripts (undoable)
```

### find_gameobjects
Expand Down Expand Up @@ -332,6 +352,11 @@ manage_components(
# - "Assets/Prefabs/My.prefab" → String shorthand for asset paths
# - "ObjectName" → String shorthand for scene name lookup
# - 12345 → Integer shorthand for instanceID
#
# Sprite sub-asset references (for SpriteRenderer.sprite, Image.sprite, etc.):
# - {"guid": "...", "spriteName": "SubSprite"} → Sprite sub-asset from atlas
# - {"guid": "...", "fileID": 12345} → Sub-asset by fileID
# Single-sprite textures auto-resolve from guid/path alone.
```

---
Expand Down Expand Up @@ -523,6 +548,24 @@ manage_prefabs(
position=[0, 1, 0],
components_to_add=["AudioSource"]
)

# Add child GameObjects to a prefab (single or batch)
manage_prefabs(
action="modify_contents",
prefab_path="Assets/Prefabs/Player.prefab",
create_child=[
{"name": "Child1", "primitive_type": "Sphere", "position": [1, 0, 0]},
{"name": "Child2", "primitive_type": "Cube", "parent": "Child1"}
]
)

# Add a nested prefab instance inside a prefab
manage_prefabs(
action="modify_contents",
prefab_path="Assets/Prefabs/Player.prefab",
create_child={"name": "Bullet", "source_prefab_path": "Assets/Prefabs/Bullet.prefab", "position": [0, 2, 0]}
)
# source_prefab_path and primitive_type are mutually exclusive
```

---
Expand Down Expand Up @@ -691,7 +734,7 @@ manage_ui(

### manage_editor

Control Unity Editor state.
Control Unity Editor state, undo/redo.

```python
manage_editor(action="play") # Enter play mode
Expand All @@ -708,6 +751,10 @@ manage_editor(action="remove_layer", layer_name="OldLayer")

manage_editor(action="close_prefab_stage") # Exit prefab editing mode back to main scene

# Undo/Redo — returns the affected undo group name
manage_editor(action="undo") # Undo last action
manage_editor(action="redo") # Redo last undone action

# Package deployment (no confirmation dialog — designed for LLM-driven iteration)
manage_editor(action="deploy_package") # Copy configured MCPForUnity source into installed package
manage_editor(action="restore_package") # Revert to pre-deployment backup
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
__pycache__/
__pycache__.meta
build/
!MCPForUnity/**/Build/
dist/
wheels/
*.egg-info
Expand Down
54 changes: 51 additions & 3 deletions MCPForUnity/Editor/Helpers/ComponentOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ private static bool SetSerializedPropertyRecursive(SerializedProperty prop, JTok
}
}

private static bool SetObjectReference(SerializedProperty prop, JToken value, out string error)
internal static bool SetObjectReference(SerializedProperty prop, JToken value, out string error)
{
error = null;

Expand Down Expand Up @@ -647,12 +647,18 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou
{
string spriteName = spriteNameToken.ToString();
var allAssets = AssetDatabase.LoadAllAssetsAtPath(path);
var originalRef = prop.objectReferenceValue;
foreach (var asset in allAssets)
{
if (asset is Sprite sprite && sprite.name == spriteName)
{
prop.objectReferenceValue = sprite;
return true;
if (prop.objectReferenceValue != null)
return true;
// Unity rejected the type — restore and report
prop.objectReferenceValue = originalRef;
error = $"Sprite '{spriteName}' found but is not compatible with the property type.";
return false;
}
}

Expand All @@ -667,6 +673,7 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou
if (targetFileId != 0)
{
var allAssets = AssetDatabase.LoadAllAssetsAtPath(path);
var originalRef = prop.objectReferenceValue;
foreach (var asset in allAssets)
{
if (asset is Sprite sprite)
Expand All @@ -675,7 +682,11 @@ private static bool SetObjectReference(SerializedProperty prop, JToken value, ou
if (spriteFileId == targetFileId)
{
prop.objectReferenceValue = sprite;
return true;
if (prop.objectReferenceValue != null)
return true;
prop.objectReferenceValue = originalRef;
error = $"Sprite with fileID '{targetFileId}' found but is not compatible with the property type.";
return false;
}
}
}
Expand Down Expand Up @@ -785,6 +796,43 @@ private static bool AssignObjectReference(SerializedProperty prop, UnityEngine.O
if (prop.objectReferenceValue != null)
return true;

// Sub-asset fallback: e.g., Texture2D → Sprite
string subAssetPath = AssetDatabase.GetAssetPath(resolved);
if (!string.IsNullOrEmpty(subAssetPath))
{
var subAssets = AssetDatabase.LoadAllAssetsAtPath(subAssetPath);
UnityEngine.Object match = null;
int matchCount = 0;
foreach (var sub in subAssets)
{
if (sub == null || sub == resolved) continue;
prop.objectReferenceValue = sub;
if (prop.objectReferenceValue != null)
{
match = sub;
matchCount++;
if (matchCount > 1) break;
}
}

if (matchCount == 1)
{
prop.objectReferenceValue = match;
return true;
}

// Clean up: probing may have left the property dirty
prop.objectReferenceValue = null;

if (matchCount > 1)
{
error = $"Multiple compatible sub-assets found in '{subAssetPath}'. " +
"Use {\"guid\": \"...\", \"spriteName\": \"<name>\"} or " +
"{\"guid\": \"...\", \"fileID\": <id>} for precise selection.";
return false;
}
}

// If the resolved object is a GameObject but the property expects a Component,
// try each component on the GameObject until one is accepted.
if (resolved is GameObject go)
Expand Down
1 change: 1 addition & 0 deletions MCPForUnity/Editor/Services/IToolDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ToolMetadata
public bool AutoRegister { get; set; } = true;
public bool RequiresPolling { get; set; } = false;
public string PollAction { get; set; } = "status";
public int MaxPollSeconds { get; set; } = 0;
public bool IsBuiltIn { get; set; }
public string Group { get; set; } = "core";
}
Expand Down
1 change: 1 addition & 0 deletions MCPForUnity/Editor/Services/ToolDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ private ToolMetadata ExtractToolMetadata(Type type, McpForUnityToolAttribute too
AutoRegister = toolAttr.AutoRegister,
RequiresPolling = toolAttr.RequiresPolling,
PollAction = string.IsNullOrEmpty(toolAttr.PollAction) ? "status" : toolAttr.PollAction,
MaxPollSeconds = toolAttr.MaxPollSeconds,
Group = toolAttr.Group ?? "core"
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ private async Task SendRegisterToolsAsync(CancellationToken token)
["structured_output"] = tool.StructuredOutput,
["requires_polling"] = tool.RequiresPolling,
["poll_action"] = tool.PollAction,
["max_poll_seconds"] = tool.MaxPollSeconds,
["group"] = string.IsNullOrWhiteSpace(tool.Group) ? "core" : tool.Group
};

Expand Down
8 changes: 8 additions & 0 deletions MCPForUnity/Editor/Tools/Build.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading