Unity Mcp

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:

  1. Transport Layer:

    • STDIO (Standard Input/Output): Direct process communication
    • SSE (Server-Sent Events): HTTP-based asynchronous communication
    • WebSocket: Bidirectional real-time communication
  2. Resource Types:

    • Prompts: Templated Unity operation patterns
    • Tools: Executable Unity Editor and runtime operations
    • Resources: Scene hierarchy, component data, and asset information
  3. 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:

  1. Editor Integration: Hooks into Unity's editor lifecycle and event system
  2. Reflection System: Dynamically accesses Unity's internal APIs and serialized objects
  3. Serialization Handler: Converts between Unity's object model and JSON-compatible structures
  4. Tool Implementations: Translates MCP commands to Unity API calls
  5. Scene Observer: Monitors scene changes and maintains consistent state

Setup and Installation

Prerequisites

To implement Unity MCP, ensure you have:

  1. Unity 2021.3 LTS or newer
  2. Basic understanding of Unity Editor scripting
  3. .NET 6.0+ support enabled in your project
  4. 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:

  1. Open Unity and navigate to Window > Package Manager
  2. Click the "+" button and select "Add package from git URL..."
  3. Enter: https://github.com/modelcontextprotocol/unity-mcp.git

Option 2: Manual Package Installation

  1. Clone the repository:

    git clone https://github.com/modelcontextprotocol/unity-mcp.git
  2. Copy the unity-mcp folder to your Unity project's Packages directory

Option 3: Using Smithery

npx -y @smithery/cli install unity-mcp --client claude

Configuration

The Unity MCP server accepts several configuration parameters:

  1. Server Configuration:

    • UNITY_MCP_PORT: Port number for WebSocket/SSE transport
    • UNITY_MCP_TRANSPORT: Transport method (stdio, sse, websocket)
    • UNITY_MCP_LOG_LEVEL: Logging verbosity (error, warning, info, debug)
  2. Security Controls:

    • UNITY_MCP_READONLY_MODE: Prevent modifications to scene/assets
    • UNITY_MCP_ALLOWED_ASSEMBLIES: Restrict reflection to specific assemblies
    • UNITY_MCP_SCRIPT_EXECUTION: Control C# script execution permissions
  3. Performance Settings:

    • UNITY_MCP_MAX_HIERARCHY_DEPTH: Limit scene hierarchy traversal depth
    • UNITY_MCP_BATCH_SIZE: Maximum objects processed in a batch
    • UNITY_MCP_RESPONSE_TIMEOUT: Tool operation timeout in milliseconds

Example configuration in Unity Editor:

  1. Navigate to Edit > Project Settings > MCP Server
  2. 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:

  1. Check Unity console for initialization errors
  2. Verify script execution order to ensure proper initialization
  3. 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:

  1. Force a scene refresh after operations:

    EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    SceneView.RepaintAll();
  2. Check for undo registration to ensure changes persist:

    Undo.RecordObject(targetObject, "MCP Modification");
    // Make changes
    EditorUtility.SetDirty(targetObject);
  3. 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.