Unity MCP: How to Use Unity MCP Servers
In the rapidly evolving landscape of AI-assisted game development, the integration of Unity's powerful game engine with the Model Context Protocol (MCP) represents a transformative advancement in how developers interact with their Unity projects. Unity MCP servers establish a bidirectional bridge between conversational AI models and the Unity Editor, enabling AI assistants to inspect scene hierarchies, modify component properties, execute runtime operations, analyze performance metrics, and even generate game assets—all through natural language interfaces. This technical implementation transforms AI assistants from simple code-completion tools into comprehensive game development partners capable of active participation in the Unity workflow while maintaining appropriate access controls and editor state management.
Introduction
The Model Context Protocol provides a standardized framework for connecting AI models with external tools and data sources. Unity MCP servers implement this protocol to create a secure, interactive interface between AI assistants and the Unity Editor environment. By leveraging Unity's extensive C# reflection capabilities, editor scripting APIs, and runtime manipulation functions, MCP servers enable language models to programmatically access scene hierarchies, component data, project assets, and editor functionality—all while maintaining proper synchronization with the editor state and respecting Unity's serialization systems.
https://github.com/modelcontextprotocol/servers/tree/main/src/unity3d (opens in a new tab)
Technical Architecture of Unity MCP
MCP Protocol Foundation
Unity MCP operates within the Model Context Protocol architecture, which defines several key components:
-
Transport Layer:
- STDIO (Standard Input/Output): Direct process communication
- SSE (Server-Sent Events): HTTP-based asynchronous communication
- WebSocket: Bidirectional real-time communication
-
Resource Types:
- Prompts: Templated Unity operation patterns
- Tools: Executable Unity Editor and runtime operations
- Resources: Scene hierarchy, component data, and asset information
-
Serialization Format: JSON for structured data exchange between client and server
Unity MCP Architecture
The Unity MCP server implements a multi-layered architecture optimized for game development workflows:
unity-mcp/
├── Editor/
│ ├── MCP/
│ │ ├── Server/
│ │ │ ├── UnityMCPServer.cs # Main server implementation
│ │ │ ├── MCPTransport.cs # Transport layer handling
│ │ │ └── ServerConfig.cs # Configuration management
│ │ ├── Core/
│ │ │ ├── SceneManager.cs # Scene operations
│ │ │ ├── ComponentManager.cs # Component operations
│ │ │ ├── AssetManager.cs # Asset operations
│ │ │ └── RuntimeManager.cs # Play mode operations
│ │ ├── Tools/
│ │ │ ├── SceneTools.cs # Scene hierarchy tools
│ │ │ ├── ComponentTools.cs # Component manipulation tools
│ │ │ ├── AssetTools.cs # Asset management tools
│ │ │ └── PlayModeTools.cs # Runtime testing tools
│ │ ├── Resources/
│ │ │ ├── SceneResources.cs # Scene hierarchy resources
│ │ │ └── ProjectResources.cs # Project structure resources
│ │ └── Unity.MCP.Editor.asmdef # Assembly definition
│ └── MCP.meta # Unity meta file
├── Runtime/
│ ├── MCPRuntime.cs # Runtime API access
│ └── Unity.MCP.Runtime.asmdef # Runtime assembly definition
└── package.json # Package manifest
The core technical implementation consists of:
- Editor Integration: Hooks into Unity's editor lifecycle and event system
- Reflection System: Dynamically accesses Unity's internal APIs and serialized objects
- Serialization Handler: Converts between Unity's object model and JSON-compatible structures
- Tool Implementations: Translates MCP commands to Unity API calls
- Scene Observer: Monitors scene changes and maintains consistent state
Setup and Installation
Prerequisites
To implement Unity MCP, ensure you have:
- Unity 2021.3 LTS or newer
- Basic understanding of Unity Editor scripting
- .NET 6.0+ support enabled in your project
- An MCP-compatible client (e.g., Claude Desktop, Cursor, VS Code)
Installation Methods
Option 1: Unity Package Manager (UPM)
Add the package via the Unity Package Manager using the GitHub URL:
- Open Unity and navigate to Window > Package Manager
- Click the "+" button and select "Add package from git URL..."
- Enter:
https://github.com/modelcontextprotocol/unity-mcp.git
Option 2: Manual Package Installation
-
Clone the repository:
git clone https://github.com/modelcontextprotocol/unity-mcp.git
-
Copy the
unity-mcp
folder to your Unity project'sPackages
directory
Option 3: Using Smithery
npx -y @smithery/cli install unity-mcp --client claude
Configuration
The Unity MCP server accepts several configuration parameters:
-
Server Configuration:
UNITY_MCP_PORT
: Port number for WebSocket/SSE transportUNITY_MCP_TRANSPORT
: Transport method (stdio, sse, websocket)UNITY_MCP_LOG_LEVEL
: Logging verbosity (error, warning, info, debug)
-
Security Controls:
UNITY_MCP_READONLY_MODE
: Prevent modifications to scene/assetsUNITY_MCP_ALLOWED_ASSEMBLIES
: Restrict reflection to specific assembliesUNITY_MCP_SCRIPT_EXECUTION
: Control C# script execution permissions
-
Performance Settings:
UNITY_MCP_MAX_HIERARCHY_DEPTH
: Limit scene hierarchy traversal depthUNITY_MCP_BATCH_SIZE
: Maximum objects processed in a batchUNITY_MCP_RESPONSE_TIMEOUT
: Tool operation timeout in milliseconds
Example configuration in Unity Editor:
- Navigate to Edit > Project Settings > MCP Server
- Configure settings in the inspector panel:
// Unity MCP configuration object structure
[Serializable]
public class MCPServerConfig
{
public TransportType transportType = TransportType.STDIO;
public int port = 9000;
public LogLevel logLevel = LogLevel.Info;
public bool readOnlyMode = false;
public string[] allowedAssemblies = new[] {
"UnityEngine",
"UnityEngine.CoreModule",
"UnityEditor"
};
public int maxHierarchyDepth = 10;
public int maxBatchSize = 100;
public int responseTimeoutMs = 5000;
}
Integration with MCP Clients
Claude Desktop Integration
To integrate with Claude Desktop, edit the configuration file:
- macOS:
~/Library/Application\ Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%/Claude/claude_desktop_config.json
Add the following configuration:
{
"mcpServers": {
"unity": {
"command": "Unity",
"args": [
"-projectPath", "/path/to/your/unity/project",
"-executeMethod", "Unity.MCP.Editor.Server.UnityMCPServer.StartServer"
],
"env": {
"UNITY_MCP_TRANSPORT": "stdio",
"UNITY_MCP_LOG_LEVEL": "info"
}
}
}
}
VS Code Integration
For VS Code with GitHub Copilot, add to settings.json:
{
"github.copilot.chat.mcpServers": [
{
"name": "unity",
"command": "Unity",
"args": [
"-projectPath", "${workspaceFolder}",
"-executeMethod", "Unity.MCP.Editor.Server.UnityMCPServer.StartServer"
],
"env": {
"UNITY_MCP_TRANSPORT": "stdio",
"UNITY_MCP_LOG_LEVEL": "info"
}
}
]
}
Core Functionality and Technical Usage
Available Tools
The Unity MCP server exposes several specialized tools for game development:
1. Scene Hierarchy Operations
-
unity_get_hierarchy: Retrieves scene hierarchy
public class GetHierarchyOptions { public string sceneName; public int maxDepth = 10; public bool includeComponents = true; public bool includeInactive = true; public string rootPath = null; }
-
unity_find_objects: Finds objects matching criteria
public class FindObjectsOptions { public string namePattern; public string componentType; public Dictionary<string, object> componentProperties; public bool includeInactive = false; public int maxResults = 20; }
2. Component Manipulation
-
unity_get_component_properties: Retrieves component data
public class GetComponentPropertiesOptions { public string objectPath; public string componentType; public string[] propertyNames = null; // If null, get all properties }
-
unity_set_component_properties: Modifies component data
public class SetComponentPropertiesOptions { public string objectPath; public string componentType; public Dictionary<string, object> properties; }
3. Asset Operations
-
unity_list_assets: Lists project assets
public class ListAssetsOptions { public string folderPath = ""; public string filter = "*"; public string[] assetTypes = null; public bool recursive = false; public int maxResults = 100; }
-
unity_get_asset_content: Retrieves asset content
public class GetAssetContentOptions { public string assetPath; public string responseFormat = "json"; // json, text, base64 }
4. Play Mode Operations
-
unity_enter_play_mode: Starts play mode
public class EnterPlayModeOptions { public bool maximizeOnPlay = false; public bool pauseOnStart = false; }
-
unity_execute_runtime_method: Invokes methods during play mode
public class ExecuteRuntimeMethodOptions { public string objectPath; public string methodName; public object[] parameters; }
Technical Usage Patterns
Scene Analysis and Optimization
// Get hierarchy with components
const sceneHierarchy = await tools.unity_get_hierarchy({
sceneName: "MainLevel",
includeComponents: true,
maxDepth: 20
});
// Analyze lights in the scene
const lightObjects = await tools.unity_find_objects({
componentType: "UnityEngine.Light",
includeInactive: true
});
// Find expensive real-time lights
const expensiveRealTimeLights = [];
for (const lightObj of lightObjects.objects) {
const lightProperties = await tools.unity_get_component_properties({
objectPath: lightObj.path,
componentType: "UnityEngine.Light"
});
if (lightProperties.properties.type === 1 && // Point light
lightProperties.properties.shadows !== 0 && // Shadows enabled
lightProperties.properties.range > 20) { // Large range
expensiveRealTimeLights.push({
path: lightObj.path,
intensity: lightProperties.properties.intensity,
range: lightProperties.properties.range,
shadowType: lightProperties.properties.shadows
});
}
}
// Optimize expensive lights by converting to baked
for (const light of expensiveRealTimeLights) {
await tools.unity_set_component_properties({
objectPath: light.path,
componentType: "UnityEngine.Light",
properties: {
mode: 2, // Baked mode
shadows: 0 // No shadows
}
});
console.log(`Optimized light: ${light.path}`);
}
// Log optimization summary
console.log(`Optimized ${expensiveRealTimeLights.length} expensive real-time lights`);
Runtime Gameplay Testing
// Enter play mode
await tools.unity_enter_play_mode({
pauseOnStart: true
});
// Find the player character
const playerObject = await tools.unity_find_objects({
namePattern: "Player",
componentType: "PlayerController"
});
if (playerObject.objects.length === 0) {
console.error("Player not found in scene");
return;
}
const playerPath = playerObject.objects[0].path;
// Resume game
await tools.unity_execute_editor_method({
typeName: "UnityEditor.EditorApplication",
methodName: "isPaused",
parameters: [false],
isStatic: true
});
// Wait a few seconds for game to initialize
await new Promise(resolve => setTimeout(resolve, 3000));
// Test player jump function
await tools.unity_execute_runtime_method({
objectPath: playerPath,
methodName: "Jump",
parameters: []
});
// Wait for jump to complete
await new Promise(resolve => setTimeout(resolve, 1000));
// Get player position after jump
const transformProps = await tools.unity_get_component_properties({
objectPath: playerPath,
componentType: "UnityEngine.Transform",
propertyNames: ["position"]
});
// Monitor key player stats
const playerStats = await tools.unity_get_component_properties({
objectPath: playerPath,
componentType: "PlayerStats",
propertyNames: ["health", "stamina", "experience"]
});
console.log("Player position after jump:", transformProps.properties.position);
console.log("Player stats:", playerStats.properties);
Advanced Implementation Considerations
Editor Lifecycle Management
Unity MCP implements robust editor state handling:
[InitializeOnLoad]
public class EditorLifecycleManager
{
private static UnityMCPServer _server;
static EditorLifecycleManager()
{
EditorApplication.update += OnEditorUpdate;
EditorApplication.quitting += OnEditorQuitting;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
}
private static void OnEditorUpdate()
{
if (_server != null)
{
_server.ProcessPendingMessages();
}
}
private static void OnEditorQuitting()
{
if (_server != null)
{
_server.ShutdownServer();
_server = null;
}
}
private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (_server != null)
{
_server.NotifyPlayModeStateChanged(state);
}
}
private static void OnAfterAssemblyReload()
{
// Restart the server if it was previously running
var config = MCPServerConfig.LoadFromEditorPrefs();
if (config != null && config.autoStartOnReload)
{
StartServer(config);
}
}
public static void StartServer(MCPServerConfig config = null)
{
if (_server == null)
{
_server = new UnityMCPServer(config);
_server.StartServer();
}
}
}
Safe Object Serialization
To safely convert Unity objects to JSON and back:
public class UnityObjectSerializer
{
public static Dictionary<string, object> SerializeObject(UnityEngine.Object obj)
{
var result = new Dictionary<string, object>();
if (obj == null)
return result;
SerializedObject serializedObj = new SerializedObject(obj);
SerializedProperty prop = serializedObj.GetIterator();
if (prop.NextVisible(true))
{
do
{
// Skip unsupported property types
if (prop.propertyType == SerializedPropertyType.ObjectReference &&
prop.objectReferenceValue is MonoBehaviour)
continue;
// Convert property to serializable value
result[prop.propertyPath] = ConvertPropertyToSerializable(prop);
} while (prop.NextVisible(false));
}
return result;
}
private static object ConvertPropertyToSerializable(SerializedProperty property)
{
switch (property.propertyType)
{
case SerializedPropertyType.Integer:
return property.intValue;
case SerializedPropertyType.Float:
return property.floatValue;
case SerializedPropertyType.Boolean:
return property.boolValue;
case SerializedPropertyType.String:
return property.stringValue;
case SerializedPropertyType.Vector2:
return new Dictionary<string, float> {
{"x", property.vector2Value.x},
{"y", property.vector2Value.y}
};
case SerializedPropertyType.Vector3:
return new Dictionary<string, float> {
{"x", property.vector3Value.x},
{"y", property.vector3Value.y},
{"z", property.vector3Value.z}
};
// Additional property types...
default:
return property.propertyPath;
}
}
public static void DeserializeToObject(UnityEngine.Object obj, Dictionary<string, object> values)
{
if (obj == null || values == null)
return;
SerializedObject serializedObj = new SerializedObject(obj);
bool modified = false;
foreach (var kvp in values)
{
SerializedProperty prop = serializedObj.FindProperty(kvp.Key);
if (prop != null && ApplyValueToProperty(prop, kvp.Value))
{
modified = true;
}
}
if (modified)
{
serializedObj.ApplyModifiedProperties();
EditorUtility.SetDirty(obj);
}
}
private static bool ApplyValueToProperty(SerializedProperty property, object value)
{
try
{
switch (property.propertyType)
{
case SerializedPropertyType.Integer:
property.intValue = Convert.ToInt32(value);
break;
case SerializedPropertyType.Float:
property.floatValue = Convert.ToSingle(value);
break;
case SerializedPropertyType.Boolean:
property.boolValue = Convert.ToBoolean(value);
break;
case SerializedPropertyType.String:
property.stringValue = value.ToString();
break;
// Additional property types...
default:
return false;
}
return true;
}
catch (Exception ex)
{
Debug.LogError($"Failed to set property {property.propertyPath}: {ex.Message}");
return false;
}
}
}
Troubleshooting Common Technical Issues
Editor Integration Problems
If the MCP server fails to start or communicate with Unity:
- Check Unity console for initialization errors
- Verify script execution order to ensure proper initialization
- Use the diagnostic tool to test connectivity:
[MenuItem("Tools/MCP/Diagnose Connection")]
public static void DiagnoseConnection()
{
var config = MCPServerConfig.LoadFromEditorPrefs();
Debug.Log($"MCP Transport: {config.transportType}");
Debug.Log($"MCP Port: {config.port}");
try
{
switch (config.transportType)
{
case TransportType.WebSocket:
DiagnoseWebSocketConnection(config.port);
break;
case TransportType.SSE:
DiagnoseSSEConnection(config.port);
break;
case TransportType.STDIO:
DiagnoseStdioConnection();
break;
}
}
catch (Exception ex)
{
Debug.LogError($"Diagnostic failed: {ex.Message}");
}
}
Scene Synchronization Issues
When scene modifications don't appear to take effect:
-
Force a scene refresh after operations:
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); SceneView.RepaintAll();
-
Check for undo registration to ensure changes persist:
Undo.RecordObject(targetObject, "MCP Modification"); // Make changes EditorUtility.SetDirty(targetObject);
-
Implement scene change detection for reliable state:
EditorApplication.hierarchyChanged += OnHierarchyChanged; EditorApplication.projectChanged += OnProjectChanged; private void OnHierarchyChanged() { // Invalidate cached hierarchy data _cachedHierarchy = null; }
Conclusion
Unity MCP servers represent a powerful technical bridge between conversational AI and the Unity game development environment. By implementing the Model Context Protocol with Unity's comprehensive API ecosystem, these servers enable AI assistants to actively participate in the game development process, from scene analysis and component manipulation to runtime testing and asset management.
This implementation establishes a foundation for building AI-assisted game development workflows that can significantly accelerate productivity while maintaining the fine-grained control that game developers require. As both MCP and Unity continue to evolve, we can expect further advancements in real-time collaboration, procedural content generation, and intelligent debugging capabilities.
For game developers seeking to leverage AI assistance in their Unity projects, Unity MCP offers a standardized approach that respects Unity's architecture while unlocking powerful new interaction modalities for AI assistants. By seamlessly integrating language models into the Unity Editor, developers can focus on creative tasks while delegating technical implementation and analysis to their AI collaborators, creating a more efficient and innovative game development process.