chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:49:17 +08:00
commit 7243d5823b
2201 changed files with 257291 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
---
id: claude-code-cli
slug: /guides/claude-code-cli
title: Install or Repair Claude Code CLI
sidebar_label: Claude Code CLI
description: Install or repair the Claude Code CLI (claude) so MCP for Unity can launch it.
---
# Install or Repair Claude Code CLI
You need the Claude Code CLI (`claude`) available on your system.
:::caution Switching transport requires a restart
If you change from `http` to `stdio` (or vice versa) in the MCP for Unity window, **restart Claude Code** for it to pick up the change.
:::
## Recommended (native installers)
**macOS / Linux / WSL:**
```bash
curl -fsSL https://claude.ai/install.sh | bash
claude doctor
```
**Windows PowerShell:**
```powershell
irm https://claude.ai/install.ps1 | iex
claude doctor
```
## Alternative: npm via NVM (installs under `~/.nvm`)
```bash
# Install / select a Node version
nvm install v21.7.1
nvm use v21.7.1
# Install Claude Code CLI into this Node's global prefix
npm install -g @anthropic-ai/claude-code
# Verify it's under NVM
which claude
claude --version
```
## Alternative: npm with system / Homebrew Node
```bash
# If you don't have Node yet (macOS):
brew install node
# Install Claude Code CLI globally
npm install -g @anthropic-ai/claude-code
# Verify it's on PATH (typical: /opt/homebrew/bin/claude or /usr/local/bin/claude)
which claude
claude --version
```
## macOS PATH gotcha
On macOS, Unity launched from Finder / Hub may not inherit your shell PATH. If `claude` isn't found:
- **Either** launch Hub from Terminal (so PATH propagates),
- **or** use the MCP for Unity window's **"Choose Claude Install Location"** to set the absolute path.
## Related troubleshooting
- macOS dyld ICU library errors: see [Common Setup Problems → macOS Claude CLI dyld error](/guides/troubleshooting#macos-claude-cli-fails-to-start-dyld-icu-library-not-loaded)
- "Claude Not Found" in the Register button: see the FAQ in [Common Setup Problems](/guides/troubleshooting#faq--claude-code)
+252
View File
@@ -0,0 +1,252 @@
---
title: CLI Examples
sidebar_label: CLI Examples
description: Worked examples of using MCP for Unity in CLI mode.
---
# Unity MCP (CLI Mode)
We use Unity MCP via **CLI commands** instead of MCP server connection. This avoids the reconnection issues that occur when Unity restarts.
### Why CLI Instead of MCP Connection?
- MCP connection breaks when Unity restarts
- `/mcp reconnect` requires human intervention
- CLI works directly via HTTP to the MCP server - no persistent connection needed
- Claude can call CLI commands autonomously without reconnection issues
### Installation
```bash
cd Server # In unity-mcp repo
pip install -e .
# Or with uv:
uv pip install -e .
```
### Global Options
| Option | Description | Default | Env Variable |
|--------|-------------|---------|--------------|
| `-h, --host` | Server host | 127.0.0.1 | `UNITY_MCP_HOST` |
| `-p, --port` | Server port | 8080 | `UNITY_MCP_HTTP_PORT` |
| `-t, --timeout` | Timeout seconds | 30 | `UNITY_MCP_TIMEOUT` |
| `-f, --format` | Output: text, json, table | text | `UNITY_MCP_FORMAT` |
| `-i, --instance` | Target Unity instance | - | `UNITY_MCP_INSTANCE` |
### Core CLI Commands
**Status & Connection**
```bash
unity-mcp status # Check server + Unity connection
```
**Instance Management**
```bash
unity-mcp instance list # List connected Unity instances
unity-mcp instance set "ProjectName@abc" # Set active instance
unity-mcp instance current # Show current instance
```
**Editor Control**
```bash
unity-mcp editor play|pause|stop # Control play mode
unity-mcp editor console [--clear] # Get/clear console logs
unity-mcp editor refresh [--compile] # Refresh assets
unity-mcp editor menu "Edit/Project Settings..." # Execute menu item
unity-mcp editor add-tag "TagName" # Add tag
unity-mcp editor add-layer "LayerName" # Add layer
unity-mcp editor tests --mode PlayMode [--async]
unity-mcp editor poll-test <job_id> [--wait 60] [--details]
unity-mcp --instance "MyProject@abc123" editor play # Target a specific instance
```
**Custom Tools**
```bash
unity-mcp tool list
unity-mcp custom_tool list
unity-mcp editor custom-tool "bake_lightmaps"
unity-mcp editor custom-tool "capture_screenshot" --params '{"filename":"shot_01","width":1920,"height":1080}'
```
**Scene Operations**
```bash
unity-mcp scene hierarchy [--limit 20] [--depth 3]
unity-mcp scene active
unity-mcp scene load "Assets/Scenes/Main.unity"
unity-mcp scene save
unity-mcp --format json scene hierarchy
```
**Screenshots** (via `camera` command):
```bash
unity-mcp camera screenshot --file-name "capture"
unity-mcp camera screenshot --camera-ref "MainCam" --include-image --max-resolution 512
unity-mcp camera screenshot --batch surround --max-resolution 256
unity-mcp camera screenshot --batch orbit --view-target "Player"
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
**GameObject Operations**
```bash
unity-mcp gameobject find "Name" [--method by_tag|by_name|by_layer|by_component]
unity-mcp gameobject create "Name" [--primitive Cube] [--position X Y Z]
unity-mcp gameobject modify "Name" [--position X Y Z] [--rotation X Y Z]
unity-mcp gameobject delete "Name" [--force]
unity-mcp gameobject duplicate "Name"
```
**Component Operations**
```bash
unity-mcp component add "GameObject" ComponentType
unity-mcp component remove "GameObject" ComponentType
unity-mcp component set "GameObject" Component property value
```
**Script Operations**
```bash
unity-mcp script create "ScriptName" --path "Assets/Scripts"
unity-mcp script read "Assets/Scripts/File.cs"
unity-mcp script delete "Assets/Scripts/File.cs" [--force]
unity-mcp code search "pattern" "path/to/file.cs" [--max-results 20]
```
**Asset Operations**
```bash
unity-mcp asset search --pattern "*.mat" --path "Assets/Materials"
unity-mcp asset info "Assets/Materials/File.mat"
unity-mcp asset mkdir "Assets/NewFolder"
unity-mcp asset move "Old/Path" "New/Path"
```
**Prefab Operations**
```bash
unity-mcp prefab open "Assets/Prefabs/File.prefab"
unity-mcp prefab save
unity-mcp prefab close
unity-mcp prefab create "GameObject" --path "Assets/Prefabs"
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --delete-child Child1
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --target Weapon --position "0,1,2"
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --set-property "Rigidbody.mass=5"
```
**Material Operations**
```bash
unity-mcp material create "Assets/Materials/File.mat"
unity-mcp material set-color "File.mat" R G B
unity-mcp material assign "File.mat" "GameObject"
```
**Shader Operations**
```bash
unity-mcp shader create "Name" --path "Assets/Shaders"
unity-mcp shader read "Assets/Shaders/Custom.shader"
unity-mcp shader update "Assets/Shaders/Custom.shader" --file local.shader
unity-mcp shader delete "Assets/Shaders/File.shader" [--force]
```
**VFX Operations**
```bash
unity-mcp vfx particle info|play|stop|pause|restart|clear "Name"
unity-mcp vfx line info "Name"
unity-mcp vfx line create-line "Name" --start X Y Z --end X Y Z
unity-mcp vfx line create-circle "Name" --radius N
unity-mcp vfx trail info|set-time|clear "Name" [time]
```
**Camera Operations**
```bash
unity-mcp camera ping # Check Cinemachine
unity-mcp camera list # List all cameras
unity-mcp camera create --name "Cam" --preset follow --follow "Player"
unity-mcp camera set-target "Cam" --follow "Player" --look-at "Enemy"
unity-mcp camera set-lens "Cam" --fov 60 --near 0.1
unity-mcp camera set-priority "Cam" --priority 15
unity-mcp camera set-body "Cam" --body-type "CinemachineFollow"
unity-mcp camera set-aim "Cam" --aim-type "CinemachineRotationComposer"
unity-mcp camera set-noise "Cam" --amplitude 1.5 --frequency 0.5
unity-mcp camera ensure-brain --blend-style "EaseInOut" --blend-duration 1.5
unity-mcp camera force "Cam" # Force Brain to use camera
unity-mcp camera release # Release override
```
**Graphics Operations**
```bash
# Volumes
unity-mcp graphics volume-create --name "PostFX" --global
unity-mcp graphics volume-add-effect --target "PostFX" --effect "Bloom"
unity-mcp graphics volume-set-effect --target "PostFX" --effect "Bloom" -p intensity 1.5
unity-mcp graphics volume-info --target "PostFX"
# Pipeline
unity-mcp graphics pipeline-info
unity-mcp graphics pipeline-set-quality --level "High"
# Baking
unity-mcp graphics bake-start [--sync]
unity-mcp graphics bake-status
unity-mcp graphics bake-create-probes --spacing 5
# Stats
unity-mcp graphics stats
unity-mcp graphics stats-memory
# URP Features
unity-mcp graphics feature-list
unity-mcp graphics feature-add --type "ScreenSpaceAmbientOcclusion"
# Skybox
unity-mcp graphics skybox-info
unity-mcp graphics skybox-set-fog --enable --mode ExponentialSquared --density 0.02
unity-mcp graphics skybox-set-sun --target "DirectionalLight"
```
**Package Operations**
```bash
unity-mcp packages list # List installed
unity-mcp packages search "cinemachine" # Search registry
unity-mcp packages info "com.unity.cinemachine" # Details
unity-mcp packages add "com.unity.cinemachine" # Install
unity-mcp packages add "com.unity.cinemachine@4.1.1" # Specific version
unity-mcp packages remove "com.unity.cinemachine" [--force]
unity-mcp packages embed "com.unity.cinemachine" # Local editing
unity-mcp packages resolve # Re-resolve
unity-mcp packages list-registries
unity-mcp packages add-registry "Name" --url URL -s "com.example"
```
**Texture Operations**
```bash
unity-mcp texture create "Assets/Textures/Red.png" --color "1,0,0,1"
unity-mcp texture create "Assets/Textures/Check.png" --pattern checkerboard --width 256 --height 256
unity-mcp texture sprite "Assets/Sprites/Player.png" --width 32 --height 32 --ppu 16
unity-mcp texture modify "Assets/Textures/Img.png" --set-pixels '{"x":0,"y":0,"width":16,"height":16,"color":[1,0,0,1]}'
unity-mcp texture delete "Assets/Textures/Old.png" [--force]
```
**Lighting & UI**
```bash
unity-mcp lighting create "Name" --type Point|Spot [--intensity N] [--position X Y Z]
unity-mcp ui create-canvas "Name"
unity-mcp ui create-text "Name" --parent "Canvas" --text "Content"
unity-mcp ui create-button "Name" --parent "Canvas" --text "Label"
```
**Batch Operations**
```bash
unity-mcp batch run commands.json [--parallel] [--fail-fast]
unity-mcp batch inline '[{"tool": "manage_scene", "params": {...}}]'
unity-mcp batch template > commands.json
```
**Raw Access (Any Tool)**
```bash
unity-mcp raw tool_name 'JSON_params'
unity-mcp raw manage_scene '{"action":"get_active"}'
unity-mcp raw manage_camera '{"action":"screenshot","include_image":true}'
unity-mcp raw manage_graphics '{"action":"volume_get_info","target":"PostProcessing"}'
unity-mcp raw manage_packages '{"action":"list_packages"}'
```
### Note on MCP Server
The MCP HTTP server still needs to be running for CLI to work. Here is an example to run the server manually on Mac:
```bash
/opt/homebrew/bin/uvx --no-cache --refresh --from /XXX/unity-mcp/Server mcp-for-unity --transport http --http-url http://localhost:8080
```
+560
View File
@@ -0,0 +1,560 @@
# Unity MCP CLI Usage Guide
The Unity MCP CLI provides command-line access to control the Unity Editor through the Model Context Protocol. It currently only supports local HTTP.
Note: Some tools are still experimental and might fail under some circumstances. Please submit an issue to help us make it better.
## Installation
```bash
cd Server
pip install -e .
# Or with uv:
uv pip install -e .
```
## Quick Start
```bash
# Check connection
unity-mcp status
# List Unity instances
unity-mcp instance list
# Get scene hierarchy
unity-mcp scene hierarchy
# Find a GameObject
unity-mcp gameobject find "Player"
```
## Global Options
| Option | Env Variable | Description |
|--------|--------------|-------------|
| `-h, --host` | `UNITY_MCP_HOST` | Server host (default: 127.0.0.1) |
| `-p, --port` | `UNITY_MCP_HTTP_PORT` | Server port (default: 8080) |
| `-t, --timeout` | `UNITY_MCP_TIMEOUT` | Timeout in seconds (default: 30) |
| `-f, --format` | `UNITY_MCP_FORMAT` | Output format: text, json, table |
| `-i, --instance` | `UNITY_MCP_INSTANCE` | Target Unity instance |
## Command Reference
### Instance Management
```bash
# List connected Unity instances
unity-mcp instance list
# Set active instance
unity-mcp instance set "ProjectName@abc123"
# Show current instance
unity-mcp instance current
```
### Scene Operations
```bash
# Get scene hierarchy
unity-mcp scene hierarchy
unity-mcp scene hierarchy --limit 20 --depth 3
# Get active scene info
unity-mcp scene active
# Load/save scenes
unity-mcp scene load "Assets/Scenes/Main.unity"
unity-mcp scene save
# Screenshots (use camera command)
unity-mcp camera screenshot
unity-mcp camera screenshot --file-name "level_preview"
unity-mcp camera screenshot --camera-ref "SecondCamera" --include-image
unity-mcp camera screenshot --batch surround --max-resolution 256
unity-mcp camera screenshot --batch orbit --view-target "Player"
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
### GameObject Operations
```bash
# Find GameObjects
unity-mcp gameobject find "Player"
unity-mcp gameobject find "Enemy" --method by_tag
# Create GameObjects
unity-mcp gameobject create "NewCube" --primitive Cube
unity-mcp gameobject create "Empty" --position 0 5 0
# Modify GameObjects
unity-mcp gameobject modify "Cube" --position 1 2 3 --rotation 0 45 0
# Delete/duplicate
unity-mcp gameobject delete "OldObject" --force
unity-mcp gameobject duplicate "Template"
```
### Component Operations
```bash
# Add component
unity-mcp component add "Player" Rigidbody
# Remove component
unity-mcp component remove "Player" Rigidbody
# Set property
unity-mcp component set "Player" Rigidbody mass 10
```
### Script Operations
```bash
# Create script
unity-mcp script create "PlayerController" --path "Assets/Scripts"
# Read script
unity-mcp script read "Assets/Scripts/Player.cs"
# Delete script
unity-mcp script delete "Assets/Scripts/Old.cs" --force
```
### Code Search
```bash
# Search with regex
unity-mcp code search "class.*Player" "Assets/Scripts/Player.cs"
unity-mcp code search "TODO|FIXME" "Assets/Scripts/Utils.cs"
unity-mcp code search "void Update" "Assets/Scripts/Game.cs" --max-results 20
```
### Shader Operations
```bash
# Create shader
unity-mcp shader create "MyShader" --path "Assets/Shaders"
# Read shader
unity-mcp shader read "Assets/Shaders/Custom.shader"
# Update from file
unity-mcp shader update "Assets/Shaders/Custom.shader" --file local.shader
# Delete shader
unity-mcp shader delete "Assets/Shaders/Old.shader" --force
```
### Editor Controls
```bash
# Play mode
unity-mcp editor play
unity-mcp editor pause
unity-mcp editor stop
# Refresh assets
unity-mcp editor refresh
unity-mcp editor refresh --compile
# Console
unity-mcp editor console
unity-mcp editor console --clear
# Tags and layers
unity-mcp editor add-tag "Enemy"
unity-mcp editor add-layer "Projectiles"
# Menu items
unity-mcp editor menu "Edit/Project Settings..."
# Custom tools
unity-mcp editor custom-tool "MyBuildTool"
unity-mcp editor custom-tool "Deploy" --params '{"target": "Android"}'
# List custom tools for the active Unity project
unity-mcp tool list
unity-mcp custom_tool list
```
#### Screenshot Parameters
| Option | Type | Description |
|--------|------|-------------|
| `--filename, -f` | string | Output filename (default: timestamp-based) |
| `--supersize, -s` | int | Resolution multiplier 14 for file-saved screenshots |
| `--camera-ref` | string | Camera name/path/ID (default: Camera.main) |
| `--include-image` | flag | Return base64 PNG inline in the response |
| `--max-resolution, -r` | int | Max longest-edge pixels (default 640) |
| `--batch, -b` | string | `surround` (6 angles) or `orbit` (configurable grid) |
| `--capture-source` | string | `game_view` (default) or `scene_view` (editor viewport) |
| `--view-target` | string | Target to focus on: GO name/path/ID, or `x,y,z`. Aims camera (game_view) or frames viewport (scene_view) |
| `--view-position` | string | Camera position as `x,y,z` (positioned screenshot, game_view only) |
| `--view-rotation` | string | Camera euler rotation as `x,y,z` (positioned screenshot, game_view only) |
| `--orbit-angles` | int | Number of azimuth steps around target (default 8) |
| `--orbit-elevations` | string | Vertical angles as JSON array, e.g. `[0,30,-15]` (default `[0, 30, -15]`) |
| `--orbit-distance` | float | Camera distance from target in world units (auto-fit if omitted) |
| `--orbit-fov` | float | Camera FOV in degrees (default 60) |
| `--output-dir, -o` | string | Save directory (default: Unity project's `Assets/Screenshots/`) |
### Testing
```bash
# Run tests synchronously
unity-mcp editor tests --mode EditMode
# Run tests asynchronously
unity-mcp editor tests --mode PlayMode --async
# Poll test job
unity-mcp editor poll-test <job_id>
unity-mcp editor poll-test <job_id> --wait 60 --details
```
### Material Operations
```bash
# Create material
unity-mcp material create "Assets/Materials/Red.mat"
# Set color
unity-mcp material set-color "Assets/Materials/Red.mat" 1 0 0
# Assign to object
unity-mcp material assign "Assets/Materials/Red.mat" "Cube"
```
### VFX Operations
Note: VFX Graph tooling is tested against com.unity.visualeffectgraph 12.1.13. Install VFX Graph and use URP/HDRP (set the Render Pipeline Asset) to avoid Unity warnings; other versions may be unsupported.
```bash
# Particle systems
unity-mcp vfx particle info "Fire"
unity-mcp vfx particle play "Fire" --with-children
unity-mcp vfx particle stop "Fire"
# Line renderers
unity-mcp vfx line info "LaserBeam"
unity-mcp vfx line create-line "Line" --start 0 0 0 --end 10 5 0
unity-mcp vfx line create-circle "Circle" --radius 5
# Trail renderers
unity-mcp vfx trail info "PlayerTrail"
unity-mcp vfx trail set-time "Trail" 2.0
# Raw VFX actions (access all 60+ actions)
unity-mcp vfx raw particle_set_main "Fire" --params '{"duration": 5}'
```
### ProBuilder Operations
Note: Requires com.unity.probuilder package installed in your Unity project.
```bash
# Create shapes
unity-mcp probuilder create-shape Cube
unity-mcp probuilder create-shape Torus --name "MyTorus" --params '{"rows": 16, "columns": 16}'
unity-mcp probuilder create-shape Stair --position 0 0 5 --params '{"steps": 10}'
# Create from polygon footprint
unity-mcp probuilder create-poly --points "[[0,0,0],[5,0,0],[5,0,5],[0,0,5]]" --height 3
# Get mesh info
unity-mcp probuilder info "MyCube"
# Raw ProBuilder actions
unity-mcp probuilder raw extrude_faces "MyCube" --params '{"faceIndices": [0], "distance": 1.0}'
unity-mcp probuilder raw bevel_edges "MyCube" --params '{"edgeIndices": [0,1], "amount": 0.2}'
unity-mcp probuilder raw set_face_material "MyCube" --params '{"faceIndices": [0], "materialPath": "Assets/Materials/Red.mat"}'
```
### Batch Operations
```bash
# Execute from JSON file
unity-mcp batch run commands.json
unity-mcp batch run commands.json --parallel --fail-fast
# Execute inline JSON
unity-mcp batch inline '[{"tool": "manage_scene", "params": {"action": "get_active"}}]'
# Generate template
unity-mcp batch template > my_commands.json
```
### Prefab Operations
```bash
# Open prefab for editing
unity-mcp prefab open "Assets/Prefabs/Player.prefab"
# Save and close
unity-mcp prefab save
unity-mcp prefab close
# Create from GameObject
unity-mcp prefab create "Player" --path "Assets/Prefabs"
# Modify prefab contents (headless, no UI)
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --target Weapon --position "0,1,2"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --delete-child Child1 --delete-child "Turret/Barrel"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --set-property "Rigidbody.mass=5"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --add-component BoxCollider
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --create-child '{"name":"Spawn","primitive_type":"Sphere"}'
```
### Asset Operations
```bash
# Search assets
unity-mcp asset search --pattern "*.mat" --path "Assets/Materials"
# Get asset info
unity-mcp asset info "Assets/Materials/Red.mat"
# Create folder
unity-mcp asset mkdir "Assets/NewFolder"
# Move/rename
unity-mcp asset move "Assets/Old.mat" "Assets/Materials/"
```
### Animation Operations
```bash
# Play animation state
unity-mcp animation play "Player" "Run"
# Set animator parameter
unity-mcp animation set-parameter "Player" Speed 1.5
unity-mcp animation set-parameter "Player" IsRunning true
```
### Audio Operations
```bash
# Play audio
unity-mcp audio play "AudioPlayer"
# Stop audio
unity-mcp audio stop "AudioPlayer"
# Set volume
unity-mcp audio volume "AudioPlayer" 0.5
```
### Lighting Operations
```bash
# Create light
unity-mcp lighting create "NewLight" --type Point --position 0 5 0
unity-mcp lighting create "Spotlight" --type Spot --intensity 2
```
### UI Operations
```bash
# Create canvas
unity-mcp ui create-canvas "MainCanvas"
# Create text
unity-mcp ui create-text "Title" --parent "MainCanvas" --text "Hello World"
# Create button
unity-mcp ui create-button "StartBtn" --parent "MainCanvas" --text "Start"
# Create image
unity-mcp ui create-image "Background" --parent "MainCanvas"
```
### Camera Operations
```bash
unity-mcp camera ping # Check Cinemachine availability
unity-mcp camera list # List all cameras
unity-mcp camera create --name "Cam" --preset follow --follow "Player"
unity-mcp camera set-target "Cam" --follow "Player" --look-at "Enemy"
unity-mcp camera set-lens "Cam" --fov 60 --near 0.1 --far 1000
unity-mcp camera set-priority "Cam" --priority 15
unity-mcp camera set-body "Cam" --body-type "CinemachineFollow"
unity-mcp camera set-aim "Cam" --aim-type "CinemachineRotationComposer"
unity-mcp camera set-noise "Cam" --amplitude 1.5 --frequency 0.5
unity-mcp camera add-extension "Cam" CinemachineConfiner3D
unity-mcp camera ensure-brain --blend-style "EaseInOut" --blend-duration 1.5
unity-mcp camera brain-status
unity-mcp camera force "Cam" # Force Brain to use camera
unity-mcp camera release # Release override
unity-mcp camera screenshot --file-name "capture" --super-size 2
unity-mcp camera screenshot --batch orbit --view-target "Player" --max-resolution 256
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
### Graphics Operations
```bash
# Volumes
unity-mcp graphics volume-create --name "PostFX" --global
unity-mcp graphics volume-add-effect --target "PostFX" --effect "Bloom"
unity-mcp graphics volume-set-effect --target "PostFX" --effect "Bloom" -p intensity 1.5
unity-mcp graphics volume-info --target "PostFX"
unity-mcp graphics volume-list-effects
# Render Pipeline
unity-mcp graphics pipeline-info
unity-mcp graphics pipeline-set-quality --level "High"
unity-mcp graphics pipeline-set-settings -s renderScale 1.5
# Light Baking
unity-mcp graphics bake-start [--sync]
unity-mcp graphics bake-status
unity-mcp graphics bake-cancel
unity-mcp graphics bake-settings
unity-mcp graphics bake-create-probes --spacing 5
unity-mcp graphics bake-create-reflection --resolution 512
# Stats & Debug
unity-mcp graphics stats
unity-mcp graphics stats-memory
unity-mcp graphics stats-debug-mode --mode "Wireframe"
# URP Renderer Features
unity-mcp graphics feature-list
unity-mcp graphics feature-add --type "ScreenSpaceAmbientOcclusion"
unity-mcp graphics feature-configure --name "SSAO" -p Intensity 1.5
unity-mcp graphics feature-toggle --name "SSAO" --active|--inactive
# Skybox & Environment
unity-mcp graphics skybox-info
unity-mcp graphics skybox-set-material --material "Assets/Materials/Sky.mat"
unity-mcp graphics skybox-set-ambient --mode Flat --color "0.2,0.2,0.3"
unity-mcp graphics skybox-set-fog --enable --mode ExponentialSquared --density 0.02
unity-mcp graphics skybox-set-reflection --intensity 1.0 --bounces 2
unity-mcp graphics skybox-set-sun --target "DirectionalLight"
```
### Package Operations
```bash
unity-mcp packages ping # Check package manager
unity-mcp packages list # List installed packages
unity-mcp packages search "cinemachine" # Search registry
unity-mcp packages info "com.unity.cinemachine" # Package details
unity-mcp packages add "com.unity.cinemachine" # Install package
unity-mcp packages add "com.unity.cinemachine@4.1.1" # Specific version
unity-mcp packages remove "com.unity.cinemachine" [--force]
unity-mcp packages embed "com.unity.cinemachine" # Embed for local editing
unity-mcp packages resolve # Force re-resolution
unity-mcp packages status <job_id> # Check async op
unity-mcp packages list-registries
unity-mcp packages add-registry "Name" --url URL -s "com.example"
unity-mcp packages remove-registry "Name"
```
### Texture Operations
```bash
unity-mcp texture create "Assets/Textures/Red.png" --color "1,0,0,1"
unity-mcp texture create "Assets/Textures/Check.png" --pattern checkerboard --width 256 --height 256
unity-mcp texture create "Assets/Textures/Img.png" --image-path "/path/to/source.png"
unity-mcp texture sprite "Assets/Sprites/Player.png" --width 32 --height 32 --ppu 16
unity-mcp texture modify "Assets/Textures/Img.png" --set-pixels '{"x":0,"y":0,"width":16,"height":16,"color":[1,0,0,1]}'
unity-mcp texture delete "Assets/Textures/Old.png" [--force]
# Patterns: checkerboard, stripes, stripes_h, stripes_v, stripes_diag, dots, grid, brick
```
### Raw Commands
For any MCP tool not covered by dedicated commands:
```bash
unity-mcp raw manage_scene '{"action": "get_hierarchy", "max_nodes": 100}'
unity-mcp raw read_console '{"count": 20}'
unity-mcp raw manage_camera '{"action": "screenshot", "include_image": true}'
unity-mcp raw manage_graphics '{"action": "volume_get_info", "target": "PostProcessing"}'
unity-mcp raw manage_packages '{"action": "list_packages"}'
```
---
## Complete Command Reference
| Group | Subcommands |
|-------|-------------|
| `instance` | `list`, `set`, `current` |
| `scene` | `hierarchy`, `active`, `load`, `save`, `create`, `build-settings` |
| `code` | `read`, `search` |
| `gameobject` | `find`, `create`, `modify`, `delete`, `duplicate`, `move` |
| `component` | `add`, `remove`, `set`, `modify` |
| `script` | `create`, `read`, `delete`, `edit`, `validate` |
| `shader` | `create`, `read`, `update`, `delete` |
| `editor` | `play`, `pause`, `stop`, `refresh`, `console`, `menu`, `tool`, `add-tag`, `remove-tag`, `add-layer`, `remove-layer`, `tests`, `poll-test`, `custom-tool` |
| `asset` | `search`, `info`, `create`, `delete`, `duplicate`, `move`, `rename`, `import`, `mkdir` |
| `prefab` | `open`, `close`, `save`, `create`, `modify` |
| `material` | `info`, `create`, `set-color`, `set-property`, `assign`, `set-renderer-color` |
| `camera` | `ping`, `list`, `create`, `set-target`, `set-lens`, `set-priority`, `set-body`, `set-aim`, `set-noise`, `add-extension`, `remove-extension`, `ensure-brain`, `brain-status`, `set-blend`, `force`, `release`, `screenshot`, `screenshot-multiview` |
| `graphics` | `ping`, `volume-create`, `volume-add-effect`, `volume-set-effect`, `volume-remove-effect`, `volume-info`, `volume-set-properties`, `volume-list-effects`, `volume-create-profile`, `pipeline-info`, `pipeline-settings`, `pipeline-set-quality`, `pipeline-set-settings`, `bake-start`, `bake-cancel`, `bake-status`, `bake-clear`, `bake-settings`, `bake-set-settings`, `bake-reflection-probe`, `bake-create-probes`, `bake-create-reflection`, `stats`, `stats-memory`, `stats-debug-mode`, `feature-list`, `feature-add`, `feature-remove`, `feature-configure`, `feature-reorder`, `feature-toggle`, `skybox-info`, `skybox-set-material`, `skybox-set-properties`, `skybox-set-ambient`, `skybox-set-fog`, `skybox-set-reflection`, `skybox-set-sun` |
| `packages` | `ping`, `list`, `search`, `info`, `add`, `remove`, `embed`, `resolve`, `status`, `list-registries`, `add-registry`, `remove-registry` |
| `texture` | `create`, `sprite`, `modify`, `delete` |
| `vfx particle` | `info`, `play`, `stop`, `pause`, `restart`, `clear` |
| `vfx line` | `info`, `set-positions`, `create-line`, `create-circle`, `clear` |
| `vfx trail` | `info`, `set-time`, `clear` |
| `vfx` | `raw` (access all 60+ actions) |
| `probuilder` | `create-shape`, `create-poly`, `info`, `raw` (access all 35+ actions) |
| `batch` | `run`, `inline`, `template` |
| `animation` | `play`, `set-parameter` |
| `audio` | `play`, `stop`, `volume` |
| `lighting` | `create` |
| `tool` | `list` |
| `custom_tool` | `list` |
| `ui` | `create-canvas`, `create-text`, `create-button`, `create-image` |
---
## Output Formats
```bash
# Text (default) - human readable
unity-mcp scene hierarchy
# JSON - for scripting
unity-mcp --format json scene hierarchy
# Table - structured display
unity-mcp --format table instance list
```
## Environment Variables
Set defaults via environment:
```bash
export UNITY_MCP_HOST=192.168.1.100
export UNITY_MCP_HTTP_PORT=8080
export UNITY_MCP_FORMAT=json
export UNITY_MCP_INSTANCE=MyProject@abc123
```
## Troubleshooting
### Connection Issues
```bash
# Check server status
unity-mcp status
# Verify Unity is running with MCP plugin
# Check Unity console for MCP connection messages
```
### Common Errors
| Error | Solution |
|-------|----------|
| Cannot connect to server | Ensure Unity MCP server is running |
| Unknown command type | Unity plugin may not support this tool |
| Timeout | Increase timeout with `-t 60` |
+300
View File
@@ -0,0 +1,300 @@
# MCP Client Configurators
This guide explains how MCP client configurators work in this repo and how to add a new one.
It covers:
- **Typical JSON-file clients** (Cursor, VSCode GitHub Copilot, VSCode Insiders, GitHub Copilot CLI, Windsurf, Kiro, Trae, Antigravity 2.0, Antigravity IDE, etc.).
- **Special clients** like **Claude CLI**, **Codex**, and **OpenClaw** that require custom logic.
- **How to add a new configurator class** so it shows up automatically in the MCP for Unity window.
## Quick example: JSON-file configurator
For most clients you just need a small class like this:
```csharp
using System;
using System.Collections.Generic;
using System.IO;
using MCPForUnity.Editor.Models;
namespace MCPForUnity.Editor.Clients.Configurators
{
public class MyClientConfigurator : JsonFileMcpConfigurator
{
public MyClientConfigurator() : base(new McpClient
{
name = "My Client",
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
})
{ }
public override IList<string> GetInstallationSteps() => new List<string>
{
"Open My Client and go to MCP settings",
"Open or create the mcp.json file at the path above",
"Click Configure in MCP for Unity (or paste the manual JSON snippet)",
"Restart My Client"
};
}
}
```
---
## How the configurator system works
At a high level:
- **`IMcpClientConfigurator`** (`MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs`)
- Contract for all MCP client configurators.
- Handles status detection, auto-configure, manual snippet, and installation steps.
- **Base classes** (`MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs`)
- **`McpClientConfiguratorBase`**
- Common properties and helpers.
- **`JsonFileMcpConfigurator`**
- For JSON-based config files (most clients).
- Implements `CheckStatus`, `Configure`, and `GetManualSnippet` using `ConfigJsonBuilder`.
- **`CodexMcpConfigurator`**
- For Codex-style TOML config files.
- **`ClaudeCliMcpConfigurator`**
- For CLI-driven clients like Claude Code (register/unregister via CLI, not JSON files).
- **`McpClient` model** (`MCPForUnity/Editor/Models/McpClient.cs`)
- Holds the per-client configuration:
- `name`
- `windowsConfigPath`, `macConfigPath`, `linuxConfigPath`
- Status and several **JSON-config flags** (used by `JsonFileMcpConfigurator`):
- `IsVsCodeLayout` VS Code-style layout (`servers` root, `type` field, etc.).
- `SupportsHttpTransport` whether the client supports HTTP transport.
- `EnsureEnvObject` ensure an `env` object exists.
- `StripEnvWhenNotRequired` remove `env` when not needed.
- `HttpUrlProperty` which property holds the HTTP URL (e.g. `"url"` vs `"serverUrl"`).
- `DefaultUnityFields` key/value pairs like `{ "disabled": false }` applied when missing.
- **Auto-discovery** (`McpClientRegistry`)
- `McpClientRegistry.All` uses `TypeCache.GetTypesDerivedFrom<IMcpClientConfigurator>()` to find configurators.
- A configurator appears automatically if:
- It is a **public, non-abstract class**.
- It has a **public parameterless constructor**.
- No extra registration list is required.
---
## Typical JSON-file clients
Most MCP clients use a JSON config file that defines one or more MCP servers. Examples:
- **Cursor** `JsonFileMcpConfigurator` (global `~/.cursor/mcp.json`).
- **VSCode GitHub Copilot** `JsonFileMcpConfigurator` with `IsVsCodeLayout = true`.
- **VSCode Insiders GitHub Copilot** `JsonFileMcpConfigurator` with `IsVsCodeLayout = true` and Insider-specific `Code - Insiders/User/mcp.json` paths.
- **GitHub Copilot CLI** `JsonFileMcpConfigurator` with standard HTTP transport.
- **Windsurf** `JsonFileMcpConfigurator` with Windsurf-specific flags (`HttpUrlProperty = "serverUrl"`, `DefaultUnityFields["disabled"] = false`, etc.).
- **Kiro**, **Trae**, **Antigravity 2.0** (`~/.gemini/config/mcp_config.json` after the 2.x migration), **Antigravity IDE** (separate `~/.gemini/antigravity-ide/mcp_config.json` — the IDE build did not migrate) JSON configs with project-specific paths and flags.
All of these follow the same pattern:
1. **Subclass `JsonFileMcpConfigurator`.**
2. **Provide a `McpClient` instance** in the constructor with:
- A user-friendly `name`.
- OS-specific config paths.
- Any JSON behavior flags as needed.
3. **Override `GetInstallationSteps`** to describe how users open or edit the config.
4. Rely on **base implementations** for:
- `CheckStatus` reads and validates the JSON config; can auto-rewrite to match Unity MCP.
- `Configure` writes/rewrites the config file.
- `GetManualSnippet` builds a JSON snippet using `ConfigJsonBuilder`.
### JSON behavior controlled by `McpClient`
`JsonFileMcpConfigurator` relies on the fields on `McpClient`:
- **HTTP vs stdio**
- `SupportsHttpTransport` + `EditorPrefs.UseHttpTransport` decide whether to configure
- `url` / `serverUrl` (HTTP), or
- `command` + `args` (stdio with `uvx`).
- **URL property name**
- `HttpUrlProperty` (default `"url"`) selects which JSON property to use for HTTP urls.
- Example: Windsurf and the two Antigravity clients use `"serverUrl"`.
- **VS Code layout**
- `IsVsCodeLayout = true` switches config structure to a VS Code compatible layout.
- **Env object and default fields**
- `EnsureEnvObject` / `StripEnvWhenNotRequired` control an `env` block.
- `DefaultUnityFields` adds client-specific fields if they are missing (e.g. `disabled: false`).
All of this logic is centralized in **`ConfigJsonBuilder`**, so most JSON-based clients **do not need to override** `GetManualSnippet`.
---
## Special clients
Some clients cannot be handled by the generic JSON configurator alone.
### Codex (TOML-based)
- Uses **`CodexMcpConfigurator`**.
- Reads and writes a **TOML** config (usually `~/.codex/config.toml`).
- Uses `CodexConfigHelper` to:
- Parse the existing TOML.
- Check for a matching Unity MCP server configuration.
- Write/patch the Codex server block.
- The `CodexConfigurator` class:
- Only needs to supply a `McpClient` with TOML config paths.
- Inherits the Codex-specific status and configure behavior from `CodexMcpConfigurator`.
### Claude Code (CLI-based)
- Uses **`ClaudeCliMcpConfigurator`**.
- Configuration is stored **internally by the Claude CLI**, not in a JSON file.
- `CheckStatus` and `Configure` are implemented in the base class using `claude mcp ...` commands:
- `CheckStatus` calls `claude mcp list` to detect if `UnityMCP` is registered.
- `Configure` toggles register/unregister via `claude mcp add/remove UnityMCP`.
- The `ClaudeCodeConfigurator` class:
- Only needs a `McpClient` with a `name`.
- Overrides `GetInstallationSteps` with CLI-specific instructions.
### Claude Desktop (JSON with restrictions)
- Uses **`JsonFileMcpConfigurator`**, but only supports **stdio transport**.
- `ClaudeDesktopConfigurator`:
- Sets `SupportsHttpTransport = false` in `McpClient`.
- Declares `SupportedTransports => StdioOnly`. `ClientConfigurationService` reads `SupportedTransports` and, via `ConfigureWithTransportCoercion` / `CoerceTransportFor`, temporarily coerces the transport pref to stdio before calling `Configure()` — so users with HTTP toggled globally still get a working stdio entry written without a thrown error. The coercion applies to any configurator whose `SupportedTransports` excludes the user's current transport; Claude Desktop is just the only one declaring stdio-only today.
### OpenClaw (plugin-based)
- Uses a custom configurator (`OpenClawConfigurator`) because OpenClaw MCP is plugin-driven.
- Config file path is `~/.openclaw/openclaw.json`.
- Unity MCP is configured through `plugins.entries.openclaw-mcp-bridge.config.servers.unityMCP`.
- When Unity MCP is set to HTTP, the bridge expects the MCP JSON-RPC endpoint URL (`http://127.0.0.1:<port>/mcp`), not just the HTTP base URL.
- When Unity MCP is set to stdio, the configurator writes a `uvx ... mcp-for-unity --transport stdio` subprocess entry.
- The bridge exposes a single proxy tool such as `unityMCP__call`, which then forwards to Unity MCP tool names.
- OpenClaw support follows the currently selected MCP for Unity transport (via `openclaw-mcp-bridge`).
---
## Adding a new MCP client (typical JSON case)
This is the most common scenario: your MCP client uses a JSON file to configure servers.
### 1. Choose the base class
- Use **`JsonFileMcpConfigurator`** if your client reads a JSON config file.
- Consider **`CodexMcpConfigurator`** only if you are integrating a TOML-based client like Codex.
- Consider **`ClaudeCliMcpConfigurator`** only if your client exposes a CLI command to manage MCP servers.
### 2. Create the configurator class
Create a new file under:
```text
MCPForUnity/Editor/Clients/Configurators
```
Name it something like:
```text
MyClientConfigurator.cs
```
Inside, follow the existing pattern (e.g. `CursorConfigurator`, `WindsurfConfigurator`, `KiroConfigurator`):
- **Namespace** must be:
- `MCPForUnity.Editor.Clients.Configurators`
- **Class**:
- `public class MyClientConfigurator : JsonFileMcpConfigurator`
- **Constructor**:
- Public, **parameterless**, and call `base(new McpClient { ... })`.
- Set at least:
- `name = "My Client"`
- `windowsConfigPath = ...`
- `macConfigPath = ...`
- `linuxConfigPath = ...`
- Optionally set flags:
- `IsVsCodeLayout = true` for VS Code-style config.
- `HttpUrlProperty = "serverUrl"` if your client expects `serverUrl`.
- `EnsureEnvObject` / `StripEnvWhenNotRequired` based on env handling.
- `DefaultUnityFields = { { "disabled", false }, ... }` for client-specific defaults.
Because the constructor is parameterless and public, **`McpClientRegistry` will auto-discover this configurator** with no extra registration.
### 3. Add installation steps
Override `GetInstallationSteps` to tell users how to configure the client:
- Where to find or create the JSON config file.
- Which menu path opens the MCP settings.
- Whether they should rely on the **Configure** button or copy-paste the manual JSON.
Look at `CursorConfigurator`, `VSCodeConfigurator`, `VSCodeInsidersConfigurator`, `KiroConfigurator`, `TraeConfigurator`, `AntigravityConfigurator`, or `AntigravityIdeConfigurator` for phrasing.
### 4. Rely on the base JSON logic
Unless your client has very unusual behavior, you typically **do not need to override**:
- `CheckStatus`
- `Configure`
- `GetManualSnippet`
The base `JsonFileMcpConfigurator`:
- Detects missing or mismatched config.
- Optionally rewrites config to match Unity MCP.
- Builds a JSON snippet with **correct HTTP vs stdio settings**, using `ConfigJsonBuilder`.
Only override these methods if your client has constraints that cannot be expressed via `McpClient` flags.
### 5. Verify in Unity
After adding your configurator class:
1. Open Unity and the **MCP for Unity** window.
2. Your client should appear in the list, sorted by display name (`McpClient.name`).
3. Use **Check Status** to verify:
- Missing config files show as `Not Configured`.
- Existing files with matching server settings show as `Configured`.
4. Click **Configure** to auto-write the config file.
5. Restart your MCP client and confirm it connects to Unity.
---
## Adding a custom (non-JSON) client
If your MCP client doesnt store configuration as a JSON file, you likely need a custom base class.
### Codex-style TOML client
- Subclass **`CodexMcpConfigurator`**.
- Provide TOML paths via `McpClient` (similar to `CodexConfigurator`).
- Override `GetInstallationSteps` to describe how to open/edit the TOML.
The Codex-specific status and configure logic is already implemented in the base class.
### CLI-managed client (Claude-style)
- Subclass **`ClaudeCliMcpConfigurator`**.
- Provide a `McpClient` with a `name`.
- Override `GetInstallationSteps` with the CLI flow.
The base class:
- Locates the CLI binary using `MCPServiceLocator.Paths`.
- Uses `ExecPath.TryRun` to call `mcp list`, `mcp add`, and `mcp remove`.
- Implements `Configure` as a toggle between register and unregister.
Use this only if the client exposes an official CLI for managing MCP servers.
---
## Summary
- **For most MCP clients**, you only need to:
- Create a `JsonFileMcpConfigurator` subclass in `Editor/Clients/Configurators`.
- Provide a `McpClient` with paths and flags.
- Override `GetInstallationSteps`.
- **Special cases** like Codex (TOML) and Claude Code (CLI) have dedicated base classes.
- **No manual registration** is needed: `McpClientRegistry` auto-discovers all configurators with a public parameterless constructor.
Following these patterns keeps all MCP client integrations consistent and lets users configure everything from the MCP for Unity window with minimal friction.
+310
View File
@@ -0,0 +1,310 @@
# Adding Custom Tools to MCP for Unity
MCP for Unity makes it easy to extend your AI assistant with custom capabilities. Using C# attributes and reflection, the system automatically discovers and registers your tools—no manual configuration needed.
This guide will walk you through creating your own tools, from simple synchronous operations to complex long-running tasks that survive Unity's domain reloads.
---
# Quick Start Guide
Let's get you up and running with your first custom tool.
## Step 1: Create Your Tool Handler
First, create a C# file in any `Editor/` folder within your Unity project. **The Editor folder is crucial**—we scan Editor assemblies for tools, so placing your code elsewhere means it won't be discovered.
Each tool is a static class with two key ingredients:
1. The `[McpForUnityTool]` attribute that tells the system "Hey, I'm a tool!"
2. A `HandleCommand(JObject)` method that does the actual work
You can also define a nested `Parameters` class with `[ToolParameter]` attributes. This gives your AI assistant helpful descriptions and lets it know which parameters are required.
```csharp
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Tools;
namespace MyProject.Editor.CustomTools
{
[McpForUnityTool("my_custom_tool")]
public static class MyCustomTool
{
public class Parameters
{
[ToolParameter("Value to process")]
public string param1 { get; set; }
[ToolParameter("Optional integer payload", Required = false)]
public int? param2 { get; set; }
}
public static object HandleCommand(JObject @params)
{
var parameters = @params.ToObject<Parameters>();
if (string.IsNullOrEmpty(parameters.param1))
{
return new ErrorResponse("param1 is required");
}
DoSomethingAmazing(parameters.param1, parameters.param2);
return new SuccessResponse("Custom tool executed successfully!", new
{
parameters.param1,
parameters.param2
});
}
private static void DoSomethingAmazing(string param1, int? param2)
{
// Your implementation
}
}
}
```
## Step 2: Refresh Your MCP Client
Once you've created your tool, you'll need to let your AI assistant know about it. While the MCP server can dynamically register new tools, not all clients pick up these changes automatically.
**The easiest approach:** Disconnect and reconnect to the MCP server in your client. This forces a fresh tool discovery.
**If that doesn't work:** Some clients (like Windsurf) may need you to remove and reconfigure the MCP for Unity server entirely. It's a bit more work, but it guarantees your new tools will appear.
## Step 3: List and Call Your Tool from the CLI
If you want to use the CLI directly, list custom tools for the active Unity project:
```bash
unity-mcp tool list
unity-mcp custom_tool list
```
Then call your tool by name:
```bash
unity-mcp editor custom-tool "my_custom_tool"
unity-mcp editor custom-tool "my_custom_tool" --params '{"param1":"value"}'
```
## Complete Example: Screenshot Tool
### C# Handler (`Assets/Editor/ScreenShots/CaptureScreenshotTool.cs`)
```csharp
using System.IO;
using Newtonsoft.Json.Linq;
using UnityEngine;
using MCPForUnity.Editor.Tools;
using MCPForUnity.Editor.Helpers;
namespace MyProject.Editor.CustomTools
{
[McpForUnityTool(
name: "capture_screenshot",
Description = "Capture screenshots in Unity, saving them as PNGs"
)]
public static class CaptureScreenshotTool
{
// Define parameters as a nested class for clarity
public class Parameters
{
[ToolParameter("Screenshot filename without extension, e.g., screenshot_01")]
public string filename { get; set; }
[ToolParameter("Width of the screenshot in pixels", Required = false)]
public int? width { get; set; }
[ToolParameter("Height of the screenshot in pixels", Required = false)]
public int? height { get; set; }
}
public static object HandleCommand(JObject @params)
{
// Parse parameters
var parameters = @params.ToObject<Parameters>();
if (string.IsNullOrEmpty(parameters.filename))
{
return new ErrorResponse("filename is required");
}
try
{
int width = parameters.width ?? Screen.width;
int height = parameters.height ?? Screen.height;
string absolutePath = Path.Combine(Application.dataPath, "Screenshots",
parameters.filename + ".png");
Directory.CreateDirectory(Path.GetDirectoryName(absolutePath));
// Find camera
Camera camera = Camera.main ?? Object.FindFirstObjectByType<Camera>();
if (camera == null)
{
return new ErrorResponse("No camera found in the scene");
}
// Capture screenshot
RenderTexture rt = new RenderTexture(width, height, 24);
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
Texture2D screenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, width, height), 0, 0);
screenshot.Apply();
// Cleanup
camera.targetTexture = null;
RenderTexture.active = null;
Object.DestroyImmediate(rt);
// Save
byte[] bytes = screenshot.EncodeToPNG();
File.WriteAllBytes(absolutePath, bytes);
Object.DestroyImmediate(screenshot);
return new SuccessResponse($"Screenshot saved to {absolutePath}", new
{
path = absolutePath,
width = width,
height = height
});
}
catch (System.Exception ex)
{
return new ErrorResponse($"Failed to capture screenshot: {ex.Message}");
}
}
}
}
```
## Long-Running (Polled) Tools
Some operations—like running tests, baking lightmaps, or building players—take time and might even trigger Unity domain reloads. For these cases, you'll want a **polled tool**.
Here's how it works: Your tool starts the work and returns a "pending" signal. Behind the scenes, the Python middleware automatically polls Unity for updates until the job completes (or times out after 10 minutes).
### Setting Up Polling
Mark your tool with `RequiresPolling = true` and specify a `PollAction` (typically `"status"`):
```csharp
[McpForUnityTool(RequiresPolling = true, PollAction = "status")]
```
### The Three Key Ingredients
1. **Start the work:** Return `new PendingResponse("message", pollIntervalSeconds)` to acknowledge the job has started. The poll interval tells the server how long to wait between checks.
2. **Implement the poll action:** Create a method (like `Status`) that checks progress and returns `_mcp_status` of `pending`, `complete`, or `error`. **Important:** The middleware calls your `PollAction` string exactly as written—no automatic case conversion—so make sure your `HandleCommand` recognizes it.
3. **Persist your state:** Use `McpJobStateStore` to save progress to the `Library/` folder. This ensures your tool remembers what it was doing even after a domain reload wipes memory.
### Complete Example
```csharp
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Tools;
[McpForUnityTool(
"bake_lightmaps",
Description = "Simulated async lightmap bake with polling",
RequiresPolling = true,
PollAction = "status"
)]
public static class BakeLightmaps
{
private const string ToolName = "bake_lightmaps";
private const float SimulatedDurationSeconds = 5f;
private static bool s_isRunning;
private static double s_lastUpdateTime;
private class State
{
public string lastStatus { get; set; }
public float progress { get; set; }
}
public static object HandleCommand(JObject @params)
{
if (s_isRunning)
{
var existing = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "in_progress", progress = 0f };
return new PendingResponse("Bake already running", 0.5, existing);
}
var state = new State { lastStatus = "in_progress", progress = 0f };
McpJobStateStore.SaveState(ToolName, state);
s_isRunning = true;
s_lastUpdateTime = EditorApplication.timeSinceStartup;
EditorApplication.update += UpdateBake;
return new PendingResponse("Starting lightmap bake", 0.5, new { state.lastStatus, state.progress });
}
public static object Status(JObject _)
{
var state = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "unknown", progress = 0f };
if (state.lastStatus == "completed")
{
return new { _mcp_status = "complete", message = "Bake finished", data = state };
}
if (state.lastStatus == "error")
{
return new { _mcp_status = "error", error = "Bake failed", data = state };
}
return new PendingResponse($"Baking... {state.progress:P0}", 0.5, state);
}
private static void UpdateBake()
{
if (!s_isRunning)
{
EditorApplication.update -= UpdateBake;
return;
}
var now = EditorApplication.timeSinceStartup;
var delta = now - s_lastUpdateTime;
s_lastUpdateTime = now;
var state = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "in_progress", progress = 0f };
state.progress = Mathf.Clamp01(state.progress + (float)(delta / SimulatedDurationSeconds));
if (state.progress >= 1f)
{
state.lastStatus = "completed";
s_isRunning = false;
EditorApplication.update -= UpdateBake;
}
else
{
state.lastStatus = "in_progress";
}
McpJobStateStore.SaveState(ToolName, state);
}
}
```
### How the Polling Protocol Works
- **`_mcp_status: "pending"`** tells the middleware to keep checking back.
- **`_mcp_poll_interval`** (in seconds) controls how long to wait between polls. The server clamps this between 0.1 and 5 seconds to balance responsiveness with performance.
- **Null or empty responses** are treated as "still working" and trigger another poll.
- **Timeout protection:** After 10 minutes, the server gives up and returns a timeout error along with the last response it received.
- **Action routing:** The initial call uses whatever action your tool expects (often implicit). Subsequent polls use your exact `PollAction` string—no automatic snake_case or camelCase conversion—so make sure your `HandleCommand` switch statement handles it correctly.
+82
View File
@@ -0,0 +1,82 @@
---
id: multi-instance
slug: /guides/multi-instance
title: Multi-Instance Routing
sidebar_label: Multi-Instance Routing
description: Drive several Unity Editors from a single MCP session with set_active_instance and per-call routing.
---
# Multi-Instance Routing
You can have several Unity Editors open at once and aim a single MCP session at any of them.
## When this comes up
- You're refactoring a shared package and need to test the same change in two projects
- You're comparing behavior between Unity LTS and Unity 6
- You have a runtime project + a tooling project both connected
- You're driving a CI fixture project alongside your day-to-day work
## How instances are identified
Each connected Unity Editor advertises a stable ID of the form `Name@hash`, where:
- `Name` is the project's `productName` from Player Settings
- `hash` is a stable 8-character hash derived from the project path
Example: `MyGame@a1b2c3d4`.
You can also reference an instance by:
- **Hash prefix** (e.g. `a1b` if it's unambiguous)
- **Port number** — stdio transport only
## Discovering instances
Read the resource:
> `mcpforunity://instances`
It returns the list of currently connected Editors with their `Name@hash`, project path, transport, and port. Most MCP clients expose this as the `unity_instances` resource.
## Setting the active instance for the session
```
set_active_instance(instance="MyGame@a1b2c3d4")
```
Once set, **every subsequent tool call** in the session routes to that instance until you change it. This is the most common pattern: choose once, then prompt normally.
You can also use:
```
set_active_instance(instance="a1b") # hash prefix
set_active_instance(instance="6401") # port number (stdio only)
```
## Routing a single call without changing the session default
Pass `unity_instance` on the individual tool call:
```
manage_scene(action="get_hierarchy", unity_instance="MyGame@a1b2c3d4")
```
This is useful for comparing two projects in the same prompt — e.g., "Read the same script from both projects and tell me what differs."
The server accepts the same value formats as `set_active_instance`: `Name@hash`, hash prefix, or (stdio) port number.
## What happens with no active instance
- **One Unity Editor connected** → it's used automatically.
- **Multiple Editors connected and no active set** → the server errors with the available instance list. Call `set_active_instance` and retry.
## HTTP vs stdio differences
- **HTTP**: instance state is keyed per-session by `client_id`, so two MCP clients can target different Editors at the same time on the same Python server.
- **Stdio**: port-number shorthand works because there's a separate Python process per client. HTTP shares one process and uses `Name@hash` exclusively.
## Related reference
- [`set_active_instance`](/reference/tools/core/set_active_instance) — full tool reference
- [`unity_instances` resource](/reference/resources) — discovery surface
+261
View File
@@ -0,0 +1,261 @@
# Remote Server API Key Authentication
When running the MCP for Unity server as a shared remote service, API key authentication ensures that only authorized users can access the server and that each user's Unity sessions are isolated from one another.
This guide covers how to configure, deploy, and use the feature.
## Prerequisites
### External Auth Service
You need an external HTTP endpoint that validates API keys. The server delegates all key validation to this endpoint rather than managing keys itself.
The endpoint must:
- Accept `POST` requests with a JSON body: `{"api_key": "<key>"}`
- Return a JSON response indicating validity and the associated user identity
- Be reachable from the MCP server over the network
See [Validation Contract](#validation-contract) for the full request/response specification.
### Transport Mode
API key authentication is only available when running with HTTP transport (`--transport http`). It has no effect in stdio mode.
## Server Configuration
### CLI Arguments
| Argument | Environment Variable | Default | Description |
| -------- | -------------------- | ------- | ----------- |
| `--http-remote-hosted` | `UNITY_MCP_HTTP_REMOTE_HOSTED` | `false` | Enable remote-hosted mode. Requires API key auth. |
| `--api-key-validation-url URL` | `UNITY_MCP_API_KEY_VALIDATION_URL` | None | External endpoint to validate API keys (required). |
| `--api-key-login-url URL` | `UNITY_MCP_API_KEY_LOGIN_URL` | None | URL where users can obtain or manage API keys. |
| `--api-key-cache-ttl SECONDS` | `UNITY_MCP_API_KEY_CACHE_TTL` | `300` | How long validated keys are cached (seconds). |
| `--api-key-service-token-header HEADER` | `UNITY_MCP_API_KEY_SERVICE_TOKEN_HEADER` | None | Header name for server-to-auth-service authentication. |
| `--api-key-service-token TOKEN` | `UNITY_MCP_API_KEY_SERVICE_TOKEN` | None | Token value sent to the auth service for server authentication. |
Environment variables take effect when the corresponding CLI argument is not provided. For boolean flags, set the env var to `true`, `1`, or `yes`.
### Startup Validation
The server validates its configuration at startup:
- If `--http-remote-hosted` is set but `--api-key-validation-url` is not provided (and the env var is also unset), the server logs an error and exits with code 1.
### Example
```bash
python -m src.main \
--transport http \
--http-host 0.0.0.0 \
--http-port 8080 \
--http-remote-hosted \
--api-key-validation-url https://auth.example.com/api/validate-key \
--api-key-login-url https://app.example.com/api-keys \
--api-key-cache-ttl 120
```
Or using environment variables:
```bash
export UNITY_MCP_TRANSPORT=http
export UNITY_MCP_HTTP_HOST=0.0.0.0
export UNITY_MCP_HTTP_PORT=8080
export UNITY_MCP_HTTP_REMOTE_HOSTED=true
export UNITY_MCP_API_KEY_VALIDATION_URL=https://auth.example.com/api/validate-key
export UNITY_MCP_API_KEY_LOGIN_URL=https://app.example.com/api-keys
python -m src.main
```
### Service Token (Optional)
If your auth service requires the MCP server to authenticate itself (server-to-server auth), configure a service token:
```bash
--api-key-service-token-header X-Service-Token \
--api-key-service-token "your-server-secret"
```
This adds the specified header to every validation request sent to the auth endpoint.
We strongly recommend using this feature because it ensures that the entity requesting validation is the MCP server itself, not an imposter.
## Unity Plugin Setup
When connecting to a remote-hosted server, Unity users need to provide their API key:
1. Open the MCP for Unity window in the Unity Editor.
2. Select HTTP Remote as the connection mode.
3. Enter the API key in the API Key field. The key is stored in `EditorPrefs` (per-machine, not source-controlled).
4. Click **Get API Key** to open the login URL in a browser if you need a new key. This fetches the URL from the server's `/api/auth/login-url` endpoint.
The API key is a one-time entry per machine. It persists across Unity sessions until explicitly cleared.
## MCP Client Configuration
When an API key is configured, the Unity plugin's MCP client configurators automatically include the `X-API-Key` header in generated configuration files.
Example generated config for **Cursor** (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"mcp-for-unity": {
"url": "http://remote-server:8080/mcp",
"headers": {
"X-API-Key": "<your-api-key>"
}
}
}
}
```
Example for **Claude Code** (CLI):
```bash
claude mcp add --transport http mcp-for-unity http://remote-server:8080/mcp \
--header "X-API-Key: <your-api-key>"
```
Similar header injection works for VS Code, Windsurf, Cline, and other supported MCP clients.
## Behaviour Changes in Remote-Hosted Mode
Enabling `--http-remote-hosted` changes several server behaviours compared to the default local mode:
### Authentication Enforcement
All MCP tool and resource calls require a valid API key. The `X-API-Key` header must be present on every HTTP request to the `/mcp` endpoint. If the key is missing or invalid, the middleware raises a `RuntimeError` that surfaces as an MCP error response.
### WebSocket Auth Gate
Unity plugins connecting via WebSocket (`/hub/plugin`) are validated during the handshake:
| Scenario | WebSocket Close Code | Reason |
| -------- | -------------------- | ------ |
| No API key header | `4401` | API key required |
| Invalid API key | `4403` | Invalid API key |
| Auth service unavailable | `1013` | Try again later |
| Valid API key | Connection accepted | user_id stored in connection state |
### Session Isolation
Each user can only see and interact with their own Unity instances. When User A calls `set_active_instance` or lists instances, they only see Unity editors that connected with User A's API key. User B's sessions are invisible to User A.
### Auto-Select Disabled
In local mode, the server automatically selects the sole connected Unity instance. In remote-hosted mode, this auto-selection is disabled. Users must explicitly call `set_active_instance` with a `Name@hash` from the `mcpforunity://instances` resource.
### CLI Routes Disabled
The following REST endpoints are disabled in remote-hosted mode to prevent unauthenticated access:
- `POST /api/command`
- `GET /api/instances`
- `GET /api/custom-tools`
### Endpoints Always Available
These endpoints remain accessible regardless of auth:
| Endpoint | Method | Purpose |
| -------- | ------ | ------- |
| `/health` | GET | Health check for load balancers and monitoring |
| `/api/auth/login-url` | GET | Returns the login URL for API key management |
## Validation Contract
### Request
```http
POST <api-key-validation-url>
Content-Type: application/json
{
"api_key": "<the-api-key>"
}
```
If a service token is configured, an additional header is sent:
```http
<service-token-header>: <service-token-value>
```
### Response (Valid Key)
```json
{
"valid": true,
"user_id": "user-abc-123",
"metadata": {}
}
```
- `valid` (bool, required): Must be `true`.
- `user_id` (string, required): Stable identifier for the user. Used for session isolation.
- `metadata` (object, optional): Arbitrary metadata stored alongside the validation result.
### Response (Invalid Key)
```json
{
"valid": false,
"error": "API key expired"
}
```
- `valid` (bool, required): Must be `false`.
- `error` (string, optional): Human-readable reason.
### Response (HTTP 401)
A `401` status code is also treated as an invalid key (no body parsing required).
### Timeouts and Retries
- Request timeout: 5 seconds
- Retries: 1 (with 100ms backoff)
- Failure mode: deny by default (treated as invalid on any error)
Transient failures (5xx, timeouts, network errors) are **not cached**, so subsequent requests will retry the auth service.
## Error Reference
| Context | Condition | Response |
| ------- | --------- | -------- |
| MCP tool/resource | Missing API key (remote-hosted) | `RuntimeError` → MCP `isError: true` |
| MCP tool/resource | Invalid API key | `RuntimeError` → MCP `isError: true` |
| WebSocket connect | Missing API key | Close `4401` "API key required" |
| WebSocket connect | Invalid API key | Close `4403` "Invalid API key" |
| WebSocket connect | Auth service down | Close `1013` "Try again later" |
| `/api/auth/login-url` | Login URL not configured | HTTP `404` with admin guidance message |
| Server startup | Remote-hosted without validation URL | `SystemExit(1)` |
## Troubleshooting
### "API key authentication required" error on every tool call
The server is in remote-hosted mode but no API key is being sent. Ensure the MCP client configuration includes the `X-API-Key` header, or set it in the Unity plugin's connection settings.
### Server exits immediately with code 1
The `--http-remote-hosted` flag requires `--api-key-validation-url`. Provide the URL via CLI argument or `UNITY_MCP_API_KEY_VALIDATION_URL` environment variable.
### WebSocket connection closes with 4401
The Unity plugin is not sending an API key. Enter the key in the MCP for Unity window's connection settings.
### WebSocket connection closes with 1013
The external auth service is unreachable. Check network connectivity between the MCP server and the validation URL. The Unity plugin can retry the connection.
### User cannot see their Unity instance
Session isolation is active. The Unity editor and the MCP client must use API keys that resolve to the same `user_id`. Verify that the Unity plugin's WebSocket connection and the MCP client's HTTP requests use the same API key.
### Stale auth after key rotation
Validated keys are cached for `--api-key-cache-ttl` seconds (default: 300). After rotating or revoking a key, there is a delay equal to the TTL before the old key stops working. Lower the TTL for faster revocation at the cost of more frequent validation requests.
+54
View File
@@ -0,0 +1,54 @@
---
id: roslyn
slug: /guides/roslyn
title: Roslyn Script Validation (Advanced)
sidebar_label: Roslyn Validation
description: Enable strict C# validation that catches undefined namespaces, types, and methods before the script reaches the Unity compiler.
---
# Roslyn Script Validation
By default, MCP for Unity uses a fast structural validator for scripts the LLM generates. For **strict** validation that catches undefined namespaces, types, and methods at write time — without a full Unity compile — install the optional Roslyn DLLs.
Most users don't need this. Enable it when:
- You're letting the LLM write a lot of unsupervised C# and want stricter feedback loops
- You're seeing recurring compile errors that survive the structural validator
- You're building custom tools that depend on accurate symbol resolution
## One-click installer (recommended)
1. Open **Window → MCP for Unity**.
2. Scroll to the **Runtime Code Execution (Roslyn)** section in the Scripts / Validation tab.
3. Click **Install Roslyn DLLs**.
The installer downloads the required NuGet packages, places the DLLs in `Assets/Plugins/Roslyn/`, and adds `USE_ROSLYN` to Scripting Define Symbols.
You can also trigger it from the menu: **Window → MCP for Unity → Install Roslyn DLLs**.
## Manual install (if the installer isn't available)
1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity).
2. Open **Window → NuGet Package Manager**.
3. Install:
- `Microsoft.CodeAnalysis` v5.0
- `SQLitePCLRaw.core` v3.0.2
- `SQLitePCLRaw.bundle_e_sqlite3` v3.0.2
4. Add `USE_ROSLYN` to **Player Settings → Scripting Define Symbols**.
5. Restart Unity.
## Manual DLL install (no NuGetForUnity)
1. Download `Microsoft.CodeAnalysis.CSharp.dll` and its dependencies from [NuGet.org](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp/).
2. Place DLLs in `Assets/Plugins/Roslyn/`.
3. Ensure .NET compatibility settings are correct for your Unity version.
4. Add `USE_ROSLYN` to Scripting Define Symbols.
5. Restart Unity.
## Verifying it's active
After restart, the MCP for Unity status panel shows **Roslyn: enabled** under the Scripts section. The `validate_script` tool now performs full semantic analysis rather than the structural pass.
## Disabling
Remove `USE_ROSLYN` from Scripting Define Symbols. The plugin falls back to structural validation; the DLLs can stay in `Assets/Plugins/Roslyn/` or be removed.
+80
View File
@@ -0,0 +1,80 @@
---
id: tool-groups
slug: /guides/tool-groups
title: Tool Groups and manage_tools
sidebar_label: Tool Groups
description: Per-session visibility for the 47 tools. Activate vfx, animation, ui, testing, etc. only when you need them.
---
# Tool Groups
MCP for Unity ships 47 tools, but exposing all of them to the LLM at once balloons the prompt and dilutes routing decisions. So tools are sorted into **groups**, and only `core` is enabled by default.
## The groups
| Group | Default | Description |
|---|---|---|
| `core` | enabled | Essential scene, script, asset, and editor tools — always on. |
| `animation` | off | Animator control, AnimationClip creation. |
| `ui` | off | UI Toolkit — UXML, USS, UIDocument. |
| `vfx` | off | VFX Graph, shaders, procedural textures. |
| `scripting_ext` | off | ScriptableObject management. |
| `testing` | off | Test runner and async test jobs. |
| `probuilder` | off | ProBuilder 3D modeling. Requires `com.unity.probuilder` package. |
| `profiling` | off | Profiler session control, counters, memory snapshots, Frame Debugger. |
| `docs` | off | Unity API reflection and documentation lookup. |
## Enabling a group
Use the `manage_tools` meta-tool from your prompt:
> Activate the `vfx` group so we can author shaders.
The assistant calls:
```
manage_tools(action="activate", group="vfx")
```
After activation, the group's tools appear in the next tool listing and are usable for the remainder of the session.
## Listing what's available
```
manage_tools(action="list_groups")
```
Returns every group with its current activation state and tool names.
## Deactivating
```
manage_tools(action="deactivate", group="vfx")
```
Useful when a group's tools are confusing the assistant — e.g., `manage_shader` and `manage_material` both apply to materials in different ways. Disabling the one you're not using keeps the assistant focused.
## Other actions
- `sync` — refreshes visibility from the Unity Editor's per-tool toggle UI. Use after toggling tools in `Window > MCP for Unity > Tools`.
- `reset` — restores defaults (only `core` enabled).
## Why this exists
Three reasons:
1. **Prompt economy**: each visible tool adds tokens to every assistant call. Hiding what you're not using is real money saved at scale.
2. **Routing clarity**: when the LLM picks between 47 tools versus the 30 core tools, the wrong-tool rate drops measurably.
3. **Package hygiene**: tools in `probuilder` only work if `com.unity.probuilder` is installed; hiding them by default avoids confusing errors.
## Server vs. session state
- The Unity Editor maintains a per-tool **toggle UI** (`Window > MCP for Unity > Tools`) that controls server-side visibility.
- The `manage_tools` meta-tool controls **per-session** visibility — different MCP sessions can see different groups even against the same server.
`sync` reconciles the two: it pulls the Editor's toggle states into the current session.
## Related reference
- [`manage_tools`](/reference/tools/core/manage_tools) — full tool reference
- [`tool_groups` resource](/reference/resources) — discoverable group catalog
+183
View File
@@ -0,0 +1,183 @@
---
id: troubleshooting
slug: /guides/troubleshooting
title: Common Setup Problems
sidebar_label: Troubleshooting / FAQ
description: Real-world fixes for the issues people actually hit — macOS dyld errors, WSL2 bridging, DLL version conflicts, and per-client FAQs.
---
# Common Setup Problems
## macOS: Claude CLI fails to start (dyld ICU library not loaded)
**Symptoms:**
- MCP for Unity error: *"Failed to start Claude CLI. dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.71.dylib …"*
- Running `claude` in Terminal fails with missing `libicui18n.xx.dylib`.
**Cause:**
Homebrew Node (or the `claude` binary) was linked against an ICU version that's no longer installed; dyld can't find that dylib.
**Fix options (pick one):**
**Reinstall Homebrew Node** (relinks to current ICU), then reinstall CLI:
```bash
brew update
brew reinstall node
npm uninstall -g @anthropic-ai/claude-code
npm install -g @anthropic-ai/claude-code
```
**Use NVM Node** (avoids Homebrew ICU churn):
```bash
nvm install --lts
nvm use --lts
npm install -g @anthropic-ai/claude-code
# Unity MCP → Claude Code → Choose Claude Location → ~/.nvm/versions/node/<ver>/bin/claude
```
**Use the native installer** (puts `claude` in a stable path):
```bash
# macOS / Linux
curl -fsSL https://claude.ai/install.sh | bash
# Unity MCP → Claude Code → Choose Claude Location → /opt/homebrew/bin/claude or ~/.local/bin/claude
```
**After fixing:** in MCP for Unity (Claude Code section), click **"Choose Claude Location"** and select the working `claude` binary, then **Register** again.
---
## WSL2: Connecting Claude Code (Linux) to Unity (Windows)
If you're running Claude Code from WSL2 and Unity on Windows, the MCP server runs on the Windows side but Claude Code needs to reach it from WSL. Here's how to bridge the two.
*Contributed by [@aollivier82](https://github.com/CoplayDev/unity-mcp/issues/712).*
### 1. Install the Unity package
In Unity Package Manager, add by git URL:
```text
https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main
```
In the MCP for Unity settings, change the port to **8090** (or any free port — the default 8080 can conflict with other services like Tailscale).
### 2. Install uv on Windows
The MCP server requires `uv`. From an admin PowerShell:
```powershell
irm https://astral.sh/uv/install.ps1 | iex
```
### 3. Set up port forwarding from WSL to Windows
WSL2 runs in a separate network namespace, so you need to forward the MCP port. From an admin PowerShell:
```powershell
netsh interface portproxy add v4tov4 listenport=8090 listenaddress=0.0.0.0 connectport=8090 connectaddress=127.0.0.1
```
Then add a firewall rule to allow it:
```powershell
New-NetFirewallRule -DisplayName "Unity MCP Server" -Direction Inbound -LocalPort 8090 -Protocol TCP -Action Allow
```
### 4. Find your WSL host IP
From inside WSL:
```bash
cat /etc/resolv.conf | grep nameserver | awk '{print $2}'
```
This prints the Windows host IP as seen from WSL (e.g. `172.21.48.1`). It's a private address that varies per machine.
### 5. Add the MCP server to Claude Code
From WSL, using the IP from step 4:
```bash
claude mcp add --transport http UnityMCP http://<YOUR_WSL_HOST_IP>:8090/mcp
```
For example:
```bash
claude mcp add --transport http UnityMCP http://172.21.48.1:8090/mcp
```
Note: this uses **HTTP transport**, not stdio — since the server is running on the Windows side.
### 6. Verify
Start Unity, then start Claude Code. You should see `UnityMCP` listed as a connected MCP server. Test it by asking Claude to get your scene info.
**Notes:**
- If you restart your machine, the WSL host IP may change. Re-run step 4 and update the MCP config if needed.
- The port proxy persists across reboots. To remove it later: `netsh interface portproxy delete v4tov4 listenport=8090 listenaddress=0.0.0.0`
- If the connection fails, make sure Unity is running and the MCP server is started (check the MCP for Unity panel).
---
## DLL reference mismatch with Unity AI Assistant package
If you're using **Unity 6.3+** alongside the **Unity AI Assistant** package, you may encounter `System.Collections.Immutable` version conflicts.
*Reported by [@rkroska](https://github.com/CoplayDev/unity-mcp/issues/557).*
**Symptoms:**
- Compilation errors referencing `System.Collections.Immutable` version mismatches
- Errors appear after installing MCP for Unity in a project that has the Unity AI Assistant package
**Cause:**
Unity AI Assistant bundles `System.Collections.Immutable` v10, while MCP for Unity's CodeAnalysis dependency needs v9. Unity's built-in version may be v8. These conflict during assembly resolution.
**Fix options:**
- **Option A (recommended):** If you don't need Unity AI Assistant, remove it via Package Manager. Then install `System.Collections.Immutable` v9.0.0 as a DLL in `Assets/Plugins/`.
- **Option B:** If you need both packages, install `System.Collections.Immutable` v9.0.0 in `Assets/Plugins/` to satisfy MCP's dependency. The AI Assistant's v10 reference should be forward-compatible.
**Note:** This is a Unity assembly resolution issue, not specific to MCP for Unity. Unity doesn't have a NuGet-style dependency resolver, so DLL version conflicts must be resolved manually.
---
## "No Unity Instances Found"
:::tip When in doubt, restart your client
Clients like Claude Code or JetBrains Rider can get confused if you switch transport modes mid-session. Restart the client so it picks up the new configuration.
:::
If restarting doesn't fix it:
- Check the MCP for Unity status panel — does it say `Connected`?
- Open `mcpforunity://instances` in your client. If it returns an empty list, the Unity-side bridge isn't running.
- Try **Window → MCP for Unity → Restart Server**.
---
## FAQ — Claude Code
**Q: Unity can't find `claude` even though Terminal can.**
A: macOS apps launched from Finder / Hub don't inherit your shell PATH. In the MCP for Unity window, click **"Choose Claude Location"** and select the absolute path (e.g., `/opt/homebrew/bin/claude` or `~/.nvm/versions/node/<ver>/bin/claude`).
**Q: I installed via NVM; where is `claude`?**
A: Typically `~/.nvm/versions/node/<ver>/bin/claude`. The MCP for Unity UI also scans NVM versions and you can browse to it via **"Choose Claude Location"**.
**Q: The Register button says "Claude Not Found".**
A: Install the CLI or set the path. Click the orange **[HELP]** link in the MCP for Unity window for step-by-step install instructions, then choose the binary location. See also: [Install or Repair Claude Code CLI](/guides/claude-code-cli).
## FAQ — VS Code
**Q: When I first set up and start the MCP for Unity server in VS Code, I get a failed response that says `Canceled: Canceled`.**
A: Start a new chat — the bad chat didn't pick up the MCP server configuration.
![Canceled error screenshot](https://github.com/user-attachments/assets/571e2aeb-c286-4235-ab2b-8285c0db3296)
## FAQ — Cursor / Windsurf / VS Code (Windows uv path)
**Q: My MCP client keeps failing to launch the server even though `uv` is installed.**
A: Some Windows machines have multiple `uv.exe` locations. Auto-config sometimes picks a less stable path, causing the launch to fail or auto-rewrite on every restart. Use **"Choose UV Install Location"** in the MCP for Unity window and pin the **WinGet Links shim** path (`%LOCALAPPDATA%\Microsoft\WinGet\Links\uv.exe`) — it's stable across uv upgrades.
+110
View File
@@ -0,0 +1,110 @@
---
id: uv-setup
slug: /guides/uv-setup
title: Install or Repair uv + Python
sidebar_label: uv + Python Setup
description: Install or repair uv and Python — the runtime MCP for Unity needs to launch the Python server from Cursor, VS Code, Windsurf, Rider, and other uv-based clients.
---
# Install or Repair uv + Python
The key to configuring MCP with **Cursor, VS Code, Windsurf, and Rider is [`uv`](https://docs.astral.sh/uv/)**.
- `uv` is a fast Python package manager used to install and run the Unity MCP Server (`mcp-for-unity`).
- **How it's used:** your MCP client config points to `command: uvx` with args like `--from mcpforunityserver mcp-for-unity --transport stdio`. The client invokes `uvx` directly to launch the server.
- **Why it matters:** if `uv` isn't installed or on PATH, Cursor / Windsurf / VS Code can't start the server. The MCP for Unity window will show **"uv Not Found"** until fixed.
- **Detection / override:** the MCP for Unity window auto-detects `uv` in common locations and on PATH. If not found, use **"Choose UV Install Location"** to navigate to your `uv` binary and save the path.
:::tip When in doubt, restart your client
Clients like Claude Code or JetBrains Rider can get confused if you switch from `http` to `stdio` (or vice versa). If they say **"No Unity Instances found"**, restart the client so it picks up the new configuration.
:::
## Requirements
You need **Python 3.10+** and the **`uv`** package manager.
### Verify
```bash
python3 --version # should be 3.10+
uv --version # should print a version like "uv 0.x"
```
## Install Python
**macOS:**
```bash
# Option A: Official installer (recommended)
# Download from https://www.python.org/downloads/
# Option B: Homebrew (3.12 is the latest LTS as of writing; 3.10 also works)
brew install python@3.12
```
**Windows:**
```powershell
# Official installer (recommended)
# Download from https://www.python.org/downloads/windows/
```
## Install uv
**macOS / Linux / WSL:**
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
# or Homebrew on macOS
brew install uv
```
**Windows PowerShell:**
```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# or
winget install --id=astral-sh.uv -e
```
## Common uv locations
| OS | Path |
|---|---|
| **macOS** | `/opt/homebrew/bin/uv`, `/usr/local/bin/uv`, `~/.local/bin/uv` |
| **Linux** | `/usr/local/bin/uv`, `/usr/bin/uv`, `~/.local/bin/uv` |
| **Windows** | `%LOCALAPPDATA%/Programs/Python/Python3xx/Scripts/uv.exe` |
## MCP for Unity window behavior
- If `uv` isn't found, the status panel shows a red **"uv Not Found"** with a hint **"Make sure uv is installed! [CLICK]"**.
- Use **"Choose UV Install Location"** to browse to the `uv` binary. This saves the path and reconfigures automatically.
- On macOS, Unity launched from Finder may not inherit your PATH. Setting the `uv` location here is the easiest fix.
## Notes and gotchas
- **macOS GUI apps don't inherit your shell startup files.** PATH may differ from Terminal. Set `uv` via the MCP window to avoid PATH issues.
- **Windows vs WSL:** if you installed `uv` inside WSL only, Windows-native Unity can't see it. Install `uv` on Windows, or use the MCP window to point to a Windows `uv.exe`.
- **Custom locations:** if you installed `uv` somewhere non-standard, the picker path is stored in `UnityMCP.UvPath` and persists across sessions.
## What the "Repair Python Env" button does
- Deletes the server's `.venv` and `.python-version` (if present)
- Runs `uv sync` in the Unity MCP Server `src` directory to rebuild a clean environment
- Useful after Python upgrades or missing modules
## Where the Unity MCP Server is installed
| OS | Path |
|---|---|
| **macOS** | `~/Library/Application Support/UnityMCP/UnityMcpServer/src` (or `~/Library/AppSupport/UnityMCP/UnityMcpServer/src` via symlink) |
| **Windows** | `%USERPROFILE%/AppData/Local/UnityMCP/UnityMcpServer/src` |
| **Linux** | `~/.local/share/UnityMCP/UnityMcpServer/src` |
## Manual repair / run
```bash
cd <UnityMcpServer/src>
uv sync
uv run server.py
```