Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 30 additions & 1 deletion MCPForUnity/Editor/Tools/ManageEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,38 @@ public static object HandleCommand(JObject @params)
case "restore_package":
return RestorePackage();

// Undo/Redo
case "undo":
{
string groupName = Undo.GetCurrentGroupName();
Undo.PerformUndo();
Comment on lines +149 to +152
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Undo/redo handlers ignore the boolean return value from Undo.PerformUndo/Redo.

Undo.PerformUndo()/Undo.PerformRedo() return bool to indicate whether an operation actually occurred, but the handlers always report success, even when the stack is empty. Consider using the return value to tailor the message (or surface an error) when nothing was undone/redone so CLI consumers, especially automation, can reliably detect no-op cases.

Suggested implementation:

                // Undo/Redo
                case "undo":
                {
                    string groupName = Undo.GetCurrentGroupName();
                    bool performed = Undo.PerformUndo();

                    string message;
                    if (!performed)
                    {
                        message = "Nothing to undo (undo stack is empty).";
                    }
                    else
                    {
                        message = string.IsNullOrEmpty(groupName)
                            ? "Undo performed."
                            : $"Undid: {groupName}";
                    }

                    if (EditorApplication.isPlaying)
                        message += " Warning: undo during play mode may have unexpected effects.";

                    return new SuccessResponse(message, new
                    {
                        performed,
                        undone_group = (!performed || string.IsNullOrEmpty(groupName)) ? (string)null : groupName,
                        next_group = Undo.GetCurrentGroupName()
                    });
                }
                case "redo":

To fully address your comment for both undo and redo:

  1. Apply an analogous change in the "redo" case:

    • Capture bool performed = Undo.PerformRedo();
    • Tailor the message based on performed (e.g., "Nothing to redo (redo stack is empty)." vs "Redo performed." / $"Redid: {groupName}").
    • Include the performed flag in the response payload and adjust any group-related fields accordingly.
  2. If there are tests or CLI consumers that parse the response, update or add tests to assert on the new performed field and the updated messages for no-op scenarios.

string message = string.IsNullOrEmpty(groupName)
? "Undo performed (stack may be empty)."
: $"Undid: {groupName}";
if (EditorApplication.isPlaying)
message += " Warning: undo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
undone_group = string.IsNullOrEmpty(groupName) ? (string)null : groupName,
next_group = Undo.GetCurrentGroupName()
});
}
case "redo":
{
Undo.PerformRedo();
string nextGroup = Undo.GetCurrentGroupName();
string message = "Redo performed.";
if (EditorApplication.isPlaying)
message += " Warning: redo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
current_group = string.IsNullOrEmpty(nextGroup) ? (string)null : nextGroup
});
Comment on lines +151 to +174
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

undo/redo cases are not wrapped in try/catch like most other actions in this tool. If Unity throws (e.g., during domain reload / invalid editor state), the exception will escape HandleCommand and fail the whole request. Wrap the undo/redo operations in try/catch and return an ErrorResponse on failure, consistent with the rest of the switch cases.

Suggested change
string groupName = Undo.GetCurrentGroupName();
Undo.PerformUndo();
string message = string.IsNullOrEmpty(groupName)
? "Undo performed (stack may be empty)."
: $"Undid: {groupName}";
if (EditorApplication.isPlaying)
message += " Warning: undo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
undone_group = string.IsNullOrEmpty(groupName) ? (string)null : groupName,
next_group = Undo.GetCurrentGroupName()
});
}
case "redo":
{
Undo.PerformRedo();
string nextGroup = Undo.GetCurrentGroupName();
string message = "Redo performed.";
if (EditorApplication.isPlaying)
message += " Warning: redo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
current_group = string.IsNullOrEmpty(nextGroup) ? (string)null : nextGroup
});
try
{
string groupName = Undo.GetCurrentGroupName();
Undo.PerformUndo();
string message = string.IsNullOrEmpty(groupName)
? "Undo performed (stack may be empty)."
: $"Undid: {groupName}";
if (EditorApplication.isPlaying)
message += " Warning: undo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
undone_group = string.IsNullOrEmpty(groupName) ? (string)null : groupName,
next_group = Undo.GetCurrentGroupName()
});
}
catch (Exception ex)
{
return new ErrorResponse($"Failed to perform undo: {ex.Message}");
}
}
case "redo":
{
try
{
Undo.PerformRedo();
string nextGroup = Undo.GetCurrentGroupName();
string message = "Redo performed.";
if (EditorApplication.isPlaying)
message += " Warning: redo during play mode may have unexpected effects.";
return new SuccessResponse(message, new
{
current_group = string.IsNullOrEmpty(nextGroup) ? (string)null : nextGroup
});
}
catch (Exception ex)
{
return new ErrorResponse($"Failed to perform redo: {ex.Message}");
}

Copilot uses AI. Check for mistakes.
}

default:
return new ErrorResponse(
$"Unknown action: '{action}'. Supported actions: play, pause, stop, set_active_tool, add_tag, remove_tag, add_layer, remove_layer, close_prefab_stage, deploy_package, restore_package. Use MCP resources for reading editor state, project info, tags, layers, selection, windows, prefab stage, and active tool."
$"Unknown action: '{action}'. Supported actions: play, pause, stop, set_active_tool, add_tag, remove_tag, add_layer, remove_layer, close_prefab_stage, deploy_package, restore_package, undo, redo. Use MCP resources for reading editor state, project info, tags, layers, selection, windows, prefab stage, and active tool."
);
}
}
Expand Down
Loading