Skip to main content
Glama
PrefabOperations.cs15.8 kB
using System; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace LocalMcp.UnityServer { /// <summary> /// Provides Prefab operations for Unity MCP Server. /// Handles prefab instantiation, creation, and management. /// </summary> public static class PrefabOperations { /// <summary> /// Instantiates a prefab from an asset path. /// </summary> /// <param name="paramsJson">JSON parameters containing prefab path and optional parent/position</param> /// <param name="id">JSON-RPC request ID</param> /// <returns>JSON-RPC response with instantiated GameObject info</returns> public static string InstantiatePrefab(string paramsJson, object id) { #if UNITY_EDITOR try { var parameters = JsonUtility.FromJson<InstantiatePrefabParams>(paramsJson); if (string.IsNullOrEmpty(parameters.prefabPath)) { return JsonRpcResponseHelper.InvalidParams("prefabPath is required", id); } // Load prefab from asset path GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(parameters.prefabPath); if (prefab == null) { return JsonRpcResponseHelper.ErrorMessage($"Prefab not found at path: {parameters.prefabPath}", id); } // Instantiate prefab GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; if (instance == null) { return JsonRpcResponseHelper.ErrorMessage("Failed to instantiate prefab", id); } // Set name if provided if (!string.IsNullOrEmpty(parameters.name)) { instance.name = parameters.name; } // Set parent if provided if (!string.IsNullOrEmpty(parameters.parentPath)) { GameObject parent = GameObject.Find(parameters.parentPath); if (parent != null) { instance.transform.SetParent(parent.transform, false); } } // Set position if provided if (parameters.position != null) { if (parameters.localPosition) { instance.transform.localPosition = new Vector3( parameters.position.x, parameters.position.y, parameters.position.z ); } else { instance.transform.position = new Vector3( parameters.position.x, parameters.position.y, parameters.position.z ); } } // Set rotation if provided if (parameters.rotation != null) { Quaternion rotation = Quaternion.Euler( parameters.rotation.x, parameters.rotation.y, parameters.rotation.z ); if (parameters.localPosition) { instance.transform.localRotation = rotation; } else { instance.transform.rotation = rotation; } } // Build GameObject path string path = GetGameObjectPath(instance); var result = new InstantiatePrefabResult { success = true, instancePath = path, instanceName = instance.name, instanceId = instance.GetInstanceID() }; var response = JsonRpcResponse.Success(result, id); return response.ToJson(); } catch (Exception e) { Debug.LogError($"[MCP] InstantiatePrefab error: {e.Message}\n{e.StackTrace}"); return JsonRpcResponseHelper.ErrorMessage($"Failed to instantiate prefab: {e.Message}", id); } #else return JsonRpcResponseHelper.ErrorMessage("InstantiatePrefab requires Unity Editor", id); #endif } /// <summary> /// Creates a prefab from a GameObject in the scene. /// </summary> /// <param name="paramsJson">JSON parameters containing gameObjectPath and prefab save path</param> /// <param name="id">JSON-RPC request ID</param> /// <returns>JSON-RPC response with prefab creation result</returns> public static string CreatePrefab(string paramsJson, object id) { #if UNITY_EDITOR try { var parameters = JsonUtility.FromJson<CreatePrefabParams>(paramsJson); if (string.IsNullOrEmpty(parameters.gameObjectPath)) { return JsonRpcResponseHelper.InvalidParams("gameObjectPath is required", id); } if (string.IsNullOrEmpty(parameters.prefabPath)) { return JsonRpcResponseHelper.InvalidParams("prefabPath is required", id); } GameObject go = GameObject.Find(parameters.gameObjectPath); if (go == null) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' not found", id); } // Ensure path ends with .prefab string prefabPath = parameters.prefabPath; if (!prefabPath.EndsWith(".prefab")) { prefabPath += ".prefab"; } // Create directory if needed string directory = System.IO.Path.GetDirectoryName(prefabPath); if (!string.IsNullOrEmpty(directory) && !System.IO.Directory.Exists(directory)) { System.IO.Directory.CreateDirectory(directory); } // Create prefab GameObject prefab = PrefabUtility.SaveAsPrefabAsset(go, prefabPath); if (prefab == null) { return JsonRpcResponseHelper.ErrorMessage("Failed to create prefab", id); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); var result = new CreatePrefabResult { success = true, prefabPath = prefabPath, prefabName = prefab.name }; var response = JsonRpcResponse.Success(result, id); return response.ToJson(); } catch (Exception e) { Debug.LogError($"[MCP] CreatePrefab error: {e.Message}\n{e.StackTrace}"); return JsonRpcResponseHelper.ErrorMessage($"Failed to create prefab: {e.Message}", id); } #else return JsonRpcResponseHelper.ErrorMessage("CreatePrefab requires Unity Editor", id); #endif } /// <summary> /// Applies changes from a prefab instance to the prefab asset. /// </summary> /// <param name="paramsJson">JSON parameters containing gameObjectPath</param> /// <param name="id">JSON-RPC request ID</param> /// <returns>JSON-RPC response</returns> public static string ApplyPrefabChanges(string paramsJson, object id) { #if UNITY_EDITOR try { var parameters = JsonUtility.FromJson<PrefabInstanceParams>(paramsJson); if (string.IsNullOrEmpty(parameters.gameObjectPath)) { return JsonRpcResponseHelper.InvalidParams("gameObjectPath is required", id); } GameObject go = GameObject.Find(parameters.gameObjectPath); if (go == null) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' not found", id); } // Check if it's a prefab instance if (!PrefabUtility.IsPartOfPrefabInstance(go)) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' is not a prefab instance", id); } // Get prefab root GameObject prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(go); // Apply all overrides PrefabUtility.ApplyPrefabInstance(prefabRoot, InteractionMode.AutomatedAction); var result = new PrefabOperationResult { success = true, message = $"Prefab changes applied for '{go.name}'" }; var response = JsonRpcResponse.Success(result, id); return response.ToJson(); } catch (Exception e) { Debug.LogError($"[MCP] ApplyPrefabChanges error: {e.Message}\n{e.StackTrace}"); return JsonRpcResponseHelper.ErrorMessage($"Failed to apply prefab changes: {e.Message}", id); } #else return JsonRpcResponseHelper.ErrorMessage("ApplyPrefabChanges requires Unity Editor", id); #endif } /// <summary> /// Reverts changes on a prefab instance to match the prefab asset. /// </summary> /// <param name="paramsJson">JSON parameters containing gameObjectPath</param> /// <param name="id">JSON-RPC request ID</param> /// <returns>JSON-RPC response</returns> public static string RevertPrefabChanges(string paramsJson, object id) { #if UNITY_EDITOR try { var parameters = JsonUtility.FromJson<PrefabInstanceParams>(paramsJson); if (string.IsNullOrEmpty(parameters.gameObjectPath)) { return JsonRpcResponseHelper.InvalidParams("gameObjectPath is required", id); } GameObject go = GameObject.Find(parameters.gameObjectPath); if (go == null) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' not found", id); } // Check if it's a prefab instance if (!PrefabUtility.IsPartOfPrefabInstance(go)) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' is not a prefab instance", id); } // Get prefab root GameObject prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(go); // Revert all overrides PrefabUtility.RevertPrefabInstance(prefabRoot, InteractionMode.AutomatedAction); var result = new PrefabOperationResult { success = true, message = $"Prefab changes reverted for '{go.name}'" }; var response = JsonRpcResponse.Success(result, id); return response.ToJson(); } catch (Exception e) { Debug.LogError($"[MCP] RevertPrefabChanges error: {e.Message}\n{e.StackTrace}"); return JsonRpcResponseHelper.ErrorMessage($"Failed to revert prefab changes: {e.Message}", id); } #else return JsonRpcResponseHelper.ErrorMessage("RevertPrefabChanges requires Unity Editor", id); #endif } /// <summary> /// Unpacks a prefab instance completely. /// </summary> /// <param name="paramsJson">JSON parameters containing gameObjectPath</param> /// <param name="id">JSON-RPC request ID</param> /// <returns>JSON-RPC response</returns> public static string UnpackPrefab(string paramsJson, object id) { #if UNITY_EDITOR try { var parameters = JsonUtility.FromJson<PrefabInstanceParams>(paramsJson); if (string.IsNullOrEmpty(parameters.gameObjectPath)) { return JsonRpcResponseHelper.InvalidParams("gameObjectPath is required", id); } GameObject go = GameObject.Find(parameters.gameObjectPath); if (go == null) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' not found", id); } // Check if it's a prefab instance if (!PrefabUtility.IsPartOfPrefabInstance(go)) { return JsonRpcResponseHelper.ErrorMessage($"GameObject '{parameters.gameObjectPath}' is not a prefab instance", id); } // Get prefab root GameObject prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(go); // Unpack prefab completely PrefabUtility.UnpackPrefabInstance(prefabRoot, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); var result = new PrefabOperationResult { success = true, message = $"Prefab unpacked for '{go.name}'" }; var response = JsonRpcResponse.Success(result, id); return response.ToJson(); } catch (Exception e) { Debug.LogError($"[MCP] UnpackPrefab error: {e.Message}\n{e.StackTrace}"); return JsonRpcResponseHelper.ErrorMessage($"Failed to unpack prefab: {e.Message}", id); } #else return JsonRpcResponseHelper.ErrorMessage("UnpackPrefab requires Unity Editor", id); #endif } private static string GetGameObjectPath(GameObject go) { string path = go.name; Transform current = go.transform.parent; while (current != null) { path = current.name + "/" + path; current = current.parent; } return path; } } #region Data Structures [Serializable] public class InstantiatePrefabParams { public string prefabPath; public string name; public string parentPath; public Vector3Data position; public Vector3Data rotation; public bool localPosition = false; } [Serializable] public class InstantiatePrefabResult { public bool success; public string instancePath; public string instanceName; public int instanceId; } [Serializable] public class CreatePrefabParams { public string gameObjectPath; public string prefabPath; } [Serializable] public class CreatePrefabResult { public bool success; public string prefabPath; public string prefabName; } [Serializable] public class PrefabInstanceParams { public string gameObjectPath; } [Serializable] public class PrefabOperationResult { public bool success; public string message; } #endregion }

Latest Blog Posts

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/dsgarage/UniMCP4CC'

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