From unity-mcp-server
Guides Unity C# development with architecture patterns: fail-fast no-nulls, cached GetComponents, UniTask async, VContainer DI. For general Unity tasks, C# editing, scenes, UI, assets, PlayMode testing.
npx claudepluginhub akiojin/unity-mcp-server --plugin unity-mcp-serverThis skill is limited to using the following tools:
A comprehensive guide for Unity development. This skill serves as **always-referenced parent skill**, providing common patterns and tool selection guidance.
Develops Unity games and interactive experiences using C#, MonoBehaviours, ScriptableObjects, prefabs, DOTS/ECS, Burst, Jobs, Addressables, and optimization patterns across mobile, PC, console, VR/AR.
Builds optimized Unity games with C# scripts, URP/HDRP rendering, asset management, gameplay systems, UI, and cross-platform deployment. For performance issues, mechanics, builds.
Creates and bootstraps Unity scenes using unity-cli. Use for new scene creation, loading/saving scenes, adding starter GameObjects, and attaching components during level or test setup.
Share bugs, ideas, or general feedback.
A comprehensive guide for Unity development. This skill serves as always-referenced parent skill, providing common patterns and tool selection guidance.
Do not write null checks. Use objects directly when their existence is assumed.
// NG: Forbidden pattern
if (component != null) { component.DoSomething(); }
if (gameObject != null) { gameObject.SetActive(false); }
if (service != null) { service.Execute(); }
// OK: Correct pattern - direct usage
GetComponent<Rigidbody>().velocity = Vector3.zero;
GameService.Initialize();
target.position = Vector3.zero;
Applies to:
GetComponent<T>()Find*()[Inject]GetComponent every frame causes GC allocation and performance degradation. Cache in Awake.
// NG: GC allocation every frame
void Update()
{
GetComponent<Rigidbody>().velocity = input;
}
// OK: Cache in Awake
private Rigidbody _rb;
void Awake()
{
_rb = GetComponent<Rigidbody>();
}
void Update()
{
_rb.velocity = input;
}
Use UniTask instead of coroutines. async void is forbidden.
using Cysharp.Threading.Tasks;
// NG: async void
async void Start()
{
await DoWorkAsync();
}
// OK: UniTaskVoid + destroyCancellationToken
async UniTaskVoid Start()
{
await DoWorkAsync(destroyCancellationToken);
}
// OK: When return value is needed
async UniTask<int> CalculateAsync(CancellationToken ct)
{
await UniTask.Delay(1000, cancellationToken: ct);
return 42;
}
Best Practices:
destroyCancellationToken for auto-cancel on GameObject destructionUniTask.Delay > Task.Delay (zero allocation)UniTask.WhenAll for parallel executionUse VContainer for dependency injection. Constructor injection recommended.
// Interface definition
public interface IPlayerService
{
void Initialize();
}
// Implementation class
public class PlayerService : IPlayerService
{
public void Initialize() { /* ... */ }
}
// Consumer (MonoBehaviour)
public class GameManager : MonoBehaviour
{
[Inject] private readonly IPlayerService _playerService;
void Start()
{
_playerService.Initialize();
}
}
// LifetimeScope configuration
public class GameLifetimeScope : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
builder.Register<IPlayerService, PlayerService>(Lifetime.Singleton);
builder.RegisterComponentInHierarchy<GameManager>();
}
}
Lifetime Selection:
Lifetime.Singleton - One instance for entire appLifetime.Scoped - One instance per sceneLifetime.Transient - New instance each time| Tool | Purpose | Usage Condition |
|---|---|---|
edit_snippet | Lightweight edit | Diff within 80 characters |
edit_structured | Structured edit | Method body replacement, member addition |
get_symbols | Symbol list | Required before editing |
find_symbol | Symbol search | Find symbol by name |
find_refs | Reference search | Before refactoring |
read | Read code | Check file contents |
search | Pattern search | Regex search |
create_class | Create class | New file |
rename_symbol | Rename | Project-wide |
remove_symbol | Remove symbol | Delete unused code |
| Tool | Purpose |
|---|---|
get_hierarchy | Get hierarchy |
create_gameobject | Create GameObject |
modify_gameobject | Modify GameObject |
delete_gameobject | Delete GameObject |
find_gameobject | Find GameObject |
add_component | Add component |
modify_component | Modify component |
remove_component | Remove component |
list_components | List components |
| Tool | Purpose |
|---|---|
create_prefab | Create prefab |
modify_prefab | Modify prefab |
instantiate_prefab | Instantiate prefab |
create_material | Create material |
modify_material | Modify material |
manage_asset_database | Asset operations |
addressables_manage | Addressables management |
| Tool | Purpose |
|---|---|
play_game | Start PlayMode |
stop_game | Stop PlayMode |
pause_game | Pause |
input_keyboard | Keyboard input |
input_mouse | Mouse input |
input_gamepad | Gamepad input |
capture_screenshot | Screenshot |
run_tests | Run tests |
| System | Purpose | Detail Skill |
|---|---|---|
| uGUI | Game UI (Canvas/EventSystem) | unity-game-ugui-design |
| UI Toolkit | Modern UI (Runtime/Editor) | unity-game-ui-toolkit-design |
| IMGUI | Editor extensions only | unity-editor-imgui-design |
Required operations: UI creation + Scene management + C# script
// 1. Create button GameObject
mcp__unity-mcp-server__create_gameobject({
name: "StartButton",
parentPath: "/Canvas"
})
// 2. Add Button component
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/StartButton",
componentType: "Button"
})
// 3. Create click handler script
mcp__unity-mcp-server__create_class({
path: "Assets/Scripts/UI/StartButtonHandler.cs",
className: "StartButtonHandler",
baseType: "MonoBehaviour",
namespace: "Game.UI"
})
// 4. Add OnClick implementation
mcp__unity-mcp-server__edit_structured({
path: "Assets/Scripts/UI/StartButtonHandler.cs",
symbolName: "StartButtonHandler",
operation: "insert_after",
newText: `
public void OnStartClicked()
{
SceneManager.LoadScene("GameScene");
}
`
})
Required operations: GameObject + Components + C# script + Prefab
// 1. Create enemy GameObject
mcp__unity-mcp-server__create_gameobject({
name: "Enemy",
primitiveType: "capsule",
position: { x: 0, y: 1, z: 0 }
})
// 2. Add components
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Enemy",
componentType: "Rigidbody"
})
// 3. Create enemy script
mcp__unity-mcp-server__create_class({
path: "Assets/Scripts/Enemies/EnemyController.cs",
className: "EnemyController",
baseType: "MonoBehaviour"
})
// 4. Add AI implementation
mcp__unity-mcp-server__edit_structured({
path: "Assets/Scripts/Enemies/EnemyController.cs",
symbolName: "EnemyController",
operation: "insert_after",
newText: `
[SerializeField] private float _speed = 3f;
private Transform _target;
void Update()
{
if (_target != null)
transform.position = Vector3.MoveTowards(
transform.position,
_target.position,
_speed * Time.deltaTime
);
}
`
})
// 5. Convert to prefab
mcp__unity-mcp-server__create_prefab({
gameObjectPath: "/Enemy",
prefabPath: "Assets/Prefabs/Enemies/Enemy.prefab"
})
Required operations: Test creation + PlayMode control + Input simulation
// 1. Create test class
mcp__unity-mcp-server__create_class({
path: "Assets/Tests/PlayMode/PlayerMovementTests.cs",
className: "PlayerMovementTests",
namespace: "Tests.PlayMode",
usings: "NUnit.Framework,UnityEngine.TestTools,System.Collections"
})
// 2. Add PlayMode test implementation
mcp__unity-mcp-server__edit_structured({
path: "Assets/Tests/PlayMode/PlayerMovementTests.cs",
symbolName: "PlayerMovementTests",
operation: "insert_after",
newText: `
[UnityTest]
public IEnumerator Player_MovesForward_WhenWPressed()
{
var player = Object.FindObjectOfType<PlayerController>();
var startPos = player.transform.position;
yield return null;
// Simulate W key input
// Use input_keyboard tool during test execution
yield return new WaitForSeconds(0.5f);
Assert.Greater(player.transform.position.z, startPos.z);
}
`
})
// 3. Run tests
mcp__unity-mcp-server__run_tests({
testMode: "PlayMode",
filter: "PlayerMovementTests"
})
Refer to the following child skills when detailed implementation patterns are needed:
| Skill | Purpose | When to Reference |
|---|---|---|
unity-csharp-editing | C# editing, TDD, refactoring | During code editing |
unity-scene-management | Scene & GameObject operations | During scene construction |
unity-asset-management | Prefabs, materials, Addressables | During asset management |
unity-playmode-testing | PlayMode, input simulation | During test execution |
unity-game-ugui-design | uGUI (Canvas/EventSystem) | During game UI implementation |
unity-game-ui-toolkit-design | UI Toolkit (Runtime) | During modern UI implementation |
unity-editor-imgui-design | IMGUI (EditorWindow/Inspector) | During editor extension |
Unity Development Task
├─ Need code editing?
│ ├─ YES → edit_snippet / edit_structured
│ │ Details: unity-csharp-editing
│ └─ NO → Next
├─ Need scene/GameObject operations?
│ ├─ YES → create_gameobject / add_component
│ │ Details: unity-scene-management
│ └─ NO → Next
├─ Need asset operations?
│ ├─ YES → create_prefab / addressables_manage
│ │ Details: unity-asset-management
│ └─ NO → Next
├─ Need UI implementation?
│ ├─ Game UI → unity-game-ugui-design or unity-game-ui-toolkit-design
│ └─ Editor UI → unity-editor-imgui-design
└─ Need testing/verification?
└─ YES → play_game / run_tests
Details: unity-playmode-testing