Unity-MCP skills (#659)
* Initial Upload for Skills * Update unity-mcp-skill/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Refine language in Unity-MCP Operator Guide Updated wording for clarity and consistency in the guide. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>beta
parent
74236b6f66
commit
20e822b60f
|
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
name: unity-mcp-orchestrator
|
||||
description: Orchestrate Unity Editor via MCP (Model Context Protocol) tools and resources. Use when working with Unity projects through MCP for Unity - creating/modifying GameObjects, editing scripts, managing scenes, running tests, or any Unity Editor automation. Provides best practices, tool schemas, and workflow patterns for effective Unity-MCP integration.
|
||||
---
|
||||
|
||||
# Unity-MCP Operator Guide
|
||||
|
||||
This skill helps you effectively use the Unity Editor with MCP tools and resources.
|
||||
|
||||
## Quick Start: Resource-First Workflow
|
||||
|
||||
**Always read relevant resources before using tools.** This prevents errors and provides the necessary context.
|
||||
|
||||
```
|
||||
1. Check editor state → mcpforunity://editor/state
|
||||
2. Understand the scene → mcpforunity://scene/gameobject-api
|
||||
3. Find what you need → find_gameobjects or resources
|
||||
4. Take action → tools (manage_gameobject, create_script, script_apply_edits, apply_text_edits, validate_script, delete_script, get_sha, etc.)
|
||||
5. Verify results → read_console, capture_screenshot (in manage_scene), resources
|
||||
```
|
||||
|
||||
## Critical Best Practices
|
||||
|
||||
### 1. After Writing/Editing Scripts: Always Refresh and Check Console
|
||||
|
||||
```python
|
||||
# After create_script or script_apply_edits:
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
read_console(types=["error"], count=10, include_stacktrace=True)
|
||||
```
|
||||
|
||||
**Why:** Unity must compile scripts before they're usable. Compilation errors block all tool execution.
|
||||
|
||||
### 2. Use `batch_execute` for Multiple Operations
|
||||
|
||||
```python
|
||||
# 10-100x faster than sequential calls
|
||||
batch_execute(
|
||||
commands=[
|
||||
{"tool": "manage_gameobject", "params": {"action": "create", "name": "Cube1", "primitive_type": "Cube"}},
|
||||
{"tool": "manage_gameobject", "params": {"action": "create", "name": "Cube2", "primitive_type": "Cube"}},
|
||||
{"tool": "manage_gameobject", "params": {"action": "create", "name": "Cube3", "primitive_type": "Cube"}}
|
||||
],
|
||||
parallel=True # Read-only operations can run in parallel
|
||||
)
|
||||
```
|
||||
|
||||
**Max 25 commands per batch.** Use `fail_fast=True` for dependent operations.
|
||||
|
||||
### 3. Use `screenshot` in manage_scene to Verify Visual Results
|
||||
|
||||
```python
|
||||
# Via manage_scene
|
||||
manage_scene(action="screenshot") # Returns base64 image
|
||||
|
||||
# After creating/modifying objects, verify visually:
|
||||
# 1. Create objects
|
||||
# 2. capture screenshot
|
||||
# 3. Analyze if result matches intent
|
||||
```
|
||||
|
||||
### 4. Check Console After Major Changes
|
||||
|
||||
```python
|
||||
read_console(
|
||||
action="get",
|
||||
types=["error", "warning"], # Focus on problems
|
||||
count=10,
|
||||
format="detailed"
|
||||
)
|
||||
```
|
||||
|
||||
### 5. Always Check `editor_state` Before Complex Operations
|
||||
|
||||
```python
|
||||
# Read mcpforunity://editor/state to check:
|
||||
# - is_compiling: Wait if true
|
||||
# - is_domain_reload_pending: Wait if true
|
||||
# - ready_for_tools: Only proceed if true
|
||||
# - blocking_reasons: Why tools might fail
|
||||
```
|
||||
|
||||
## Parameter Type Conventions
|
||||
|
||||
### Vectors (position, rotation, scale, color)
|
||||
```python
|
||||
# Both forms accepted:
|
||||
position=[1.0, 2.0, 3.0] # List
|
||||
position="[1.0, 2.0, 3.0]" # JSON string
|
||||
```
|
||||
|
||||
### Booleans
|
||||
```python
|
||||
# Both forms accepted:
|
||||
include_inactive=True # Boolean
|
||||
include_inactive="true" # String
|
||||
```
|
||||
|
||||
### Colors
|
||||
```python
|
||||
# Auto-detected format:
|
||||
color=[255, 0, 0, 255] # 0-255 range
|
||||
color=[1.0, 0.0, 0.0, 1.0] # 0.0-1.0 normalized (auto-converted)
|
||||
```
|
||||
|
||||
### Paths
|
||||
```python
|
||||
# Assets-relative (default):
|
||||
path="Assets/Scripts/MyScript.cs"
|
||||
|
||||
# URI forms:
|
||||
uri="mcpforunity://path/Assets/Scripts/MyScript.cs"
|
||||
uri="file:///full/path/to/file.cs"
|
||||
```
|
||||
|
||||
## Core Tool Categories
|
||||
|
||||
| Category | Key Tools | Use For |
|
||||
|----------|-----------|---------|
|
||||
| **Scene** | `manage_scene`, `find_gameobjects` | Scene operations, finding objects |
|
||||
| **Objects** | `manage_gameobject`, `manage_components` | Creating/modifying GameObjects |
|
||||
| **Scripts** | `create_script`, `script_apply_edits`, `refresh_unity` | C# code management |
|
||||
| **Assets** | `manage_asset`, `manage_prefabs` | Asset operations |
|
||||
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control |
|
||||
| **Testing** | `run_tests`, `get_test_job` | Unity Test Framework |
|
||||
| **Batch** | `batch_execute` | Parallel/bulk operations |
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Creating a New Script and Using It
|
||||
|
||||
```python
|
||||
# 1. Create the script
|
||||
create_script(
|
||||
path="Assets/Scripts/PlayerController.cs",
|
||||
contents="using UnityEngine;\n\npublic class PlayerController : MonoBehaviour\n{\n void Update() { }\n}"
|
||||
)
|
||||
|
||||
# 2. CRITICAL: Refresh and wait for compilation
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
|
||||
# 3. Check for compilation errors
|
||||
read_console(types=["error"], count=10)
|
||||
|
||||
# 4. Only then attach to GameObject
|
||||
manage_gameobject(action="modify", target="Player", components_to_add=["PlayerController"])
|
||||
```
|
||||
|
||||
### Finding and Modifying GameObjects
|
||||
|
||||
```python
|
||||
# 1. Find by name/tag/component (returns IDs only)
|
||||
result = find_gameobjects(search_term="Enemy", search_method="by_tag", page_size=50)
|
||||
|
||||
# 2. Get full data via resource
|
||||
# mcpforunity://scene/gameobject/{instance_id}
|
||||
|
||||
# 3. Modify using the ID
|
||||
manage_gameobject(action="modify", target=instance_id, position=[10, 0, 0])
|
||||
```
|
||||
|
||||
### Running and Monitoring Tests
|
||||
|
||||
```python
|
||||
# 1. Start test run (async)
|
||||
result = run_tests(mode="EditMode", test_names=["MyTests.TestSomething"])
|
||||
job_id = result["job_id"]
|
||||
|
||||
# 2. Poll for completion
|
||||
result = get_test_job(job_id=job_id, wait_timeout=60, include_failed_tests=True)
|
||||
```
|
||||
|
||||
## Pagination Pattern
|
||||
|
||||
Large queries return paginated results. Always follow `next_cursor`:
|
||||
|
||||
```python
|
||||
cursor = 0
|
||||
all_items = []
|
||||
while True:
|
||||
result = manage_scene(action="get_hierarchy", page_size=50, cursor=cursor)
|
||||
all_items.extend(result["data"]["items"])
|
||||
if not result["data"].get("next_cursor"):
|
||||
break
|
||||
cursor = result["data"]["next_cursor"]
|
||||
```
|
||||
|
||||
## Multi-Instance Workflow
|
||||
|
||||
When multiple Unity Editors are running:
|
||||
|
||||
```python
|
||||
# 1. List instances via resource: mcpforunity://instances
|
||||
# 2. Set active instance
|
||||
set_active_instance(instance="MyProject@abc123")
|
||||
# 3. All subsequent calls route to that instance
|
||||
```
|
||||
|
||||
## Error Recovery
|
||||
|
||||
| Symptom | Cause | Solution |
|
||||
|---------|-------|----------|
|
||||
| Tools return "busy" | Compilation in progress | Wait, check `editor_state` |
|
||||
| "stale_file" error | File changed since SHA | Re-fetch SHA with `get_sha`, retry |
|
||||
| Connection lost | Domain reload | Wait ~5s, reconnect |
|
||||
| Commands fail silently | Wrong instance | Check `set_active_instance` |
|
||||
|
||||
## Reference Files
|
||||
|
||||
For detailed schemas and examples:
|
||||
|
||||
- **[tools-reference.md](references/tools-reference.md)**: Complete tool documentation with all parameters
|
||||
- **[resources-reference.md](references/resources-reference.md)**: All available resources and their data
|
||||
- **[workflows.md](references/workflows.md)**: Extended workflow examples and patterns
|
||||
|
|
@ -0,0 +1,493 @@
|
|||
# Unity-MCP Resources Reference
|
||||
|
||||
Resources provide read-only access to Unity state. Use resources to inspect before using tools to modify.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Editor State Resources](#editor-state-resources)
|
||||
- [Scene & GameObject Resources](#scene--gameobject-resources)
|
||||
- [Prefab Resources](#prefab-resources)
|
||||
- [Project Resources](#project-resources)
|
||||
- [Instance Resources](#instance-resources)
|
||||
- [Test Resources](#test-resources)
|
||||
|
||||
---
|
||||
|
||||
## URI Scheme
|
||||
|
||||
All resources use `mcpforunity://` scheme:
|
||||
|
||||
```
|
||||
mcpforunity://{category}/{resource_path}[?query_params]
|
||||
```
|
||||
|
||||
**Categories:** `editor`, `scene`, `prefab`, `project`, `menu-items`, `custom-tools`, `tests`, `instances`
|
||||
|
||||
---
|
||||
|
||||
## Editor State Resources
|
||||
|
||||
### mcpforunity://editor/state
|
||||
|
||||
**Purpose:** Editor readiness snapshot - check before tool operations.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"unity_version": "2022.3.10f1",
|
||||
"is_compiling": false,
|
||||
"is_domain_reload_pending": false,
|
||||
"play_mode": {
|
||||
"is_playing": false,
|
||||
"is_paused": false
|
||||
},
|
||||
"active_scene": {
|
||||
"path": "Assets/Scenes/Main.unity",
|
||||
"name": "Main"
|
||||
},
|
||||
"ready_for_tools": true,
|
||||
"blocking_reasons": [],
|
||||
"recommended_retry_after_ms": null,
|
||||
"staleness": {
|
||||
"age_ms": 150,
|
||||
"is_stale": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Fields:**
|
||||
- `ready_for_tools`: Only proceed if `true`
|
||||
- `is_compiling`: Wait if `true`
|
||||
- `blocking_reasons`: Array explaining why tools might fail
|
||||
- `recommended_retry_after_ms`: Suggested wait time
|
||||
|
||||
### mcpforunity://editor/selection
|
||||
|
||||
**Purpose:** Currently selected objects.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"activeObject": "Player",
|
||||
"activeGameObject": "Player",
|
||||
"activeInstanceID": 12345,
|
||||
"count": 3,
|
||||
"gameObjects": ["Player", "Enemy", "Wall"],
|
||||
"assetGUIDs": []
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://editor/active-tool
|
||||
|
||||
**Purpose:** Current editor tool state.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"activeTool": "Move",
|
||||
"isCustom": false,
|
||||
"pivotMode": "Center",
|
||||
"pivotRotation": "Global"
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://editor/windows
|
||||
|
||||
**Purpose:** All open editor windows.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"windows": [
|
||||
{
|
||||
"title": "Scene",
|
||||
"typeName": "UnityEditor.SceneView",
|
||||
"isFocused": true,
|
||||
"position": {"x": 0, "y": 0, "width": 800, "height": 600}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://editor/prefab-stage
|
||||
|
||||
**Purpose:** Current prefab editing context.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"isOpen": true,
|
||||
"assetPath": "Assets/Prefabs/Player.prefab",
|
||||
"prefabRootName": "Player",
|
||||
"isDirty": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scene & GameObject Resources
|
||||
|
||||
### mcpforunity://scene/gameobject-api
|
||||
|
||||
**Purpose:** Documentation for GameObject resources (read this first).
|
||||
|
||||
### mcpforunity://scene/gameobject/{instance_id}
|
||||
|
||||
**Purpose:** Basic GameObject data (metadata, no component properties).
|
||||
|
||||
**Parameters:**
|
||||
- `instance_id` (int): GameObject instance ID from `find_gameobjects`
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"instanceID": 12345,
|
||||
"name": "Player",
|
||||
"tag": "Player",
|
||||
"layer": 8,
|
||||
"layerName": "Player",
|
||||
"active": true,
|
||||
"activeInHierarchy": true,
|
||||
"isStatic": false,
|
||||
"transform": {
|
||||
"position": [0, 1, 0],
|
||||
"rotation": [0, 0, 0],
|
||||
"scale": [1, 1, 1]
|
||||
},
|
||||
"parent": {"instanceID": 0},
|
||||
"children": [{"instanceID": 67890}],
|
||||
"componentTypes": ["Transform", "Rigidbody", "PlayerController"],
|
||||
"path": "/Player"
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://scene/gameobject/{instance_id}/components
|
||||
|
||||
**Purpose:** All components with full property serialization (paginated).
|
||||
|
||||
**Parameters:**
|
||||
- `instance_id` (int): GameObject instance ID
|
||||
- `page_size` (int): Default 25, max 100
|
||||
- `cursor` (int): Pagination cursor
|
||||
- `include_properties` (bool): Default true, set false for just types
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"gameObjectID": 12345,
|
||||
"gameObjectName": "Player",
|
||||
"components": [
|
||||
{
|
||||
"type": "Transform",
|
||||
"properties": {
|
||||
"position": {"x": 0, "y": 1, "z": 0},
|
||||
"rotation": {"x": 0, "y": 0, "z": 0, "w": 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Rigidbody",
|
||||
"properties": {
|
||||
"mass": 1.0,
|
||||
"useGravity": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursor": 0,
|
||||
"pageSize": 25,
|
||||
"nextCursor": null,
|
||||
"hasMore": false
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://scene/gameobject/{instance_id}/component/{component_name}
|
||||
|
||||
**Purpose:** Single component with full properties.
|
||||
|
||||
**Parameters:**
|
||||
- `instance_id` (int): GameObject instance ID
|
||||
- `component_name` (string): e.g., "Rigidbody", "Camera", "Transform"
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"gameObjectID": 12345,
|
||||
"gameObjectName": "Player",
|
||||
"component": {
|
||||
"type": "Rigidbody",
|
||||
"properties": {
|
||||
"mass": 1.0,
|
||||
"drag": 0,
|
||||
"angularDrag": 0.05,
|
||||
"useGravity": true,
|
||||
"isKinematic": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prefab Resources
|
||||
|
||||
### mcpforunity://prefab-api
|
||||
|
||||
**Purpose:** Documentation for prefab resources.
|
||||
|
||||
### mcpforunity://prefab/{encoded_path}
|
||||
|
||||
**Purpose:** Prefab asset information.
|
||||
|
||||
**Parameters:**
|
||||
- `encoded_path` (string): URL-encoded path, e.g., `Assets%2FPrefabs%2FPlayer.prefab`
|
||||
|
||||
**Path Encoding:**
|
||||
```
|
||||
Assets/Prefabs/Player.prefab → Assets%2FPrefabs%2FPlayer.prefab
|
||||
```
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"assetPath": "Assets/Prefabs/Player.prefab",
|
||||
"guid": "abc123...",
|
||||
"prefabType": "Regular",
|
||||
"rootObjectName": "Player",
|
||||
"rootComponentTypes": ["Transform", "PlayerController"],
|
||||
"childCount": 5,
|
||||
"isVariant": false,
|
||||
"parentPrefab": null
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://prefab/{encoded_path}/hierarchy
|
||||
|
||||
**Purpose:** Full prefab hierarchy with nested prefab info.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"prefabPath": "Assets/Prefabs/Player.prefab",
|
||||
"total": 6,
|
||||
"items": [
|
||||
{
|
||||
"name": "Player",
|
||||
"instanceId": 12345,
|
||||
"path": "/Player",
|
||||
"activeSelf": true,
|
||||
"childCount": 2,
|
||||
"componentTypes": ["Transform", "PlayerController"]
|
||||
},
|
||||
{
|
||||
"name": "Model",
|
||||
"path": "/Player/Model",
|
||||
"isNestedPrefab": true,
|
||||
"nestedPrefabPath": "Assets/Prefabs/PlayerModel.prefab"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Resources
|
||||
|
||||
### mcpforunity://project/info
|
||||
|
||||
**Purpose:** Static project configuration.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"projectRoot": "/Users/dev/MyProject",
|
||||
"projectName": "MyProject",
|
||||
"unityVersion": "2022.3.10f1",
|
||||
"platform": "StandaloneWindows64",
|
||||
"assetsPath": "/Users/dev/MyProject/Assets"
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://project/tags
|
||||
|
||||
**Purpose:** All tags defined in TagManager.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
["Untagged", "Respawn", "Finish", "EditorOnly", "MainCamera", "Player", "GameController", "Enemy"]
|
||||
```
|
||||
|
||||
### mcpforunity://project/layers
|
||||
|
||||
**Purpose:** All layers with indices (0-31).
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"0": "Default",
|
||||
"1": "TransparentFX",
|
||||
"2": "Ignore Raycast",
|
||||
"4": "Water",
|
||||
"5": "UI",
|
||||
"8": "Player",
|
||||
"9": "Enemy"
|
||||
}
|
||||
```
|
||||
|
||||
### mcpforunity://menu-items
|
||||
|
||||
**Purpose:** All available Unity menu items.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
[
|
||||
"File/New Scene",
|
||||
"File/Open Scene",
|
||||
"File/Save",
|
||||
"Edit/Undo",
|
||||
"Edit/Redo",
|
||||
"GameObject/Create Empty",
|
||||
"GameObject/3D Object/Cube",
|
||||
"Window/General/Console"
|
||||
]
|
||||
```
|
||||
|
||||
### mcpforunity://custom-tools
|
||||
|
||||
**Purpose:** Custom tools available in the active Unity project.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"project_id": "MyProject",
|
||||
"tool_count": 3,
|
||||
"tools": [
|
||||
{
|
||||
"name": "capture_screenshot",
|
||||
"description": "Capture screenshots in Unity",
|
||||
"parameters": [
|
||||
{"name": "filename", "type": "string", "required": true},
|
||||
{"name": "width", "type": "int", "required": false},
|
||||
{"name": "height", "type": "int", "required": false}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Instance Resources
|
||||
|
||||
### mcpforunity://instances
|
||||
|
||||
**Purpose:** All running Unity Editor instances (for multi-instance workflows).
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
{
|
||||
"transport": "http",
|
||||
"instance_count": 2,
|
||||
"instances": [
|
||||
{
|
||||
"id": "MyProject@abc123",
|
||||
"name": "MyProject",
|
||||
"hash": "abc123",
|
||||
"unity_version": "2022.3.10f1",
|
||||
"connected_at": "2024-01-15T10:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "TestProject@def456",
|
||||
"name": "TestProject",
|
||||
"hash": "def456",
|
||||
"unity_version": "2022.3.10f1",
|
||||
"connected_at": "2024-01-15T11:00:00Z"
|
||||
}
|
||||
],
|
||||
"warnings": []
|
||||
}
|
||||
```
|
||||
|
||||
**Use with:** `set_active_instance(instance="MyProject@abc123")`
|
||||
|
||||
---
|
||||
|
||||
## Test Resources
|
||||
|
||||
### mcpforunity://tests
|
||||
|
||||
**Purpose:** All tests in the project.
|
||||
|
||||
**Returns:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "TestSomething",
|
||||
"full_name": "MyTests.TestSomething",
|
||||
"mode": "EditMode"
|
||||
},
|
||||
{
|
||||
"name": "TestOther",
|
||||
"full_name": "MyTests.TestOther",
|
||||
"mode": "PlayMode"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### mcpforunity://tests/{mode}
|
||||
|
||||
**Purpose:** Tests filtered by mode.
|
||||
|
||||
**Parameters:**
|
||||
- `mode` (string): "EditMode" or "PlayMode"
|
||||
|
||||
**Example:** `mcpforunity://tests/EditMode`
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Check Editor State First
|
||||
|
||||
```python
|
||||
# Before any complex operation:
|
||||
# Read mcpforunity://editor/state
|
||||
# Check ready_for_tools == true
|
||||
```
|
||||
|
||||
### 2. Use Find Then Read Pattern
|
||||
|
||||
```python
|
||||
# 1. find_gameobjects to get IDs
|
||||
result = find_gameobjects(search_term="Player")
|
||||
|
||||
# 2. Read resource for full data
|
||||
# mcpforunity://scene/gameobject/{id}
|
||||
```
|
||||
|
||||
### 3. Paginate Large Queries
|
||||
|
||||
```python
|
||||
# Start with include_properties=false for component lists
|
||||
# mcpforunity://scene/gameobject/{id}/components?include_properties=false&page_size=25
|
||||
|
||||
# Then read specific components as needed
|
||||
# mcpforunity://scene/gameobject/{id}/component/Rigidbody
|
||||
```
|
||||
|
||||
### 4. URL-Encode Prefab Paths
|
||||
|
||||
```python
|
||||
# Wrong:
|
||||
# mcpforunity://prefab/Assets/Prefabs/Player.prefab
|
||||
|
||||
# Correct:
|
||||
# mcpforunity://prefab/Assets%2FPrefabs%2FPlayer.prefab
|
||||
```
|
||||
|
||||
### 5. Multi-Instance Awareness
|
||||
|
||||
```python
|
||||
# Always check mcpforunity://instances when:
|
||||
# - First connecting
|
||||
# - Commands fail unexpectedly
|
||||
# - Working with multiple projects
|
||||
```
|
||||
|
|
@ -0,0 +1,606 @@
|
|||
# Unity-MCP Tools Reference
|
||||
|
||||
Complete reference for all MCP tools. Each tool includes parameters, types, and usage examples.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Infrastructure Tools](#infrastructure-tools)
|
||||
- [Scene Tools](#scene-tools)
|
||||
- [GameObject Tools](#gameobject-tools)
|
||||
- [Script Tools](#script-tools)
|
||||
- [Asset Tools](#asset-tools)
|
||||
- [Material & Shader Tools](#material--shader-tools)
|
||||
- [Editor Control Tools](#editor-control-tools)
|
||||
- [Testing Tools](#testing-tools)
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure Tools
|
||||
|
||||
### batch_execute
|
||||
|
||||
Execute multiple MCP commands in a single batch (10-100x faster).
|
||||
|
||||
```python
|
||||
batch_execute(
|
||||
commands=[ # list[dict], required, max 25
|
||||
{"tool": "tool_name", "params": {...}},
|
||||
...
|
||||
],
|
||||
parallel=False, # bool, optional - run read-only ops in parallel
|
||||
fail_fast=False, # bool, optional - stop on first failure
|
||||
max_parallelism=None # int, optional - max parallel workers
|
||||
)
|
||||
```
|
||||
|
||||
### set_active_instance
|
||||
|
||||
Route commands to a specific Unity instance (multi-instance workflows).
|
||||
|
||||
```python
|
||||
set_active_instance(
|
||||
instance="ProjectName@abc123" # str, required - Name@hash or hash prefix
|
||||
)
|
||||
```
|
||||
|
||||
### refresh_unity
|
||||
|
||||
Refresh asset database and trigger script compilation.
|
||||
|
||||
```python
|
||||
refresh_unity(
|
||||
mode="if_dirty", # "if_dirty" | "force"
|
||||
scope="all", # "assets" | "scripts" | "all"
|
||||
compile="none", # "none" | "request"
|
||||
wait_for_ready=True # bool - wait until editor ready
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scene Tools
|
||||
|
||||
### manage_scene
|
||||
|
||||
Scene CRUD operations and hierarchy queries.
|
||||
|
||||
```python
|
||||
# Get hierarchy (paginated)
|
||||
manage_scene(
|
||||
action="get_hierarchy",
|
||||
page_size=50, # int, default 50, max 500
|
||||
cursor=0, # int, pagination cursor
|
||||
parent=None, # str|int, optional - filter by parent
|
||||
include_transform=False # bool - include local transforms
|
||||
)
|
||||
|
||||
# Screenshot
|
||||
manage_scene(action="screenshot") # Returns base64 PNG
|
||||
|
||||
# Other actions
|
||||
manage_scene(action="get_active") # Current scene info
|
||||
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")
|
||||
```
|
||||
|
||||
### find_gameobjects
|
||||
|
||||
Search for GameObjects (returns instance IDs only).
|
||||
|
||||
```python
|
||||
find_gameobjects(
|
||||
search_term="Player", # str, required
|
||||
search_method="by_name", # "by_name"|"by_tag"|"by_layer"|"by_component"|"by_path"|"by_id"
|
||||
include_inactive=False, # bool|str
|
||||
page_size=50, # int, default 50, max 500
|
||||
cursor=0 # int, pagination cursor
|
||||
)
|
||||
# Returns: {"ids": [12345, 67890], "next_cursor": 50, ...}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GameObject Tools
|
||||
|
||||
### manage_gameobject
|
||||
|
||||
Create, modify, delete, duplicate GameObjects.
|
||||
|
||||
```python
|
||||
# Create
|
||||
manage_gameobject(
|
||||
action="create",
|
||||
name="MyCube", # str, required
|
||||
primitive_type="Cube", # "Cube"|"Sphere"|"Capsule"|"Cylinder"|"Plane"|"Quad"
|
||||
position=[0, 1, 0], # list[float] or JSON string "[0,1,0]"
|
||||
rotation=[0, 45, 0], # euler angles
|
||||
scale=[1, 1, 1],
|
||||
components_to_add=["Rigidbody", "BoxCollider"],
|
||||
save_as_prefab=False,
|
||||
prefab_path="Assets/Prefabs/MyCube.prefab"
|
||||
)
|
||||
|
||||
# Modify
|
||||
manage_gameobject(
|
||||
action="modify",
|
||||
target="Player", # name, path, or instance ID
|
||||
search_method="by_name", # how to find target
|
||||
position=[10, 0, 0],
|
||||
rotation=[0, 90, 0],
|
||||
scale=[2, 2, 2],
|
||||
set_active=True,
|
||||
layer="Player",
|
||||
components_to_add=["AudioSource"],
|
||||
components_to_remove=["OldComponent"],
|
||||
component_properties={ # nested dict for property setting
|
||||
"Rigidbody": {
|
||||
"mass": 10.0,
|
||||
"useGravity": True
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Delete
|
||||
manage_gameobject(action="delete", target="OldObject")
|
||||
|
||||
# Duplicate
|
||||
manage_gameobject(
|
||||
action="duplicate",
|
||||
target="Player",
|
||||
new_name="Player2",
|
||||
offset=[5, 0, 0] # position offset from original
|
||||
)
|
||||
|
||||
# Move relative
|
||||
manage_gameobject(
|
||||
action="move_relative",
|
||||
target="Player",
|
||||
reference_object="Enemy", # optional reference
|
||||
direction="left", # "left"|"right"|"up"|"down"|"forward"|"back"
|
||||
distance=5.0,
|
||||
world_space=True
|
||||
)
|
||||
```
|
||||
|
||||
### manage_components
|
||||
|
||||
Add, remove, or set properties on components.
|
||||
|
||||
```python
|
||||
# Add component
|
||||
manage_components(
|
||||
action="add",
|
||||
target=12345, # instance ID (preferred) or name
|
||||
component_type="Rigidbody",
|
||||
search_method="by_id"
|
||||
)
|
||||
|
||||
# Remove component
|
||||
manage_components(
|
||||
action="remove",
|
||||
target="Player",
|
||||
component_type="OldScript"
|
||||
)
|
||||
|
||||
# Set single property
|
||||
manage_components(
|
||||
action="set_property",
|
||||
target=12345,
|
||||
component_type="Rigidbody",
|
||||
property="mass",
|
||||
value=5.0
|
||||
)
|
||||
|
||||
# Set multiple properties
|
||||
manage_components(
|
||||
action="set_property",
|
||||
target=12345,
|
||||
component_type="Transform",
|
||||
properties={
|
||||
"position": [1, 2, 3],
|
||||
"localScale": [2, 2, 2]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Script Tools
|
||||
|
||||
### create_script
|
||||
|
||||
Create a new C# script.
|
||||
|
||||
```python
|
||||
create_script(
|
||||
path="Assets/Scripts/MyScript.cs", # str, required
|
||||
contents='''using UnityEngine;
|
||||
|
||||
public class MyScript : MonoBehaviour
|
||||
{
|
||||
void Start() { }
|
||||
void Update() { }
|
||||
}''',
|
||||
script_type="MonoBehaviour", # optional hint
|
||||
namespace="MyGame" # optional namespace
|
||||
)
|
||||
```
|
||||
|
||||
### script_apply_edits
|
||||
|
||||
Apply structured edits to C# scripts (safer than raw text edits).
|
||||
|
||||
```python
|
||||
script_apply_edits(
|
||||
name="MyScript", # script name (no .cs)
|
||||
path="Assets/Scripts", # folder path
|
||||
edits=[
|
||||
# Replace entire method
|
||||
{
|
||||
"op": "replace_method",
|
||||
"methodName": "Update",
|
||||
"replacement": "void Update() { transform.Rotate(Vector3.up); }"
|
||||
},
|
||||
# Insert new method
|
||||
{
|
||||
"op": "insert_method",
|
||||
"afterMethod": "Start",
|
||||
"code": "void OnEnable() { Debug.Log(\"Enabled\"); }"
|
||||
},
|
||||
# Delete method
|
||||
{
|
||||
"op": "delete_method",
|
||||
"methodName": "OldMethod"
|
||||
},
|
||||
# Anchor-based insert
|
||||
{
|
||||
"op": "anchor_insert",
|
||||
"anchor": "void Start()",
|
||||
"position": "before", # "before" | "after"
|
||||
"text": "// Called before Start\n"
|
||||
},
|
||||
# Regex replace
|
||||
{
|
||||
"op": "regex_replace",
|
||||
"pattern": "Debug\\.Log\\(",
|
||||
"text": "Debug.LogWarning("
|
||||
},
|
||||
# Prepend/append to file
|
||||
{"op": "prepend", "text": "// File header\n"},
|
||||
{"op": "append", "text": "\n// File footer"}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### apply_text_edits
|
||||
|
||||
Apply precise character-position edits (1-indexed lines/columns).
|
||||
|
||||
```python
|
||||
apply_text_edits(
|
||||
uri="mcpforunity://path/Assets/Scripts/MyScript.cs",
|
||||
edits=[
|
||||
{
|
||||
"startLine": 10,
|
||||
"startCol": 5,
|
||||
"endLine": 10,
|
||||
"endCol": 20,
|
||||
"newText": "replacement text"
|
||||
}
|
||||
],
|
||||
precondition_sha256="abc123...", # optional, prevents stale edits
|
||||
strict=True # optional, stricter validation
|
||||
)
|
||||
```
|
||||
|
||||
### validate_script
|
||||
|
||||
Check script for syntax/semantic errors.
|
||||
|
||||
```python
|
||||
validate_script(
|
||||
uri="mcpforunity://path/Assets/Scripts/MyScript.cs",
|
||||
level="standard", # "basic" | "standard"
|
||||
include_diagnostics=True # include full error details
|
||||
)
|
||||
```
|
||||
|
||||
### get_sha
|
||||
|
||||
Get file hash without content (for preconditions).
|
||||
|
||||
```python
|
||||
get_sha(uri="mcpforunity://path/Assets/Scripts/MyScript.cs")
|
||||
# Returns: {"sha256": "...", "lengthBytes": 1234, "lastModifiedUtc": "..."}
|
||||
```
|
||||
|
||||
### delete_script
|
||||
|
||||
Delete a script file.
|
||||
|
||||
```python
|
||||
delete_script(uri="mcpforunity://path/Assets/Scripts/OldScript.cs")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Asset Tools
|
||||
|
||||
### manage_asset
|
||||
|
||||
Asset operations: search, import, create, modify, delete.
|
||||
|
||||
```python
|
||||
# Search assets (paginated)
|
||||
manage_asset(
|
||||
action="search",
|
||||
path="Assets", # search scope
|
||||
search_pattern="*.prefab", # glob or "t:MonoScript" filter
|
||||
filter_type="Prefab", # optional type filter
|
||||
page_size=25, # keep small to avoid large payloads
|
||||
page_number=1, # 1-based
|
||||
generate_preview=False # avoid base64 bloat
|
||||
)
|
||||
|
||||
# Get asset info
|
||||
manage_asset(action="get_info", path="Assets/Prefabs/Player.prefab")
|
||||
|
||||
# Create asset
|
||||
manage_asset(
|
||||
action="create",
|
||||
path="Assets/Materials/NewMaterial.mat",
|
||||
asset_type="Material",
|
||||
properties={"color": [1, 0, 0, 1]}
|
||||
)
|
||||
|
||||
# Duplicate/move/rename
|
||||
manage_asset(action="duplicate", path="Assets/A.prefab", destination="Assets/B.prefab")
|
||||
manage_asset(action="move", path="Assets/A.prefab", destination="Assets/Prefabs/A.prefab")
|
||||
manage_asset(action="rename", path="Assets/A.prefab", destination="Assets/B.prefab")
|
||||
|
||||
# Create folder
|
||||
manage_asset(action="create_folder", path="Assets/NewFolder")
|
||||
|
||||
# Delete
|
||||
manage_asset(action="delete", path="Assets/OldAsset.asset")
|
||||
```
|
||||
|
||||
### manage_prefabs
|
||||
|
||||
Headless prefab operations.
|
||||
|
||||
```python
|
||||
# Get prefab info
|
||||
manage_prefabs(action="get_info", prefab_path="Assets/Prefabs/Player.prefab")
|
||||
|
||||
# Get prefab hierarchy
|
||||
manage_prefabs(action="get_hierarchy", prefab_path="Assets/Prefabs/Player.prefab")
|
||||
|
||||
# Create prefab from scene GameObject
|
||||
manage_prefabs(
|
||||
action="create_from_gameobject",
|
||||
target="Player", # GameObject in scene
|
||||
prefab_path="Assets/Prefabs/Player.prefab",
|
||||
allow_overwrite=False
|
||||
)
|
||||
|
||||
# Modify prefab contents (headless)
|
||||
manage_prefabs(
|
||||
action="modify_contents",
|
||||
prefab_path="Assets/Prefabs/Player.prefab",
|
||||
target="ChildObject", # object within prefab
|
||||
position=[0, 1, 0],
|
||||
components_to_add=["AudioSource"]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Material & Shader Tools
|
||||
|
||||
### manage_material
|
||||
|
||||
Create and modify materials.
|
||||
|
||||
```python
|
||||
# Create material
|
||||
manage_material(
|
||||
action="create",
|
||||
material_path="Assets/Materials/Red.mat",
|
||||
shader="Standard",
|
||||
properties={"_Color": [1, 0, 0, 1]}
|
||||
)
|
||||
|
||||
# Get material info
|
||||
manage_material(action="get_material_info", material_path="Assets/Materials/Red.mat")
|
||||
|
||||
# Set shader property
|
||||
manage_material(
|
||||
action="set_material_shader_property",
|
||||
material_path="Assets/Materials/Red.mat",
|
||||
property="_Metallic",
|
||||
value=0.8
|
||||
)
|
||||
|
||||
# Set color
|
||||
manage_material(
|
||||
action="set_material_color",
|
||||
material_path="Assets/Materials/Red.mat",
|
||||
property="_BaseColor",
|
||||
color=[0, 1, 0, 1] # RGBA
|
||||
)
|
||||
|
||||
# Assign to renderer
|
||||
manage_material(
|
||||
action="assign_material_to_renderer",
|
||||
target="MyCube",
|
||||
material_path="Assets/Materials/Red.mat",
|
||||
slot=0 # material slot index
|
||||
)
|
||||
|
||||
# Set renderer color directly
|
||||
manage_material(
|
||||
action="set_renderer_color",
|
||||
target="MyCube",
|
||||
color=[1, 0, 0, 1],
|
||||
mode="instance" # "shared"|"instance"|"property_block"
|
||||
)
|
||||
```
|
||||
|
||||
### manage_texture
|
||||
|
||||
Create procedural textures.
|
||||
|
||||
```python
|
||||
manage_texture(
|
||||
action="create",
|
||||
path="Assets/Textures/Checker.png",
|
||||
width=64,
|
||||
height=64,
|
||||
fill_color=[255, 255, 255, 255] # or [1.0, 1.0, 1.0, 1.0]
|
||||
)
|
||||
|
||||
# Apply pattern
|
||||
manage_texture(
|
||||
action="apply_pattern",
|
||||
path="Assets/Textures/Checker.png",
|
||||
pattern="checkerboard", # "checkerboard"|"stripes"|"dots"|"grid"|"brick"
|
||||
palette=[[0,0,0,255], [255,255,255,255]],
|
||||
pattern_size=8
|
||||
)
|
||||
|
||||
# Apply gradient
|
||||
manage_texture(
|
||||
action="apply_gradient",
|
||||
path="Assets/Textures/Gradient.png",
|
||||
gradient_type="linear", # "linear"|"radial"
|
||||
gradient_angle=45,
|
||||
palette=[[255,0,0,255], [0,0,255,255]]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Editor Control Tools
|
||||
|
||||
### manage_editor
|
||||
|
||||
Control Unity Editor state.
|
||||
|
||||
```python
|
||||
manage_editor(action="play") # Enter play mode
|
||||
manage_editor(action="pause") # Pause play mode
|
||||
manage_editor(action="stop") # Exit play mode
|
||||
|
||||
manage_editor(action="set_active_tool", tool_name="Move") # Move/Rotate/Scale/etc.
|
||||
|
||||
manage_editor(action="add_tag", tag_name="Enemy")
|
||||
manage_editor(action="remove_tag", tag_name="OldTag")
|
||||
|
||||
manage_editor(action="add_layer", layer_name="Projectiles")
|
||||
manage_editor(action="remove_layer", layer_name="OldLayer")
|
||||
```
|
||||
|
||||
### execute_menu_item
|
||||
|
||||
Execute any Unity menu item.
|
||||
|
||||
```python
|
||||
execute_menu_item(menu_path="File/Save Project")
|
||||
execute_menu_item(menu_path="GameObject/3D Object/Cube")
|
||||
execute_menu_item(menu_path="Window/General/Console")
|
||||
```
|
||||
|
||||
### read_console
|
||||
|
||||
Read or clear Unity console messages.
|
||||
|
||||
```python
|
||||
# Get recent messages
|
||||
read_console(
|
||||
action="get",
|
||||
types=["error", "warning", "log"], # or ["all"]
|
||||
count=10, # max messages (ignored with paging)
|
||||
filter_text="NullReference", # optional text filter
|
||||
since_timestamp="2024-01-01T00:00:00Z", # optional time filter
|
||||
page_size=50,
|
||||
cursor=0,
|
||||
format="detailed", # "plain"|"detailed"|"json"
|
||||
include_stacktrace=True
|
||||
)
|
||||
|
||||
# Clear console
|
||||
read_console(action="clear")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Tools
|
||||
|
||||
### run_tests
|
||||
|
||||
Start async test execution.
|
||||
|
||||
```python
|
||||
result = run_tests(
|
||||
mode="EditMode", # "EditMode"|"PlayMode"
|
||||
test_names=["MyTests.TestA", "MyTests.TestB"], # specific tests
|
||||
group_names=["Integration*"], # regex patterns
|
||||
category_names=["Unit"], # NUnit categories
|
||||
assembly_names=["Tests"], # assembly filter
|
||||
include_failed_tests=True, # include failure details
|
||||
include_details=False # include all test details
|
||||
)
|
||||
# Returns: {"job_id": "abc123", ...}
|
||||
```
|
||||
|
||||
### get_test_job
|
||||
|
||||
Poll test job status.
|
||||
|
||||
```python
|
||||
result = get_test_job(
|
||||
job_id="abc123",
|
||||
wait_timeout=60, # wait up to N seconds
|
||||
include_failed_tests=True,
|
||||
include_details=False
|
||||
)
|
||||
# Returns: {"status": "complete"|"running"|"failed", "results": {...}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Search Tools
|
||||
|
||||
### find_in_file
|
||||
|
||||
Search file contents with regex.
|
||||
|
||||
```python
|
||||
find_in_file(
|
||||
uri="mcpforunity://path/Assets/Scripts/MyScript.cs",
|
||||
pattern="public void \\w+", # regex pattern
|
||||
max_results=200,
|
||||
ignore_case=True
|
||||
)
|
||||
# Returns: line numbers, content excerpts, match positions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Tools
|
||||
|
||||
### execute_custom_tool
|
||||
|
||||
Execute project-specific custom tools.
|
||||
|
||||
```python
|
||||
execute_custom_tool(
|
||||
tool_name="my_custom_tool",
|
||||
parameters={"param1": "value", "param2": 42}
|
||||
)
|
||||
```
|
||||
|
||||
Discover available custom tools via `mcpforunity://custom-tools` resource.
|
||||
|
|
@ -0,0 +1,609 @@
|
|||
# Unity-MCP Workflow Patterns
|
||||
|
||||
Common workflows and patterns for effective Unity-MCP usage.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Setup & Verification](#setup--verification)
|
||||
- [Scene Creation Workflows](#scene-creation-workflows)
|
||||
- [Script Development Workflows](#script-development-workflows)
|
||||
- [Asset Management Workflows](#asset-management-workflows)
|
||||
- [Testing Workflows](#testing-workflows)
|
||||
- [Debugging Workflows](#debugging-workflows)
|
||||
- [Batch Operations](#batch-operations)
|
||||
|
||||
---
|
||||
|
||||
## Setup & Verification
|
||||
|
||||
### Initial Connection Verification
|
||||
|
||||
```python
|
||||
# 1. Check editor state
|
||||
# Read mcpforunity://editor/state
|
||||
|
||||
# 2. Verify ready_for_tools == true
|
||||
# If false, wait for recommended_retry_after_ms
|
||||
|
||||
# 3. Check active scene
|
||||
# Read mcpforunity://editor/state → active_scene
|
||||
|
||||
# 4. List available instances (multi-instance)
|
||||
# Read mcpforunity://instances
|
||||
```
|
||||
|
||||
### Before Any Operation
|
||||
|
||||
```python
|
||||
# Quick readiness check pattern:
|
||||
editor_state = read_resource("mcpforunity://editor/state")
|
||||
|
||||
if not editor_state["ready_for_tools"]:
|
||||
# Check blocking_reasons
|
||||
# Wait recommended_retry_after_ms
|
||||
pass
|
||||
|
||||
if editor_state["is_compiling"]:
|
||||
# Wait for compilation to complete
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scene Creation Workflows
|
||||
|
||||
### Create Complete Scene from Scratch
|
||||
|
||||
```python
|
||||
# 1. Create new scene
|
||||
manage_scene(action="create", name="GameLevel", path="Assets/Scenes/")
|
||||
|
||||
# 2. Batch create environment objects
|
||||
batch_execute(commands=[
|
||||
{"tool": "manage_gameobject", "params": {
|
||||
"action": "create", "name": "Ground", "primitive_type": "Plane",
|
||||
"position": [0, 0, 0], "scale": [10, 1, 10]
|
||||
}},
|
||||
{"tool": "manage_gameobject", "params": {
|
||||
"action": "create", "name": "Light", "primitive_type": "Cube"
|
||||
}},
|
||||
{"tool": "manage_gameobject", "params": {
|
||||
"action": "create", "name": "Player", "primitive_type": "Capsule",
|
||||
"position": [0, 1, 0]
|
||||
}}
|
||||
])
|
||||
|
||||
# 3. Add light component (delete cube mesh, add light)
|
||||
manage_components(action="remove", target="Light", component_type="MeshRenderer")
|
||||
manage_components(action="remove", target="Light", component_type="MeshFilter")
|
||||
manage_components(action="remove", target="Light", component_type="BoxCollider")
|
||||
manage_components(action="add", target="Light", component_type="Light")
|
||||
manage_components(action="set_property", target="Light", component_type="Light",
|
||||
property="type", value="Directional")
|
||||
|
||||
# 4. Set up camera
|
||||
manage_gameobject(action="modify", target="Main Camera", position=[0, 5, -10],
|
||||
rotation=[30, 0, 0])
|
||||
|
||||
# 5. Verify with screenshot
|
||||
manage_scene(action="screenshot")
|
||||
|
||||
# 6. Save scene
|
||||
manage_scene(action="save")
|
||||
```
|
||||
|
||||
### Populate Scene with Grid of Objects
|
||||
|
||||
```python
|
||||
# Create 5x5 grid of cubes using batch
|
||||
commands = []
|
||||
for x in range(5):
|
||||
for z in range(5):
|
||||
commands.append({
|
||||
"tool": "manage_gameobject",
|
||||
"params": {
|
||||
"action": "create",
|
||||
"name": f"Cube_{x}_{z}",
|
||||
"primitive_type": "Cube",
|
||||
"position": [x * 2, 0, z * 2]
|
||||
}
|
||||
})
|
||||
|
||||
# Execute in batches of 25
|
||||
batch_execute(commands=commands[:25], parallel=True)
|
||||
```
|
||||
|
||||
### Clone and Arrange Objects
|
||||
|
||||
```python
|
||||
# Find template object
|
||||
result = find_gameobjects(search_term="Template", search_method="by_name")
|
||||
template_id = result["ids"][0]
|
||||
|
||||
# Duplicate in a line
|
||||
for i in range(10):
|
||||
manage_gameobject(
|
||||
action="duplicate",
|
||||
target=template_id,
|
||||
new_name=f"Instance_{i}",
|
||||
offset=[i * 2, 0, 0]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Script Development Workflows
|
||||
|
||||
### Create New Script and Attach
|
||||
|
||||
```python
|
||||
# 1. Create script
|
||||
create_script(
|
||||
path="Assets/Scripts/EnemyAI.cs",
|
||||
contents='''using UnityEngine;
|
||||
|
||||
public class EnemyAI : MonoBehaviour
|
||||
{
|
||||
public float speed = 5f;
|
||||
public Transform target;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
Vector3 direction = (target.position - transform.position).normalized;
|
||||
transform.position += direction * speed * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
}'''
|
||||
)
|
||||
|
||||
# 2. CRITICAL: Refresh and compile
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
|
||||
# 3. Check for errors
|
||||
console = read_console(types=["error"], count=10)
|
||||
if console["messages"]:
|
||||
# Handle compilation errors
|
||||
print("Compilation errors:", console["messages"])
|
||||
else:
|
||||
# 4. Attach to GameObject
|
||||
manage_gameobject(action="modify", target="Enemy", components_to_add=["EnemyAI"])
|
||||
|
||||
# 5. Set component properties
|
||||
manage_components(
|
||||
action="set_property",
|
||||
target="Enemy",
|
||||
component_type="EnemyAI",
|
||||
properties={
|
||||
"speed": 10.0
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Edit Existing Script Safely
|
||||
|
||||
```python
|
||||
# 1. Get current SHA
|
||||
sha_info = get_sha(uri="mcpforunity://path/Assets/Scripts/PlayerController.cs")
|
||||
|
||||
# 2. Find the method to edit
|
||||
matches = find_in_file(
|
||||
uri="mcpforunity://path/Assets/Scripts/PlayerController.cs",
|
||||
pattern="void Update\\(\\)"
|
||||
)
|
||||
|
||||
# 3. Apply structured edit
|
||||
script_apply_edits(
|
||||
name="PlayerController",
|
||||
path="Assets/Scripts",
|
||||
edits=[{
|
||||
"op": "replace_method",
|
||||
"methodName": "Update",
|
||||
"replacement": '''void Update()
|
||||
{
|
||||
float h = Input.GetAxis("Horizontal");
|
||||
float v = Input.GetAxis("Vertical");
|
||||
transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime);
|
||||
}'''
|
||||
}]
|
||||
)
|
||||
|
||||
# 4. Validate
|
||||
validate_script(
|
||||
uri="mcpforunity://path/Assets/Scripts/PlayerController.cs",
|
||||
level="standard"
|
||||
)
|
||||
|
||||
# 5. Refresh
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
|
||||
# 6. Check console
|
||||
read_console(types=["error"], count=10)
|
||||
```
|
||||
|
||||
### Add Method to Existing Class
|
||||
|
||||
```python
|
||||
script_apply_edits(
|
||||
name="GameManager",
|
||||
path="Assets/Scripts",
|
||||
edits=[
|
||||
{
|
||||
"op": "insert_method",
|
||||
"afterMethod": "Start",
|
||||
"code": '''
|
||||
public void ResetGame()
|
||||
{
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
|
||||
}'''
|
||||
},
|
||||
{
|
||||
"op": "anchor_insert",
|
||||
"anchor": "using UnityEngine;",
|
||||
"position": "after",
|
||||
"text": "\nusing UnityEngine.SceneManagement;"
|
||||
}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Asset Management Workflows
|
||||
|
||||
### Create and Apply Material
|
||||
|
||||
```python
|
||||
# 1. Create material
|
||||
manage_material(
|
||||
action="create",
|
||||
material_path="Assets/Materials/PlayerMaterial.mat",
|
||||
shader="Standard",
|
||||
properties={
|
||||
"_Color": [0.2, 0.5, 1.0, 1.0],
|
||||
"_Metallic": 0.5,
|
||||
"_Glossiness": 0.8
|
||||
}
|
||||
)
|
||||
|
||||
# 2. Assign to renderer
|
||||
manage_material(
|
||||
action="assign_material_to_renderer",
|
||||
target="Player",
|
||||
material_path="Assets/Materials/PlayerMaterial.mat",
|
||||
slot=0
|
||||
)
|
||||
|
||||
# 3. Verify visually
|
||||
manage_scene(action="screenshot")
|
||||
```
|
||||
|
||||
### Create Procedural Texture
|
||||
|
||||
```python
|
||||
# 1. Create base texture
|
||||
manage_texture(
|
||||
action="create",
|
||||
path="Assets/Textures/Checkerboard.png",
|
||||
width=256,
|
||||
height=256,
|
||||
fill_color=[255, 255, 255, 255]
|
||||
)
|
||||
|
||||
# 2. Apply checkerboard pattern
|
||||
manage_texture(
|
||||
action="apply_pattern",
|
||||
path="Assets/Textures/Checkerboard.png",
|
||||
pattern="checkerboard",
|
||||
palette=[[0, 0, 0, 255], [255, 255, 255, 255]],
|
||||
pattern_size=32
|
||||
)
|
||||
|
||||
# 3. Create material with texture
|
||||
manage_material(
|
||||
action="create",
|
||||
material_path="Assets/Materials/CheckerMaterial.mat",
|
||||
shader="Standard"
|
||||
)
|
||||
|
||||
# 4. Assign texture to material (via manage_material set_material_shader_property)
|
||||
```
|
||||
|
||||
### Organize Assets into Folders
|
||||
|
||||
```python
|
||||
# 1. Create folder structure
|
||||
batch_execute(commands=[
|
||||
{"tool": "manage_asset", "params": {"action": "create_folder", "path": "Assets/Prefabs"}},
|
||||
{"tool": "manage_asset", "params": {"action": "create_folder", "path": "Assets/Materials"}},
|
||||
{"tool": "manage_asset", "params": {"action": "create_folder", "path": "Assets/Scripts"}},
|
||||
{"tool": "manage_asset", "params": {"action": "create_folder", "path": "Assets/Textures"}}
|
||||
])
|
||||
|
||||
# 2. Move existing assets
|
||||
manage_asset(action="move", path="Assets/MyMaterial.mat", destination="Assets/Materials/MyMaterial.mat")
|
||||
manage_asset(action="move", path="Assets/MyScript.cs", destination="Assets/Scripts/MyScript.cs")
|
||||
```
|
||||
|
||||
### Search and Process Assets
|
||||
|
||||
```python
|
||||
# Find all prefabs
|
||||
result = manage_asset(
|
||||
action="search",
|
||||
path="Assets",
|
||||
search_pattern="*.prefab",
|
||||
page_size=50,
|
||||
generate_preview=False
|
||||
)
|
||||
|
||||
# Process each prefab
|
||||
for asset in result["assets"]:
|
||||
prefab_path = asset["path"]
|
||||
# Get prefab info
|
||||
info = manage_prefabs(action="get_info", prefab_path=prefab_path)
|
||||
print(f"Prefab: {prefab_path}, Children: {info['childCount']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Workflows
|
||||
|
||||
### Run Specific Tests
|
||||
|
||||
```python
|
||||
# 1. List available tests
|
||||
# Read mcpforunity://tests/EditMode
|
||||
|
||||
# 2. Run specific tests
|
||||
result = run_tests(
|
||||
mode="EditMode",
|
||||
test_names=["MyTests.TestPlayerMovement", "MyTests.TestEnemySpawn"],
|
||||
include_failed_tests=True
|
||||
)
|
||||
job_id = result["job_id"]
|
||||
|
||||
# 3. Wait for results
|
||||
final_result = get_test_job(
|
||||
job_id=job_id,
|
||||
wait_timeout=60,
|
||||
include_failed_tests=True
|
||||
)
|
||||
|
||||
# 4. Check results
|
||||
if final_result["status"] == "complete":
|
||||
for test in final_result.get("failed_tests", []):
|
||||
print(f"FAILED: {test['name']}: {test['message']}")
|
||||
```
|
||||
|
||||
### Run Tests by Category
|
||||
|
||||
```python
|
||||
# Run all unit tests
|
||||
result = run_tests(
|
||||
mode="EditMode",
|
||||
category_names=["Unit"],
|
||||
include_failed_tests=True
|
||||
)
|
||||
|
||||
# Poll until complete
|
||||
while True:
|
||||
status = get_test_job(job_id=result["job_id"], wait_timeout=30)
|
||||
if status["status"] in ["complete", "failed"]:
|
||||
break
|
||||
```
|
||||
|
||||
### Test-Driven Development Pattern
|
||||
|
||||
```python
|
||||
# 1. Write test first
|
||||
create_script(
|
||||
path="Assets/Tests/Editor/PlayerTests.cs",
|
||||
contents='''using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerTests
|
||||
{
|
||||
[Test]
|
||||
public void TestPlayerStartsAtOrigin()
|
||||
{
|
||||
var player = new GameObject("TestPlayer");
|
||||
Assert.AreEqual(Vector3.zero, player.transform.position);
|
||||
Object.DestroyImmediate(player);
|
||||
}
|
||||
}'''
|
||||
)
|
||||
|
||||
# 2. Refresh
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
|
||||
# 3. Run test (expect pass for this simple test)
|
||||
result = run_tests(mode="EditMode", test_names=["PlayerTests.TestPlayerStartsAtOrigin"])
|
||||
get_test_job(job_id=result["job_id"], wait_timeout=30)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging Workflows
|
||||
|
||||
### Diagnose Compilation Errors
|
||||
|
||||
```python
|
||||
# 1. Check console for errors
|
||||
errors = read_console(
|
||||
types=["error"],
|
||||
count=20,
|
||||
include_stacktrace=True,
|
||||
format="detailed"
|
||||
)
|
||||
|
||||
# 2. For each error, find the file and line
|
||||
for error in errors["messages"]:
|
||||
# Parse error message for file:line info
|
||||
# Use find_in_file to locate the problematic code
|
||||
pass
|
||||
|
||||
# 3. After fixing, refresh and check again
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
read_console(types=["error"], count=10)
|
||||
```
|
||||
|
||||
### Investigate Missing References
|
||||
|
||||
```python
|
||||
# 1. Find the GameObject
|
||||
result = find_gameobjects(search_term="Player", search_method="by_name")
|
||||
|
||||
# 2. Get all components
|
||||
# Read mcpforunity://scene/gameobject/{id}/components
|
||||
|
||||
# 3. Check for null references in serialized fields
|
||||
# Look for fields with null/missing values
|
||||
|
||||
# 4. Find the referenced object
|
||||
result = find_gameobjects(search_term="Target", search_method="by_name")
|
||||
|
||||
# 5. Set the reference
|
||||
manage_components(
|
||||
action="set_property",
|
||||
target="Player",
|
||||
component_type="PlayerController",
|
||||
property="target",
|
||||
value={"instanceID": result["ids"][0]} # Reference by ID
|
||||
)
|
||||
```
|
||||
|
||||
### Check Scene State
|
||||
|
||||
```python
|
||||
# 1. Get hierarchy
|
||||
hierarchy = manage_scene(action="get_hierarchy", page_size=100, include_transform=True)
|
||||
|
||||
# 2. Find objects at unexpected positions
|
||||
for item in hierarchy["data"]["items"]:
|
||||
if item.get("transform", {}).get("position", [0,0,0])[1] < -100:
|
||||
print(f"Object {item['name']} fell through floor!")
|
||||
|
||||
# 3. Visual verification
|
||||
manage_scene(action="screenshot")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Batch Operations
|
||||
|
||||
### Mass Property Update
|
||||
|
||||
```python
|
||||
# Find all enemies
|
||||
enemies = find_gameobjects(search_term="Enemy", search_method="by_tag")
|
||||
|
||||
# Update health on all enemies
|
||||
commands = []
|
||||
for enemy_id in enemies["ids"]:
|
||||
commands.append({
|
||||
"tool": "manage_components",
|
||||
"params": {
|
||||
"action": "set_property",
|
||||
"target": enemy_id,
|
||||
"component_type": "EnemyHealth",
|
||||
"property": "maxHealth",
|
||||
"value": 100
|
||||
}
|
||||
})
|
||||
|
||||
# Execute in batches
|
||||
for i in range(0, len(commands), 25):
|
||||
batch_execute(commands=commands[i:i+25], parallel=True)
|
||||
```
|
||||
|
||||
### Mass Object Creation with Variations
|
||||
|
||||
```python
|
||||
import random
|
||||
|
||||
commands = []
|
||||
for i in range(20):
|
||||
commands.append({
|
||||
"tool": "manage_gameobject",
|
||||
"params": {
|
||||
"action": "create",
|
||||
"name": f"Tree_{i}",
|
||||
"primitive_type": "Capsule",
|
||||
"position": [random.uniform(-50, 50), 0, random.uniform(-50, 50)],
|
||||
"scale": [1, random.uniform(2, 5), 1]
|
||||
}
|
||||
})
|
||||
|
||||
batch_execute(commands=commands, parallel=True)
|
||||
```
|
||||
|
||||
### Cleanup Pattern
|
||||
|
||||
```python
|
||||
# Find all temporary objects
|
||||
temps = find_gameobjects(search_term="Temp_", search_method="by_name")
|
||||
|
||||
# Delete in batch
|
||||
commands = [
|
||||
{"tool": "manage_gameobject", "params": {"action": "delete", "target": id}}
|
||||
for id in temps["ids"]
|
||||
]
|
||||
|
||||
batch_execute(commands=commands, fail_fast=False)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Recovery Patterns
|
||||
|
||||
### Stale File Recovery
|
||||
|
||||
```python
|
||||
try:
|
||||
apply_text_edits(uri=script_uri, edits=[...], precondition_sha256=old_sha)
|
||||
except Exception as e:
|
||||
if "stale_file" in str(e):
|
||||
# Re-fetch SHA
|
||||
new_sha = get_sha(uri=script_uri)
|
||||
# Retry with new SHA
|
||||
apply_text_edits(uri=script_uri, edits=[...], precondition_sha256=new_sha["sha256"])
|
||||
```
|
||||
|
||||
### Domain Reload Recovery
|
||||
|
||||
```python
|
||||
# After domain reload, connection may be lost
|
||||
# Wait and retry pattern:
|
||||
import time
|
||||
|
||||
max_retries = 5
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
editor_state = read_resource("mcpforunity://editor/state")
|
||||
if editor_state["ready_for_tools"]:
|
||||
break
|
||||
except:
|
||||
time.sleep(2 ** attempt) # Exponential backoff
|
||||
```
|
||||
|
||||
### Compilation Block Recovery
|
||||
|
||||
```python
|
||||
# If tools fail due to compilation:
|
||||
# 1. Check console for errors
|
||||
errors = read_console(types=["error"], count=20)
|
||||
|
||||
# 2. Fix the script errors
|
||||
# ... edit scripts ...
|
||||
|
||||
# 3. Force refresh
|
||||
refresh_unity(mode="force", scope="scripts", compile="request", wait_for_ready=True)
|
||||
|
||||
# 4. Verify clean console
|
||||
errors = read_console(types=["error"], count=5)
|
||||
if not errors["messages"]:
|
||||
# Safe to proceed with tools
|
||||
pass
|
||||
```
|
||||
Loading…
Reference in New Issue