Unity MCP Server

by justinpbarnett
Verified
using UnityEngine; using UnityEditor; using System.IO; using Newtonsoft.Json.Linq; using System.Collections.Generic; namespace UnityMCP.Editor.Commands { /// <summary> /// Handles asset-related commands for the MCP Server /// </summary> public static class AssetCommandHandler { /// <summary> /// Imports an asset into the project /// </summary> public static object ImportAsset(JObject @params) { try { string sourcePath = (string)@params["source_path"]; string targetPath = (string)@params["target_path"]; if (string.IsNullOrEmpty(sourcePath)) return new { success = false, error = "Source path cannot be empty" }; if (string.IsNullOrEmpty(targetPath)) return new { success = false, error = "Target path cannot be empty" }; if (!File.Exists(sourcePath)) return new { success = false, error = $"Source file not found: {sourcePath}" }; // Ensure target directory exists string targetDir = Path.GetDirectoryName(targetPath); if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); } // Copy file to target location File.Copy(sourcePath, targetPath, true); AssetDatabase.Refresh(); return new { success = true, message = $"Successfully imported asset to {targetPath}", path = targetPath }; } catch (System.Exception e) { return new { success = false, error = $"Failed to import asset: {e.Message}", stackTrace = e.StackTrace }; } } /// <summary> /// Instantiates a prefab in the current scene /// </summary> public static object InstantiatePrefab(JObject @params) { try { string prefabPath = (string)@params["prefab_path"]; if (string.IsNullOrEmpty(prefabPath)) return new { success = false, error = "Prefab path cannot be empty" }; Vector3 position = new( (float)@params["position_x"], (float)@params["position_y"], (float)@params["position_z"] ); Vector3 rotation = new( (float)@params["rotation_x"], (float)@params["rotation_y"], (float)@params["rotation_z"] ); GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath); if (prefab == null) { return new { success = false, error = $"Prefab not found at path: {prefabPath}" }; } GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab); if (instance == null) { return new { success = false, error = $"Failed to instantiate prefab: {prefabPath}" }; } instance.transform.position = position; instance.transform.rotation = Quaternion.Euler(rotation); return new { success = true, message = "Successfully instantiated prefab", instance_name = instance.name }; } catch (System.Exception e) { return new { success = false, error = $"Failed to instantiate prefab: {e.Message}", stackTrace = e.StackTrace }; } } /// <summary> /// Creates a new prefab from a GameObject in the scene /// </summary> public static object CreatePrefab(JObject @params) { try { string objectName = (string)@params["object_name"]; string prefabPath = (string)@params["prefab_path"]; if (string.IsNullOrEmpty(objectName)) return new { success = false, error = "GameObject name cannot be empty" }; if (string.IsNullOrEmpty(prefabPath)) return new { success = false, error = "Prefab path cannot be empty" }; // Ensure prefab has .prefab extension if (!prefabPath.ToLower().EndsWith(".prefab")) prefabPath = $"{prefabPath}.prefab"; GameObject sourceObject = GameObject.Find(objectName); if (sourceObject == null) { return new { success = false, error = $"GameObject not found in scene: {objectName}" }; } // Ensure target directory exists string targetDir = Path.GetDirectoryName(prefabPath); if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); } GameObject prefab = PrefabUtility.SaveAsPrefabAsset(sourceObject, prefabPath); if (prefab == null) { return new { success = false, error = "Failed to create prefab. Verify the path is writable." }; } return new { success = true, message = $"Successfully created prefab at {prefabPath}", path = prefabPath }; } catch (System.Exception e) { return new { success = false, error = $"Failed to create prefab: {e.Message}", stackTrace = e.StackTrace, sourceInfo = $"Object: {@params["object_name"]}, Path: {@params["prefab_path"]}" }; } } /// <summary> /// Applies changes from a prefab instance back to the original prefab asset /// </summary> public static object ApplyPrefab(JObject @params) { string objectName = (string)@params["object_name"]; GameObject instance = GameObject.Find(objectName); if (instance == null) { return new { error = $"GameObject not found in scene: {objectName}" }; } Object prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(instance); if (prefabAsset == null) { return new { error = "Selected object is not a prefab instance" }; } PrefabUtility.ApplyPrefabInstance(instance, InteractionMode.AutomatedAction); return new { message = "Successfully applied changes to prefab asset" }; } /// <summary> /// Gets a list of assets in the project, optionally filtered by type /// </summary> public static object GetAssetList(JObject @params) { string type = (string)@params["type"]; string searchPattern = (string)@params["search_pattern"] ?? "*"; string folder = (string)@params["folder"] ?? "Assets"; var guids = AssetDatabase.FindAssets(searchPattern, new[] { folder }); var assets = new List<object>(); foreach (var guid in guids) { var path = AssetDatabase.GUIDToAssetPath(guid); var assetType = AssetDatabase.GetMainAssetTypeAtPath(path); // Skip if type filter is specified and doesn't match if (!string.IsNullOrEmpty(type) && assetType?.Name != type) continue; assets.Add(new { name = Path.GetFileNameWithoutExtension(path), path, type = assetType?.Name ?? "Unknown", guid }); } return new { assets }; } } }