Skip to content

Commit 61c552e

Browse files
committed
Removed the async dependency of some tools that are rather syncronous
Took care of race condition when executing update on the unity package manager mutliple times in a row
1 parent 6b92996 commit 61c552e

15 files changed

+356
-295
lines changed

Editor/Services/TestRunnerService.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private void CollectTestItems(ITestAdaptor testAdaptor, List<TestItemInfo> tests
8080
/// <param name="completionSource">TaskCompletionSource to resolve when tests are complete</param>
8181
/// <param name="timeoutMinutes">Timeout in minutes, defaults to 10</param>
8282
/// <returns>Task that resolves with test results when tests are complete</returns>
83-
public async Task<JObject> ExecuteTests(
83+
public async void ExecuteTests(
8484
TestMode testMode,
8585
string testFilter,
8686
TaskCompletionSource<JObject> completionSource,
@@ -109,13 +109,11 @@ public async Task<JObject> ExecuteTests(
109109

110110
if (completedTask != completionSource.Task)
111111
{
112-
return McpUnitySocketHandler.CreateErrorResponse(
112+
completionSource.SetResult(McpUnitySocketHandler.CreateErrorResponse(
113113
$"Test run timed out after {timeoutMinutes} minutes",
114114
"test_runner_timeout"
115-
);
115+
));
116116
}
117-
118-
return completionSource.Task.Result;
119117
}
120118
}
121119

Editor/Tools/McpToolBase.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,43 @@ public abstract class McpToolBase
2020
/// Description of the tool's functionality
2121
/// </summary>
2222
public string Description { get; protected set; }
23+
24+
/// <summary>
25+
/// Flag indicating if the tool executes asynchronously on the main thread.
26+
/// If true, ExecuteAsync should be overridden.
27+
/// If false, Execute should be overridden.
28+
/// </summary>
29+
public bool IsAsync { get; protected set; } = false;
2330

2431
/// <summary>
25-
/// Execute the tool with the provided parameters
32+
/// Execute the tool asynchronously with the provided parameters.
33+
/// This should be overridden by tools that need to run on the Unity main thread
34+
/// or perform long-running operations without blocking the WebSocket handler.
2635
/// </summary>
2736
/// <param name="parameters">Tool parameters as a JObject</param>
28-
/// <returns>The result of the tool execution as a JObject</returns>
29-
public abstract Task<JObject> ExecuteAsync(JObject parameters);
37+
/// <param name="tcs">TaskCompletionSource to set the result or exception of the execution</param>
38+
public virtual void ExecuteAsync(JObject parameters, TaskCompletionSource<JObject> tcs)
39+
{
40+
// Default implementation for tools that don't override this.
41+
// Indicate that this method should have been overridden if IsAsync is true.
42+
tcs.TrySetException(new NotImplementedException("ExecuteAsync must be overridden if IsAsync is true."));
43+
}
3044

3145
/// <summary>
32-
/// Synchronous execution method for backward compatibility
46+
/// Execute the tool synchronously with the provided parameters.
47+
/// This should be overridden by tools that can execute quickly and directly
48+
/// within the WebSocket message handler thread.
3349
/// </summary>
3450
/// <param name="parameters">Tool parameters as a JObject</param>
35-
/// <returns>The result of the tool execution as a JObject</returns>
51+
/// <returns>The result of the tool execution as a JObject, or an error JObject</returns>
3652
public virtual JObject Execute(JObject parameters)
3753
{
38-
// Call the async method and wait for it to complete
39-
return ExecuteAsync(parameters).GetAwaiter().GetResult();
54+
// Default implementation for tools that don't override this.
55+
// Indicate that this method should have been overridden if IsAsync is false.
56+
return McpUnity.Unity.McpUnitySocketHandler.CreateErrorResponse(
57+
"Execute must be overridden if IsAsync is false.",
58+
"implementation_error"
59+
);
4060
}
4161
}
4262
}

Editor/Tools/MenuItemTool.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ public MenuItemTool()
1919
}
2020

2121
/// <summary>
22-
/// Execute the MenuItem tool with the provided parameters asynchronously
22+
/// Execute the MenuItem tool with the provided parameters synchronously
2323
/// </summary>
2424
/// <param name="parameters">Tool parameters as a JObject</param>
25-
public override Task<JObject> ExecuteAsync(JObject parameters)
25+
public override JObject Execute(JObject parameters)
2626
{
2727
// Extract parameters with defaults
2828
string menuPath = parameters["menuPath"]?.ToObject<string>();
2929
if (string.IsNullOrEmpty(menuPath))
3030
{
31-
return Task.FromResult(McpUnitySocketHandler.CreateErrorResponse(
31+
return McpUnitySocketHandler.CreateErrorResponse(
3232
"Required parameter 'menuPath' not provided",
3333
"validation_error"
34-
));
34+
);
3535
}
3636

3737
// Log the execution
@@ -41,13 +41,13 @@ public override Task<JObject> ExecuteAsync(JObject parameters)
4141
bool success = EditorApplication.ExecuteMenuItem(menuPath);
4242

4343
// Create the response
44-
return Task.FromResult(new JObject
44+
return new JObject
4545
{
4646
["success"] = success,
4747
["message"] = success
4848
? $"Successfully executed menu item: {menuPath}"
4949
: $"Failed to execute menu item: {menuPath}"
50-
});
50+
};
5151
}
5252
}
5353
}

Editor/Tools/NotifyMessageTool.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,44 @@ public NotifyMessageTool()
1717
}
1818

1919
/// <summary>
20-
/// Execute the NotifyMessage tool with the provided parameters asynchronously
20+
/// Execute the NotifyMessage tool with the provided parameters synchronously
2121
/// </summary>
2222
/// <param name="parameters">Tool parameters as a JObject</param>
23-
public override Task<JObject> ExecuteAsync(JObject parameters)
23+
public override JObject Execute(JObject parameters)
2424
{
2525
// Extract parameters
2626
string message = parameters["message"]?.ToObject<string>();
27+
string type = parameters["type"]?.ToObject<string>()?.ToLower() ?? "info";
28+
2729
if (string.IsNullOrEmpty(message))
2830
{
29-
return Task.FromResult(McpUnitySocketHandler.CreateErrorResponse(
31+
return McpUnitySocketHandler.CreateErrorResponse(
3032
"Required parameter 'message' not provided",
3133
"validation_error"
32-
));
34+
);
3335
}
34-
35-
string messageType = parameters["type"]?.ToObject<string>()?.ToLowerInvariant() ?? "info";
36-
37-
// Display the message in the Unity console based on the type
38-
switch (messageType)
36+
37+
// Log the message based on type
38+
switch (type)
3939
{
40-
case "warning":
41-
Debug.LogWarning($"[MCP Unity Notification] {message}");
42-
break;
4340
case "error":
44-
Debug.LogError($"[MCP Unity Notification] {message}");
41+
Debug.LogError($"[MCP]: {message}");
42+
break;
43+
case "warning":
44+
Debug.LogWarning($"[MCP]: {message}");
4545
break;
46-
case "info":
4746
default:
48-
Debug.Log($"[MCP Unity Notification] {message}");
47+
Debug.Log($"[MCP]: {message}");
4948
break;
5049
}
51-
52-
return Task.FromResult(new JObject
50+
51+
// Create the response
52+
return new JObject
5353
{
5454
["success"] = true,
5555
["message"] = $"Message displayed: {message}",
5656
["type"] = "text"
57-
});
57+
};
5858
}
5959
}
6060
}

0 commit comments

Comments
 (0)