Skip to main content
Glama

Unity Editor MCP Server

using System; using UnityEngine; using UnityEditor; using McpUnity.Utils; // For GameObjectHierarchyCreator and McpLogger using McpUnity.Unity; // For McpUnitySocketHandler using Newtonsoft.Json.Linq; // For JObject namespace McpUnity.Tools { /// <summary> /// Tool for updating or creating a GameObject in the Unity Editor. /// Supports setting name, tag, layer, active state, and static state by instance ID or hierarchy path. /// Returns a JObject result similar to UpdateComponentTool for consistency. /// </summary> public class UpdateGameObjectTool : McpToolBase { public UpdateGameObjectTool() { Name = "update_gameobject"; Description = "Updates or creates a GameObject and its properties (name, tag, layer, active state, static state) based on instance ID or object path."; IsAsync = false; // Operations are expected to be quick } /// <summary> /// Executes the update or creation of a GameObject based on the provided parameters. /// </summary> /// <param name="parameters">A JObject containing: instanceId (int?), objectPath (string), name (string), tag (string), layer (int?), isActiveSelf (bool?), isStatic (bool?)</param> /// <returns>JObject with success, message, instanceId, name, and path fields (see UpdateComponentTool for format)</returns> public override JObject Execute(JObject parameters) { // Extract parameters from JObject int? instanceId = parameters["instanceId"]?.ToObject<int?>(); string objectPath = parameters["objectPath"]?.ToObject<string>(); JObject gameObjectData = parameters["gameObjectData"] as JObject; string newName = gameObjectData? ["name"]?.ToObject<string>(); string newTag = gameObjectData? ["tag"]?.ToObject<string>(); int? newLayer = gameObjectData? ["layer"]?.ToObject<int?>(); bool? newIsActiveSelf = gameObjectData? ["isActiveSelf"]?.ToObject<bool?>(); bool? newIsStatic = gameObjectData? ["isStatic"]?.ToObject<bool?>(); GameObject targetGameObject = null; string identifierInfo = ""; // Identify or create the GameObject by instanceId or objectPath if (instanceId.HasValue) { targetGameObject = EditorUtility.InstanceIDToObject(instanceId.Value) as GameObject; identifierInfo = $"instance ID {instanceId.Value}"; } else if (!string.IsNullOrEmpty(objectPath)) { // Will create the GameObject if it doesn't exist targetGameObject = GameObjectHierarchyCreator.FindOrCreateHierarchicalGameObject(objectPath); identifierInfo = $"path '{objectPath}'"; } else { // Neither instanceId nor objectPath was provided return McpUnitySocketHandler.CreateErrorResponse("Either 'instanceId' or 'objectPath' must be provided.", "validation_error"); } // Check if we could not identify or create the GameObject if (targetGameObject == null) { return McpUnitySocketHandler.CreateErrorResponse($"Target GameObject could not be identified or created using {identifierInfo}.", "unknown_error"); } // Record for undo in Unity Editor Undo.RecordObject(targetGameObject, "Update GameObject Properties"); bool propertiesUpdated = false; string originalNameForLog = targetGameObject.name; // Update name if provided and different if (!string.IsNullOrEmpty(newName) && targetGameObject.name != newName) { targetGameObject.name = newName; propertiesUpdated = true; } // Update tag if provided and different, warn if tag doesn't exist if (!string.IsNullOrEmpty(newTag)) { bool tagExists = Array.Exists(UnityEditorInternal.InternalEditorUtility.tags, t => t.Equals(newTag)); if (!tagExists) { McpLogger.LogWarning($"UpdateGameObjectTool: Tag '{newTag}' does not exist for GameObject '{originalNameForLog}'. Tag not changed. Please create the tag in Unity's Tag Manager."); } else if (!targetGameObject.CompareTag(newTag)) { targetGameObject.tag = newTag; propertiesUpdated = true; } } // Update layer if provided and valid if (newLayer.HasValue) { if (newLayer.Value < 0 || newLayer.Value > 31) { McpLogger.LogWarning($"UpdateGameObjectTool: Invalid layer value {newLayer.Value} for GameObject '{originalNameForLog}'. Layer must be between 0 and 31. Layer not changed."); } else if (targetGameObject.layer != newLayer.Value) { targetGameObject.layer = newLayer.Value; propertiesUpdated = true; } } // Update active state if provided and different if (newIsActiveSelf.HasValue && targetGameObject.activeSelf != newIsActiveSelf.Value) { targetGameObject.SetActive(newIsActiveSelf.Value); propertiesUpdated = true; } // Update static state if provided and different if (newIsStatic.HasValue && targetGameObject.isStatic != newIsStatic.Value) { targetGameObject.isStatic = newIsStatic.Value; propertiesUpdated = true; } // Mark as dirty if any property was changed if (propertiesUpdated) { EditorUtility.SetDirty(targetGameObject); } // Compose result message and return as JObject (like UpdateComponentTool) return new JObject { ["success"] = true, ["type"] = "text", ["message"] = propertiesUpdated ? $"GameObject '{targetGameObject.name}' (identified by {identifierInfo}) updated successfully." : $"No properties were changed for GameObject '{targetGameObject.name}' (identified by {identifierInfo}).", ["instanceId"] = targetGameObject.GetInstanceID(), ["name"] = targetGameObject.name, ["path"] = GetGameObjectPath(targetGameObject) }; } /// <summary> /// Utility to get the hierarchy path of a GameObject (root/child/.../target) /// </summary> /// <param name="obj">The GameObject to get the path for</param> /// <returns>Hierarchy path as string</returns> private static string GetGameObjectPath(GameObject obj) { if (obj == null) return null; string path = "/" + obj.name; while (obj.transform.parent != null) { obj = obj.transform.parent.gameObject; path = "/" + obj.name + path; } return path; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CoderGamester/mcp-unity'

If you have feedback or need assistance with the MCP directory API, please join our Discord server