Fix manage prefabs (#405)

* Standardize import ordering and whitespace in plugin

The whitespace gave a warning in the asset store submission

* Fix manage_prefab tool structure

* Fix manage_editor actions

* Add get_component singular to manage_gameobject

* Improve uv cache clear error handling with lock detection and combined output

Replace simple stderr-only error reporting with combined stdout/stderr output. Add detection for "currently in-use" lock errors with helpful hint about waiting or using --force flag. Provide fallback message when command fails with no output.

* Improve error message formatting in uv cache clear failure logging
main
Marcus Sanatan 2025-11-28 18:47:11 -04:00 committed by GitHub
parent 2f63405069
commit adfc6f5e84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 72 additions and 66 deletions

View File

@ -54,7 +54,7 @@ namespace MCPForUnity.Editor.Dependencies.PlatformDetectors
// Try common uv command names // Try common uv command names
var commands = new[] { "uvx", "uv" }; var commands = new[] { "uvx", "uv" };
foreach (var cmd in commands) foreach (var cmd in commands)
{ {
try try

View File

@ -2,8 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using MCPForUnity.External.Tommy;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using MCPForUnity.External.Tommy;
using UnityEditor; using UnityEditor;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers

View File

@ -1,10 +1,10 @@
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers

View File

@ -2,10 +2,10 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEditor; using System.Text;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using UnityEditor;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -2,11 +2,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using MCPForUnity.Runtime.Serialization; // For Converters
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using MCPForUnity.Runtime.Serialization; // For Converters
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -1,7 +1,7 @@
using System; using System;
using UnityEditor;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Config; using MCPForUnity.Editor.Config;
using MCPForUnity.Editor.Constants;
using UnityEditor;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -1,6 +1,6 @@
using MCPForUnity.Editor.Constants;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using MCPForUnity.Editor.Constants;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -1,14 +1,14 @@
using System; using System;
using System.IO; using System.IO;
using UnityEditor;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Newtonsoft.Json;
using UnityEngine;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using Newtonsoft.Json;
using UnityEditor;
using UnityEngine;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -2,8 +2,8 @@ using Newtonsoft.Json;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {
public interface IMcpResponse public interface IMcpResponse
{ {
[JsonProperty("success")] [JsonProperty("success")]
bool Success { get; } bool Success { get; }
} }

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using UnityEngine;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Services.Transport.Transports; using MCPForUnity.Editor.Services.Transport.Transports;
using UnityEngine;
namespace MCPForUnity.Editor.Helpers namespace MCPForUnity.Editor.Helpers
{ {

View File

@ -1,7 +1,7 @@
using System; using System;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using MCPForUnity.Editor.Constants;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;

View File

@ -1,14 +1,14 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using MCPForUnity.Editor.Clients; using MCPForUnity.Editor.Clients;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models; using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using MCPForUnity.Editor.Constants;
using System.Linq;
namespace MCPForUnity.Editor.Migrations namespace MCPForUnity.Editor.Migrations
{ {

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using Newtonsoft.Json.Linq;
using UnityEditor.TestTools.TestRunner.Api; using UnityEditor.TestTools.TestRunner.Api;
namespace MCPForUnity.Editor.Resources.Tests namespace MCPForUnity.Editor.Resources.Tests

View File

@ -1,11 +1,11 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEditor;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services.Transport; using MCPForUnity.Editor.Services.Transport;
using MCPForUnity.Editor.Services.Transport.Transports; using MCPForUnity.Editor.Services.Transport.Transports;
using UnityEditor;
namespace MCPForUnity.Editor.Services namespace MCPForUnity.Editor.Services
{ {

View File

@ -1,10 +1,10 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEditor;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services.Transport; using MCPForUnity.Editor.Services.Transport;
using MCPForUnity.Editor.Windows; using MCPForUnity.Editor.Windows;
using UnityEditor;
namespace MCPForUnity.Editor.Services namespace MCPForUnity.Editor.Services
{ {

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Net; using System.Net;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using MCPForUnity.Editor.Constants;
namespace MCPForUnity.Editor.Services namespace MCPForUnity.Editor.Services
{ {

View File

@ -41,15 +41,24 @@ namespace MCPForUnity.Editor.Services
McpLog.Debug($"uv cache cleared successfully: {stdout}"); McpLog.Debug($"uv cache cleared successfully: {stdout}");
return true; return true;
} }
else string combinedOutput = string.Join(
{ Environment.NewLine,
string errorMessage = string.IsNullOrEmpty(stderr) new[] { stderr, stdout }.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()));
? "Unknown error"
: stderr;
McpLog.Error($"Failed to clear uv cache using '{uvCommand} {args}': {errorMessage}. Ensure uv is installed, available on PATH, or set an override in Advanced Settings."); string lockHint = (!string.IsNullOrEmpty(combinedOutput) &&
return false; combinedOutput.IndexOf("currently in-use", StringComparison.OrdinalIgnoreCase) >= 0)
? "Another uv process may be holding the cache lock; wait a moment and try again or clear with '--force' from a terminal."
: string.Empty;
if (string.IsNullOrEmpty(combinedOutput))
{
combinedOutput = "Command failed with no output. Ensure uv is installed, on PATH, or set an override in Advanced Settings.";
} }
McpLog.Error(
$"Failed to clear uv cache using '{uvCommand} {args}'. " +
$"Details: {combinedOutput}{(string.IsNullOrEmpty(lockHint) ? string.Empty : " Hint: " + lockHint)}");
return false;
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -1,9 +1,9 @@
using System; using System;
using UnityEditor;
using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services.Transport; using MCPForUnity.Editor.Services.Transport;
using MCPForUnity.Editor.Services.Transport.Transports; using MCPForUnity.Editor.Services.Transport.Transports;
using UnityEditor;
namespace MCPForUnity.Editor.Services namespace MCPForUnity.Editor.Services
{ {

View File

@ -1,22 +1,22 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Services.Transport;
using MCPForUnity.Editor.Tools;
using MCPForUnity.Editor.Tools.Prefabs;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Tools;
using MCPForUnity.Editor.Tools.Prefabs;
using MCPForUnity.Editor.Services.Transport;
namespace MCPForUnity.Editor.Services.Transport.Transports namespace MCPForUnity.Editor.Services.Transport.Transports
{ {

View File

@ -1,10 +1,10 @@
using System; using System;
using MCPForUnity.Editor.Config;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Dependencies; using MCPForUnity.Editor.Dependencies;
using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Dependencies.Models;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Windows; using MCPForUnity.Editor.Windows;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Config;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;

View File

@ -1,8 +1,8 @@
using System; using System;
using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEditorInternal; // Required for tag management using UnityEditorInternal; // Required for tag management
using MCPForUnity.Editor.Helpers;
namespace MCPForUnity.Editor.Tools namespace MCPForUnity.Editor.Tools
{ {

View File

@ -3,6 +3,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using MCPForUnity.Editor.Helpers; // For Response class
using MCPForUnity.Runtime.Serialization;
using Newtonsoft.Json; // Added for JsonSerializationException using Newtonsoft.Json; // Added for JsonSerializationException
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
@ -11,8 +13,6 @@ using UnityEditor.SceneManagement;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using MCPForUnity.Editor.Helpers; // For Response class
using MCPForUnity.Runtime.Serialization;
namespace MCPForUnity.Editor.Tools namespace MCPForUnity.Editor.Tools
{ {

View File

@ -2,12 +2,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using MCPForUnity.Editor.Helpers; // For Response class
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEditor.SceneManagement; using UnityEditor.SceneManagement;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using MCPForUnity.Editor.Helpers; // For Response class
namespace MCPForUnity.Editor.Tools namespace MCPForUnity.Editor.Tools
{ {

View File

@ -2,10 +2,10 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using MCPForUnity.Editor.Helpers;
namespace MCPForUnity.Editor.Tools namespace MCPForUnity.Editor.Tools
{ {

View File

@ -2,11 +2,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using MCPForUnity.Editor.Helpers; // For Response class
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using UnityEditor; using UnityEditor;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine; using UnityEngine;
using MCPForUnity.Editor.Helpers; // For Response class
namespace MCPForUnity.Editor.Tools namespace MCPForUnity.Editor.Tools
{ {

View File

@ -4,13 +4,13 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using MCPForUnity.Editor.Clients; using MCPForUnity.Editor.Clients;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models; using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace MCPForUnity.Editor.Windows.Components.ClientConfig namespace MCPForUnity.Editor.Windows.Components.ClientConfig
{ {

View File

@ -4,8 +4,8 @@ using System.Threading.Tasks;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.UIElements; using UnityEngine.UIElements;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services; using MCPForUnity.Editor.Services;
using MCPForUnity.Editor.Windows.Components.Settings; using MCPForUnity.Editor.Windows.Components.Settings;
using MCPForUnity.Editor.Windows.Components.Connection; using MCPForUnity.Editor.Windows.Components.Connection;
using MCPForUnity.Editor.Windows.Components.ClientConfig; using MCPForUnity.Editor.Windows.Components.ClientConfig;
@ -19,7 +19,7 @@ namespace MCPForUnity.Editor.Windows
private McpConnectionSection connectionSection; private McpConnectionSection connectionSection;
private McpClientConfigSection clientConfigSection; private McpClientConfigSection clientConfigSection;
private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new(); private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new();
public static void ShowWindow() public static void ShowWindow()
{ {
@ -102,8 +102,8 @@ namespace MCPForUnity.Editor.Windows
{ {
var clientConfigRoot = clientConfigTree.Instantiate(); var clientConfigRoot = clientConfigTree.Instantiate();
sectionsContainer.Add(clientConfigRoot); sectionsContainer.Add(clientConfigRoot);
clientConfigSection = new McpClientConfigSection(clientConfigRoot); clientConfigSection = new McpClientConfigSection(clientConfigRoot);
} }
// Initial updates // Initial updates
RefreshAllData(); RefreshAllData();

View File

@ -1,10 +1,10 @@
using System; using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using MCPForUnity.Editor.Dependencies; using MCPForUnity.Editor.Dependencies;
using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Dependencies.Models;
using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Helpers;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace MCPForUnity.Editor.Windows namespace MCPForUnity.Editor.Windows
{ {

View File

@ -13,8 +13,7 @@ from transport.legacy.unity_connection import async_send_command_with_retry
) )
async def manage_editor( async def manage_editor(
ctx: Context, ctx: Context,
action: Annotated[Literal["telemetry_status", "telemetry_ping", "play", "pause", "stop", "get_state", "get_project_root", "get_windows", action: Annotated[Literal["telemetry_status", "telemetry_ping", "play", "pause", "stop", "set_active_tool", "add_tag", "remove_tag", "add_layer", "remove_layer"], "Get and update the Unity Editor state."],
"get_active_tool", "get_selection", "get_prefab_stage", "set_active_tool", "add_tag", "remove_tag", "get_tags", "add_layer", "remove_layer", "get_layers"], "Get and update the Unity Editor state."],
wait_for_completion: Annotated[bool | str, wait_for_completion: Annotated[bool | str,
"Optional. If True, waits for certain actions (accepts true/false or 'true'/'false')"] | None = None, "Optional. If True, waits for certain actions (accepts true/false or 'true'/'false')"] | None = None,
tool_name: Annotated[str, tool_name: Annotated[str,

View File

@ -13,7 +13,7 @@ from transport.legacy.unity_connection import async_send_command_with_retry
) )
async def manage_gameobject( async def manage_gameobject(
ctx: Context, ctx: Context,
action: Annotated[Literal["create", "modify", "delete", "find", "add_component", "remove_component", "set_component_property", "get_components"], "Perform CRUD operations on GameObjects and components."], action: Annotated[Literal["create", "modify", "delete", "find", "add_component", "remove_component", "set_component_property", "get_components", "get_component"], "Perform CRUD operations on GameObjects and components."],
target: Annotated[str, target: Annotated[str,
"GameObject identifier by name or path for modify/delete/component actions"] | None = None, "GameObject identifier by name or path for modify/delete/component actions"] | None = None,
search_method: Annotated[Literal["by_id", "by_name", "by_path", "by_tag", "by_layer", "by_component"], search_method: Annotated[Literal["by_id", "by_name", "by_path", "by_tag", "by_layer", "by_component"],

View File

@ -8,11 +8,11 @@ from transport.legacy.unity_connection import async_send_command_with_retry
@mcp_for_unity_tool( @mcp_for_unity_tool(
description="Performs prefab operations (create, modify, delete, etc.)." description="Performs prefab operations (open_stage, close_stage, save_open_stage, create_from_gameobject)."
) )
async def manage_prefabs( async def manage_prefabs(
ctx: Context, ctx: Context,
action: Annotated[Literal["create", "modify", "delete", "get_components"], "Perform prefab operations."], action: Annotated[Literal["open_stage", "close_stage", "save_open_stage", "create_from_gameobject"], "Perform prefab operations."],
prefab_path: Annotated[str, prefab_path: Annotated[str,
"Prefab asset path relative to Assets e.g. Assets/Prefabs/favorite.prefab"] | None = None, "Prefab asset path relative to Assets e.g. Assets/Prefabs/favorite.prefab"] | None = None,
mode: Annotated[str, mode: Annotated[str,
@ -25,8 +25,6 @@ async def manage_prefabs(
"Allow replacing an existing prefab at the same path"] | None = None, "Allow replacing an existing prefab at the same path"] | None = None,
search_inactive: Annotated[bool, search_inactive: Annotated[bool,
"Include inactive objects when resolving the target name"] | None = None, "Include inactive objects when resolving the target name"] | None = None,
component_properties: Annotated[str,
"Component properties in JSON format"] | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
# Get active instance from session state # Get active instance from session state
# Removed session_state import # Removed session_state import