Skip to content

Commit a17df1e

Browse files
authored
feat(batch_execute): improve error handling with success detection and fail-fast support (#531)
- Add DetermineCallSucceeded() to check command success via IMcpResponse interface or JObject/JToken 'success' field - Track invocationFailureCount and set anyCommandFailed flag when commands fail - Implement fail-fast behavior to stop batch execution on first failure when failFast=true - Update commandResults to use computed callSucceeded value instead of hardcoded true feat(game_object_create): enhance asset
1 parent ea55c44 commit a17df1e

File tree

2 files changed

+83
-7
lines changed

2 files changed

+83
-7
lines changed

MCPForUnity/Editor/Tools/BatchExecute.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,28 @@ public static async Task<object> HandleCommand(JObject @params)
9191
try
9292
{
9393
var result = await CommandRegistry.InvokeCommandAsync(toolName, commandParams).ConfigureAwait(true);
94-
invocationSuccessCount++;
94+
bool callSucceeded = DetermineCallSucceeded(result);
95+
if (callSucceeded)
96+
{
97+
invocationSuccessCount++;
98+
}
99+
else
100+
{
101+
invocationFailureCount++;
102+
anyCommandFailed = true;
103+
}
95104

96105
commandResults.Add(new
97106
{
98107
tool = toolName,
99-
callSucceeded = true,
108+
callSucceeded,
100109
result
101110
});
111+
112+
if (!callSucceeded && failFast)
113+
{
114+
break;
115+
}
102116
}
103117
catch (Exception ex)
104118
{
@@ -134,6 +148,39 @@ public static async Task<object> HandleCommand(JObject @params)
134148
: new ErrorResponse("One or more commands failed.", data);
135149
}
136150

151+
private static bool DetermineCallSucceeded(object result)
152+
{
153+
if (result == null)
154+
{
155+
return true;
156+
}
157+
158+
if (result is IMcpResponse response)
159+
{
160+
return response.Success;
161+
}
162+
163+
if (result is JObject obj)
164+
{
165+
var successToken = obj["success"];
166+
if (successToken != null && successToken.Type == JTokenType.Boolean)
167+
{
168+
return successToken.Value<bool>();
169+
}
170+
}
171+
172+
if (result is JToken token)
173+
{
174+
var successToken = token["success"];
175+
if (successToken != null && successToken.Type == JTokenType.Boolean)
176+
{
177+
return successToken.Value<bool>();
178+
}
179+
}
180+
181+
return true;
182+
}
183+
137184
private static JObject NormalizeParameterKeys(JObject source)
138185
{
139186
if (source == null)

MCPForUnity/Editor/Tools/GameObjects/GameObjectCreate.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ internal static object Handle(JObject @params)
2929

3030
// --- Try Instantiating Prefab First ---
3131
string originalPrefabPath = prefabPath;
32-
if (!string.IsNullOrEmpty(prefabPath))
32+
if (!saveAsPrefab && !string.IsNullOrEmpty(prefabPath))
3333
{
34-
if (!prefabPath.Contains("/") && !prefabPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
34+
string extension = System.IO.Path.GetExtension(prefabPath);
35+
36+
if (!prefabPath.Contains("/") && (string.IsNullOrEmpty(extension) || extension.Equals(".prefab", StringComparison.OrdinalIgnoreCase)))
3537
{
3638
string prefabNameOnly = prefabPath;
3739
McpLog.Info($"[ManageGameObject.Create] Searching for prefab named: '{prefabNameOnly}'");
@@ -51,11 +53,38 @@ internal static object Handle(JObject @params)
5153
McpLog.Info($"[ManageGameObject.Create] Found unique prefab at path: '{prefabPath}'");
5254
}
5355
}
54-
else if (!prefabPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
56+
else if (prefabPath.Contains("/") && string.IsNullOrEmpty(extension))
5557
{
56-
McpLog.Warn($"[ManageGameObject.Create] Provided prefabPath '{prefabPath}' does not end with .prefab. Assuming it's missing and appending.");
58+
McpLog.Warn($"[ManageGameObject.Create] Provided prefabPath '{prefabPath}' has no extension. Assuming it's a prefab and appending .prefab.");
5759
prefabPath += ".prefab";
5860
}
61+
else if (!prefabPath.Contains("/") && !string.IsNullOrEmpty(extension) && !extension.Equals(".prefab", StringComparison.OrdinalIgnoreCase))
62+
{
63+
string fileName = prefabPath;
64+
string fileNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(fileName);
65+
McpLog.Info($"[ManageGameObject.Create] Searching for asset file named: '{fileName}'");
66+
67+
string[] guids = AssetDatabase.FindAssets(fileNameWithoutExtension);
68+
var matches = guids
69+
.Select(g => AssetDatabase.GUIDToAssetPath(g))
70+
.Where(p => p.EndsWith("/" + fileName, StringComparison.OrdinalIgnoreCase) || p.Equals(fileName, StringComparison.OrdinalIgnoreCase))
71+
.ToArray();
72+
73+
if (matches.Length == 0)
74+
{
75+
return new ErrorResponse($"Asset file '{fileName}' not found anywhere in the project.");
76+
}
77+
else if (matches.Length > 1)
78+
{
79+
string foundPaths = string.Join(", ", matches);
80+
return new ErrorResponse($"Multiple assets found matching file name '{fileName}': {foundPaths}. Please provide a more specific path.");
81+
}
82+
else
83+
{
84+
prefabPath = matches[0];
85+
McpLog.Info($"[ManageGameObject.Create] Found unique asset at path: '{prefabPath}'");
86+
}
87+
}
5988

6089
GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
6190
if (prefabAsset != null)
@@ -83,7 +112,7 @@ internal static object Handle(JObject @params)
83112
}
84113
else
85114
{
86-
McpLog.Warn($"[ManageGameObject.Create] Prefab asset not found at path: '{prefabPath}'. Will proceed to create new object if specified.");
115+
return new ErrorResponse($"Asset not found or not a GameObject at path: '{prefabPath}'.");
87116
}
88117
}
89118

0 commit comments

Comments
 (0)