使用说明
Unity Code MCP
Description
Unity Code MCP is a coding focused Model Context Protocol (MCP) server that enables AI agents to write Unity code autonomously, and to verify the runtime UI Toolkit interfaces they build by actually operating them in the Game View.
🎯 Why Unity Code MCP?
Unity Code MCP is a high-performance, coding-focused MCP server built in Rust. It handles Unity's compilation cycles gracefully while providing only the essential tools needed for autonomous code development: compilation feedback, test execution, console logs, and hands-on automation of the running game's UI Toolkit interface.
This MCP server enables AI agents to develop Unity code autonomously with exceptional speed and reliability - write code, compile, fix compile errors, test, fix bugs, repeat, just like how a human would.
Autonomous UI Toolkit work
UI code is where AI agents usually stop being autonomous. The code compiles and the tests pass, but whether the interface actually works is invisible to the agent, so a human has to enter Play Mode, click around, and report back what went wrong.
Unity Code MCP closes that loop. An agent can enter Play Mode itself, read the runtime UI Toolkit tree of the Game View, click a button, type into a field, read what the game logged in response, inspect an element's layout and resolved styles when it looks wrong, and take a screenshot of the result - all without a human touching the Editor.
That turns "I wrote the UI, please check it" into an agent that verifies its own UI work the way a developer would:
- Does the button do anything? Click it, then read the console.
- Why is it not visible? Inspect its world bounds,
display,visibilityand resolved styles, like the UI Toolkit Debugger would. - Why does the click not land? The click is rejected with a reason, e.g. the element is disabled or covered by another element.
- Does it look right? Capture the Game View and look at the image.
✨ Key Features
- 🤖 Coding-Optimized: Streamlined tools designed for efficient AI agent coding workflows
- 🎮 Runtime UI Automation: Agents can drive and inspect the runtime UI Toolkit interface in the Game View, so UI work can be verified without human intervention
- ⚡ Lightweight and High Performance: Built in Rust for exceptional speed, minimal memory usage, and lightning-fast response times. Uses only 1MB memory when the workspace is not a Unity Project, and only 10MB when it is and Unity Editor is open for the project. Also, the communication with Unity Editor is based on UDP, so it's minimal load for your system.
- 🎯 Efficient Communication: Minimal token usage with essential operations, only returns relevant information. Console logs merge repeated messages and are capped per call, and UI snapshots are compact YAML rather than a raw visual tree dump
- 🧪 Test-Driven: Comprehensive test execution and reporting capabilities
- 📦 Self-Contained: Single binary with no runtime dependencies (no Node.js, Python, or .NET required)
🛠️ MCP Server Tools
Code workflow
refresh_asset_database
- Triggers Unity compilation and asset processing
- Returns compile errors and other non compile warning and errors only include the logs during the refresh
- Handles domain reload gracefully
Asset database refresh tool in action:
run_tests
- Runs Unity tests with comprehensive reporting
- Provides detailed stack traces and logs for failures
- Supports both EditMode and PlayMode tests
Test execution tool in action:
get_console_logs
- Reads the Unity console output collected while the server is connected
- Repeated messages with identical content are merged into one entry with a repeat count, the way Unity's console collapses them
- Filter by log level (
Error,Warning,Info) and by a substring of the message - At most 20 entries per call, newest last, and the response says how many entries matched in total so the agent can narrow its filter
- Stack traces are left out unless asked for, because they are long and only needed once the interesting entry is found
Play Mode control
enter_play_mode / exit_play_mode
- Enters or exits Play Mode and waits until Unity confirms the new state, instead of assuming it worked
- Entering Play Mode reloads Unity's script domain, so the wait matters, and it is what makes the Game View tools below usable without a human pressing play
- Unity cannot compile scripts while playing, so
run_testsonly works outside of Play Mode, andrefresh_asset_databaseonly compiles there. An agent that changed code exits Play Mode, compiles, and enters it again - which reloads the script domain and therefore invalidates the UI element refs it held - A refresh in Play Mode is left to Unity to accept or refuse: it starts one only when the
Script Changes While Playingpreference isRecompile After Finished Playing, because the other options would recompile immediately and either reload the domain under the running game or stop Play Mode. Such a refresh imports assets and never compiles, so it reportscompilation_occurred: falseand cannot report compile errors
Game View automation (runtime UI Toolkit)
These tools operate on the runtime UI Toolkit content rendered in Unity's Game View, and require Play Mode. Paused Play Mode works too, which is useful for inspecting a specific frame.
ui_toolkit_snapshot
- Compact YAML snapshot of every active
UIDocument, with element types, their relevant properties, and an automationrefper element - The starting point: the agent reads this to see what the game is showing, then uses the refs with the tools below
- Implementation noise of built-in controls is folded away, invisible subtrees are omitted, and long runs of identical siblings are truncated, so the snapshot stays small enough to read
ui_toolkit_get_element_hierarchy
- Type, name and USS class hierarchy below one element, with an optional depth
- Unlike the snapshot this expands built-in implementation nodes and invisible descendants, which is how an agent finds an element the compact snapshot folded away
ui_toolkit_get_element_debug_info
- Layout, geometry, visibility state, USS classes, stylesheets, inline and resolved styles, and remaining properties of one element
- The UI Toolkit Debugger equivalent, and the tool to reach for when a click fails or the UI does not look right
ui_toolkit_click_element / ui_toolkit_hover_over_element
- Interact with an element through the normal UI Toolkit event pipeline, so the game's own callbacks,
:hoverstate and value change notifications behave as they do for a real user - A click that cannot land is rejected with a reason, such as the element being disabled, hidden, or covered by another element
buttonselectsleft(the default),rightormiddle. Only a left click activates aButton, and a right click never opens a contextual menu, because a runtime panel has no menu manager - it delivers the pointer events, which is what UI handling the right button itself needs
ui_toolkit_set_field_value
- Assigns a value to a runtime field such as a
Toggle,Slider,TextFieldor enum field, raising the usual change notifications
take_screenshot
- Captures the rendered Game View (the whole game image, not just the UI) to a PNG in the project's
Tempdirectory and returns its path, so the agent can read the image
Note: These tools automate the runtime UI of your game. They do not inspect Unity's Editor UI. Element refs come from the most recent snapshot or hierarchy, and are invalidated when Unity reloads its script domain, so an agent takes a fresh snapshot after compiling. Failed requests come back with an error code and a hint on how to recover.
Editor state
Unlike the Game View tools, each of these has its own Play Mode requirement.
list_open_scenes
- YAML list of the scenes currently open in the Editor, with each scene's name, asset path, whether it is the active one, whether it is loaded, whether it has unsaved changes, its build index and its root object count
- Works in both Edit Mode and Play Mode
open_scene
- Opens a scene asset, so an agent can set up the right scene before entering Play Mode, and returns the resulting open scenes as the same YAML
list_open_scenesgives - Works outside of Play Mode only
modeselectsSingle(the default),AdditiveorAdditiveWithoutLoadingunsaved_changesdecides what happens to unsaved work when aSingleopen would close modified scenes:refusereports them and opens nothing (the default),savesaves them first,discardloses them. Unity never shows a save dialog, because a modal dialog would block automation
list_locales / select_locale
- Reads the project's localization locales and the selected one, and switches the selection, so localized UI can be checked in another language without touching the game's own settings screen
- Both require Play Mode, because the runtime locale list only exists while playing
- The Unity package reads Unity's localization settings through reflection, so a project without
com.unity.localizationkeeps working and simply reports that localization is unavailable
Scene and GameObject inspection
These tools read what is inside the open scenes, which is what the Hierarchy and Inspector windows show. Reading never changes a scene, so all of them work in both Edit Mode and Play Mode, except the visual snapshot, which needs a Game View to measure against.
Every GameObject is reported with an instance id, which is the unambiguous way to address it in the next call. A path such as Canvas/Panel/Button is matched in full and case sensitively, and reports back the candidate ids when several objects share it. An id stays valid until Unity reloads its script domain or Play Mode is entered or exited, exactly like a UI element ref.
Hierarchies are capped at 20 children per object, 50 roots per scene and 200 objects in total. The total budget lowers the depth before anything is written, so the answer is a shallower complete tree rather than a truncated deep one, and everything left out is counted.
get_scene_hierarchy
- The GameObject tree of one open scene as YAML, each object with its name, instance id and whether it is inactive
sceneselects the scene by asset path or name, defaulting to the active one, anddepthlimits the levels, defaulting to as deep as the object budget allows
get_gameobject_hierarchy
- The same YAML for the descendants of one object, which is how an agent expands a branch the scene tree cut off without paying for the rest of the scene
find_gameobjects
- Finds objects by
name(exactly, or as a substring withmatch_mode="contains") or by fullpath, across every open scene or just the one named byscene - Each match reports its name, id, scene, path, own and inherited active state, and component count, so the next call can address it by id
- Finding nothing is a successful answer with
count: 0, not an error
inspect_gameobject
- What the Inspector window shows for one object: tag, layer, prefab status, parent and child count, and every component with its member values
- Well known built-in components (transforms, renderers, colliders, rigidbodies,
Camera,Light,Animator,AudioSource,Canvas, uGUI, ...) report a curated set of members, because reflecting overCameraalone yields around sixty. Name a component infull_detail_componentsto see all of its members, public and non-public - A value that references another Unity object is written with its instance id, so it can be fed straight back into the next call, and a getter that throws is reported instead of failing the request
get_camera_visible_gameobjects
- What the game is actually drawing outside of UI Toolkit: the 2D and 3D objects a camera can see, as a tree that keeps each object's ancestors, with the pixel rectangle it covers on screen, its depth range, its renderer and its sorting layer and order
- Screen pixels use the same top left origin as
take_screenshotand the world bounds ofui_toolkit_get_element_debug_info, so the three can be compared directly - Requires Play Mode, because outside it there is no Game View to be a screen
renderersdefaults tocore(mesh, skinned mesh and sprite renderers), andalladds particles, trails, tilemaps and every other renderer, which is how to find out why something did not show up
Calling into the game's own code
invoke_static_method
- Calls a
public staticC# method of the project inside the Editor and returns what it returned, as a string, which is how an agent reaches behaviour no UI exposes: a cheat that grants gold, a save game reset, a debug spawner, or a helper written just to be called here - Works in both Edit Mode and Play Mode, because a static method does not depend on anything the player loop provides
type_nametakes the full namespace, with+before a nested type (MyGame.Systems+Debug). When several loaded assemblies declare the same name, the error lists their assembly qualified names to pick from- Arguments are always passed as strings and converted to the parameter types, using the same conversion
ui_toolkit_set_field_valueuses, so"100","1.5","true","(1,2)"for aVector2and enum member names all work, and a JSONnullpasses null. Collection parameters such asint[]andList<string>have no string conversion and are rejected - A method returning nothing answers with
returns: void, which is not the same answer as a method that returned null - Overloads with the same parameter count are resolved deterministically rather than by reflection order, so the same call always reaches the same method. To pin one exactly, avoid overloading or pass an argument the other overload cannot accept
- Generic methods,
ref/out/inandparamsparameters, and pointers cannot be invoked from strings and are reported asunsupported_method
Note: This runs arbitrary project code inside your Editor. Its only trust boundary is the loopback check every message of this protocol shares, and there is no method allow-list, because one would be trivial to work around and would only suggest a guarantee that is not there.
🚀 Autonomous AI agent workflow example
Once configured, AI agents can develop Unity code completely autonomously:
User: "Create a player controller that moves with WASD keys and has jump functionality. Make sure it's fully tested."
AI: I'll create a complete player controller with movement and jumping, then write comprehensive tests.
1. [AI writes PlayerController.cs with movement logic]
2. [AI calls: refresh_asset_database]
→ Result: "Compilation failed: CS0246: The type or namespace name 'Rigidbody' could not be found"
3. [AI fixes the missing using UnityEngine; statement]
4. [AI calls: refresh_asset_database]
→ Result: "Compilation successful, no errors"
5. [AI writes PlayerControllerTests.cs with movement and jump tests]
6. [AI calls: run_tests]
→ Result: "5 tests passed, 2 tests failed: NullReferenceException in Jump_ShouldApplyUpwardForce, ArgumentException in Move_WithInvalidInput"
7. [AI analyzes failures and fixes null reference and input validation bugs]
8. [AI calls: refresh_asset_database]
→ Result: "Compilation successful, no errors"
9. [AI calls: run_tests]
→ Result: "All 7 tests passed successfully"
AI: ✅ Complete! Created a fully functional PlayerController with WASD movement, jump mechanics, and comprehensive test coverage. All tests are passing.
This demonstrates true autonomous development - from user request to fully tested, working Unity code without any human intervention.
AI agent in action, tell Kimi K2 to fix compile errors in Unity project with no context:
🎮 Autonomous UI Toolkit workflow example
Compiling and passing tests says nothing about whether a UI actually works. With Play Mode control and Game View automation, the agent checks that itself:
User: "Add a settings panel, reachable from the main menu, with a volume slider and a mute
toggle. Muting should disable the slider."
AI: I'll build the panel, then play the game and check it behaves correctly.
1. [AI writes SettingsPanel.uxml, SettingsPanel.uss and SettingsPanel.cs, and adds a
Settings button to the main menu]
2. [AI calls: refresh_asset_database]
→ Result: "Compilation successful, no errors"
3. [AI calls: enter_play_mode]
→ Result: "is_playing: true, changed: true, duration_seconds: 4.2"
4. [AI calls: ui_toolkit_snapshot] # the game starts at the main menu
→ Result: "- UIDocument [name=\"MainMenu\"]:
- Button [name=\"play\"] [text=\"Play\"] [ref=e2]
- Button [name=\"settings\"] [text=\"Settings\"] [ref=e3]
- Button [name=\"quit\"] [text=\"Quit\"] [ref=e4]"
5. [AI calls: ui_toolkit_click_element ref=e3] # navigate into the settings panel
→ Result: "ok: true"
6. [AI calls: ui_toolkit_snapshot] # what the panel actually looks like now
→ Result: "- UIDocument [name=\"Settings\"]:
- Slider [name=\"volume\"] [label=\"Volume\"] [value=0.8] [ref=e7]
- Toggle [name=\"mute\"] [label=\"Mute\"] [value=false] [ref=e8]
- Button [name=\"back\"] [text=\"Back\"] [ref=e9]"
7. [AI calls: ui_toolkit_set_field_value ref=e8 value=true] # mute it
→ Result: "ok: true"
8. [AI calls: ui_toolkit_snapshot] # did the slider get disabled?
→ Result: "- Slider [name=\"volume\"] [label=\"Volume\"] [value=0.8] [ref=e7]"
# no enabledSelf=false, so the bug is real
9. [AI calls: get_console_logs levels=["Error"]]
→ Result: "NullReferenceException in SettingsPanel.OnMuteChanged (x1)"
10. [AI fixes the null reference: the slider was queried before the tree was cloned]
11. [AI calls: exit_play_mode] # scripts cannot compile while playing
12. [AI calls: refresh_asset_database]
→ Result: "Compilation successful, no errors"
13. [AI calls: enter_play_mode] # the game restarts at the main menu
14. [AI calls: ui_toolkit_snapshot] # refs are new, the domain was reloaded
15. [AI calls: ui_toolkit_click_element ref=e3] # navigate to the panel again
16. [AI calls: ui_toolkit_snapshot]
17. [AI calls: ui_toolkit_set_field_value ref=e8 value=true]
18. [AI calls: ui_toolkit_get_element_debug_info ref=e7]
→ Result: "element: { enabledSelf: false, enabledInHierarchy: false }" # fixed
19. [AI calls: ui_toolkit_click_element ref=e7] # a disabled slider must reject input
→ Result: "ok: false, error_code: disabled"
20. [AI calls: take_screenshot]
→ Result: ".../Temp/GameViewScreenshots/game-view-....png"
21. [AI reads the PNG and confirms the panel looks right]
22. [AI calls: exit_play_mode]
AI: ✅ Done. The settings panel opens from the main menu, and muting disables the volume
slider, which now rejects input. I found and fixed a NullReferenceException that made
the first attempt do nothing.
The agent played the game to get to its own feature, and found a bug that compiled cleanly and would have passed a naive unit test, because it actually operated the UI and read back what the game said. Note steps 13 to 16: re-entering Play Mode restarts the game, so the agent navigates from the main menu again and works from fresh refs, because the domain reload invalidated the old ones.
📦 Installation
Prerequisites
- Unity 6.0 or higher
- Rust toolchain (for building from source)
- CMake and a C compiler (required for building dependencies)
Step 1: Install Unity Package
Install the Visual Studio Code Editor package in your Unity project.
Important: The Visual Studio Code Editor package must be enabled (that is, you most select an external script editor provided by Visual Studio Code Editor for it to be enabled) for unity_code_mcp to work. Verify this in Unity at
Preferences→External Tools→External Script Editor- it should show something like "Visual Studio Code Editor v1.0.12 enabled".
Note: The Game View automation tools need the package to implement the Game View automation messages of the messaging protocol, which version 1.0.14 does. Every other tool works with older versions too.
Step 2: Get the Binary
Option A: Download Release (Recommended) (Windows Only)
- Download the latest binary from the Releases page
Option B: Build from Source
cargo build --release
Step 3: Configure Your AI Assistant
Add the MCP server to your AI assistant configuration:
For Cursor/Trae:
{
"mcpServers": {
"unity-code": {
"command": "/path/to/unity-code-mcp",
"env": {
"UNITY_PROJECT_PATH": "${workspaceFolder}"
}
}
}
}
For VS Code with MCP Extension:
{
"mcp.servers": {
"unity-code": {
"command": "/path/to/unity_code_mcp",
"env": {
"UNITY_PROJECT_PATH": "${workspaceFolder}"
}
}
}
}
For Claude Desktop:
{
"mcpServers": {
"unity-code": {
"command": "/path/to/unity_code_mcp"
}
}
}
Note: The
UNITY_PROJECT_PATHenvironment variable is a fallback option. If your IDE supports the MCProotscapability, the server will automatically detect Unity projects from the provided workspace roots and prioritize that over the environment variable.
Troubleshooting: If
${workspaceFolder}doesn't work in your IDE, try using an absolute path instead, e.g.,"UNITY_PROJECT_PATH": "/absolute/path/to/your/unity/project". Alternatively, ask your IDE developer to add support for the MCProotscapability.
Important: Use absolute paths for the binary command.
Platform support
The code is cross platform, but I can't build or test for other platforms, because I only use Windows. If there are platform specific bugs, you have to fix them yourself.
🧪 Development & Testing
Running Tests
To run the test suite:
-
Start Unity Editor with the embedded test project:
# Open Unity Editor and load the project at: # ./UnityProject -
Run tests (single-threaded to avoid Unity conflicts):
cargo test -- --test-threads=1
Note: Tests require a running Unity Editor instance with the embedded project loaded. Tests may take 30-60 seconds to complete due to Unity Editor interactions.
- For the Game View automation tests, open
Assets/Scenes/GameViewAutomationTest.unityand enter Play Mode. That scene contains the runtime UI the tests operate on, and it reports every interaction in its status label so a test can confirm a click or a value assignment really reached the game. Without it those tests report what is missing and skip, so the suite still passes.
Note: Most Unity dependent tests need the Editor to be outside of Play Mode, because
refresh_asset_databaseandrun_testsdo not work while playing. Run the Game View automation tests separately from the rest.
Building from Source
Prerequisites
- C Compiler: Required for building
aws-lc-rsdependency- Windows: MSVC (Visual Studio Build Tools)
- macOS: Xcode Command Line Tools (
xcode-select --install) - Linux: GCC (
sudo apt-get install build-essentialon Ubuntu/Debian)
- CMake: Required for building the
aws-lc-rsdependency- Windows: Follow the official guide
- macOS:
brew install cmake - Linux:
sudo apt-get install cmake(Ubuntu/Debian)
Build Commands
# Debug build
cargo build
# Release build (recommended for production)
cargo build --release
🤝 Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Run tests with
cargo test -- --test-threads=1 - Submit a pull request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Related Projects
- Visual Studio Code Editor for Unity - Required Unity package
- Model Context Protocol - The protocol specification
- Unity Code Pro VS Code Extension - VS Code extension that is related
