Skip to content

Commit 3c8eebc

Browse files
committed
Improved packages and tools in this MCP
Now they properly run while unity is in the background or minimized. Avoiding timeout issues
1 parent 3acfb23 commit 3c8eebc

File tree

7 files changed

+97
-632
lines changed

7 files changed

+97
-632
lines changed

Editor/McpUnity.Editor.asmdef

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
{
22
"name": "McpUnity.Editor",
33
"rootNamespace": "",
4-
"references": [],
4+
"references": [
5+
"GUID:478a2357cc57436488a56e564b08d223"
6+
],
57
"includePlatforms": [
68
"Editor"
79
],

Editor/Tools/AddPackageTool.cs

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
namespace McpUnity.Tools
1414
{
1515
/// <summary>
16-
/// Tool for adding packages into the Unity Package Manager
16+
/// Tool for adding new packages into the Unity Package Manager
1717
/// </summary>
1818
public class AddPackageTool : McpToolBase
1919
{
@@ -33,7 +33,7 @@ private class PackageOperation
3333
public AddPackageTool()
3434
{
3535
Name = "add_package";
36-
Description = "Adds packages into the Unity Package Manager";
36+
Description = "Adds a new packages into the Unity Package Manager";
3737
IsAsync = true; // Package Manager operations are asynchronous
3838
}
3939

@@ -44,71 +44,59 @@ public AddPackageTool()
4444
/// <param name="tcs">TaskCompletionSource to set the result or exception</param>
4545
public override void ExecuteAsync(JObject parameters, TaskCompletionSource<JObject> tcs)
4646
{
47-
try
47+
// Extract source parameter
48+
string source = parameters["source"]?.ToObject<string>();
49+
if (string.IsNullOrEmpty(source))
4850
{
49-
// Extract source parameter
50-
string source = parameters["source"]?.ToObject<string>();
51-
if (string.IsNullOrEmpty(source))
52-
{
51+
tcs.SetResult(McpUnitySocketHandler.CreateErrorResponse(
52+
"Required parameter 'source' not provided",
53+
"validation_error"
54+
));
55+
return;
56+
}
57+
58+
// Create and register the operation
59+
var operation = new PackageOperation
60+
{
61+
CompletionSource = tcs
62+
};
63+
64+
switch (source.ToLowerInvariant())
65+
{
66+
case "registry":
67+
operation.Request = AddFromRegistry(parameters, tcs);
68+
break;
69+
case "github":
70+
operation.Request = AddFromGitHub(parameters, tcs);
71+
break;
72+
case "disk":
73+
operation.Request = AddFromDisk(parameters, tcs);
74+
break;
75+
default:
5376
tcs.SetResult(McpUnitySocketHandler.CreateErrorResponse(
54-
"Required parameter 'source' not provided",
77+
$"Unknown method '{source}'. Valid methods are: registry, github, disk",
5578
"validation_error"
5679
));
5780
return;
58-
}
59-
60-
// Create and register the operation
61-
var operation = new PackageOperation
62-
{
63-
CompletionSource = tcs
64-
};
65-
66-
switch (source.ToLowerInvariant())
67-
{
68-
case "registry":
69-
operation.Request = AddFromRegistry(parameters, tcs);
70-
break;
71-
case "github":
72-
operation.Request = AddFromGitHub(parameters, tcs);
73-
break;
74-
case "disk":
75-
operation.Request = AddFromDisk(parameters, tcs);
76-
break;
77-
default:
78-
tcs.SetResult(McpUnitySocketHandler.CreateErrorResponse(
79-
$"Unknown method '{source}'. Valid methods are: registry, github, disk",
80-
"validation_error"
81-
));
82-
return;
83-
}
84-
85-
// If request creation failed, the error has already been set on the tcs
86-
if (operation.Request == null)
87-
{
88-
return;
89-
}
81+
}
82+
83+
// If request creation failed, the error has already been set on the tcs
84+
if (operation.Request == null)
85+
{
86+
return;
87+
}
88+
89+
lock (_activeOperations)
90+
{
91+
_activeOperations.Add(operation);
9092

91-
lock (_activeOperations)
93+
// Register update callback if not already registered
94+
if (!_updateCallbackRegistered)
9295
{
93-
_activeOperations.Add(operation);
94-
95-
// Register update callback if not already registered
96-
if (!_updateCallbackRegistered)
97-
{
98-
EditorApplication.update += CheckOperationsCompletion;
99-
_updateCallbackRegistered = true;
100-
}
96+
EditorApplication.update += CheckOperationsCompletion;
97+
_updateCallbackRegistered = true;
10198
}
10299
}
103-
catch (Exception ex)
104-
{
105-
// Handle any uncaught exceptions
106-
Debug.LogError($"[MCP Unity] Exception in AddPackageTool.ExecuteAsync: {ex}");
107-
tcs.SetResult(McpUnitySocketHandler.CreateErrorResponse(
108-
$"Internal error: {ex.Message}",
109-
"internal_error"
110-
));
111-
}
112100
}
113101

114102
/// <summary>

Editor/UnityBridge/McpUnitySocketHandler.cs

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using WebSocketSharp.Server;
99
using McpUnity.Tools;
1010
using McpUnity.Resources;
11+
using Unity.EditorCoroutines.Editor;
12+
using System.Collections;
1113

1214
namespace McpUnity.Unity
1315
{
@@ -57,26 +59,29 @@ protected override async void OnMessage(MessageEventArgs e)
5759
var method = requestJson["method"]?.ToString();
5860
var parameters = requestJson["params"] as JObject ?? new JObject();
5961
var requestId = requestJson["id"]?.ToString();
60-
61-
JObject responseJson;
62+
// We need to dispatch to Unity's main thread and wait for completion
63+
var tcs = new TaskCompletionSource<JObject>();
6264

6365
if (string.IsNullOrEmpty(method))
6466
{
65-
responseJson = CreateErrorResponse("Missing method in request", "invalid_request");
67+
tcs.SetResult(CreateErrorResponse("Missing method in request", "invalid_request"));
6668
}
6769
else if (_server.TryGetTool(method, out var tool))
6870
{
69-
responseJson = await ExecuteTool(tool, parameters);
71+
EditorCoroutineUtility.StartCoroutineOwnerless(ExecuteTool(tool, parameters, tcs));
7072
}
7173
else if (_server.TryGetResource(method, out var resource))
7274
{
73-
responseJson = await FetchResource(resource, parameters);
75+
EditorCoroutineUtility.StartCoroutineOwnerless(FetchResourceCoroutine(resource, parameters, tcs));
7476
}
7577
else
7678
{
77-
responseJson = CreateErrorResponse($"Unknown method: {method}", "unknown_method");
79+
tcs.SetResult(CreateErrorResponse($"Unknown method: {method}", "unknown_method"));
7880
}
7981

82+
// Wait for the task to complete
83+
JObject responseJson = await tcs.Task;
84+
8085
// Format as JSON-RPC 2.0 response
8186
JObject jsonRpcResponse = CreateResponse(requestId, responseJson);
8287
string responseStr = jsonRpcResponse.ToString(Formatting.None);
@@ -121,66 +126,52 @@ protected override void OnError(ErrorEventArgs e)
121126
/// <summary>
122127
/// Execute a tool with the provided parameters
123128
/// </summary>
124-
private async Task<JObject> ExecuteTool(McpToolBase tool, JObject parameters)
129+
private IEnumerator ExecuteTool(McpToolBase tool, JObject parameters, TaskCompletionSource<JObject> tcs)
125130
{
126-
// We need to dispatch to Unity's main thread
127-
var tcs = new TaskCompletionSource<JObject>();
128-
129-
UnityEditor.EditorApplication.delayCall += () =>
131+
try
130132
{
131-
try
133+
if (tool.IsAsync)
132134
{
133-
if (tool.IsAsync)
134-
{
135-
tool.ExecuteAsync(parameters, tcs);
136-
}
137-
else
138-
{
139-
var result = tool.Execute(parameters);
140-
tcs.SetResult(result);
141-
}
135+
tool.ExecuteAsync(parameters, tcs);
142136
}
143-
catch (Exception ex)
137+
else
144138
{
145-
Debug.LogError($"[MCP Unity] Error executing tool {tool.Name}: {ex.Message}");
146-
tcs.SetResult(CreateErrorResponse(
147-
$"Failed to execute tool {tool.Name}: {ex.Message}",
148-
"tool_execution_error"
149-
));
139+
var result = tool.Execute(parameters);
140+
tcs.SetResult(result);
150141
}
151-
};
142+
}
143+
catch (Exception ex)
144+
{
145+
Debug.LogError($"[MCP Unity] Error executing tool {tool.Name}: {ex.Message}");
146+
tcs.SetResult(CreateErrorResponse(
147+
$"Failed to execute tool {tool.Name}: {ex.Message}",
148+
"tool_execution_error"
149+
));
150+
}
152151

153-
// Wait for the task to complete
154-
return await tcs.Task;
152+
yield return null;
155153
}
156154

157155
/// <summary>
158156
/// Fetch a resource with the provided parameters
159157
/// </summary>
160-
private async Task<JObject> FetchResource(McpResourceBase resource, JObject parameters)
158+
private IEnumerator FetchResourceCoroutine(McpResourceBase resource, JObject parameters, TaskCompletionSource<JObject> tcs)
161159
{
162-
// We need to dispatch to Unity's main thread and wait for completion
163-
var tcs = new TaskCompletionSource<JObject>();
164-
165-
UnityEditor.EditorApplication.delayCall += () =>
160+
try
166161
{
167-
try
168-
{
169-
var result = resource.Fetch(parameters);
170-
tcs.SetResult(result);
171-
}
172-
catch (Exception ex)
173-
{
174-
Debug.LogError($"[MCP Unity] Error fetching resource {resource.Name}: {ex.Message}");
175-
tcs.SetResult(CreateErrorResponse(
176-
$"Failed to fetch resource {resource.Name}: {ex.Message}",
177-
"resource_fetch_error"
178-
));
179-
}
180-
};
162+
var result = resource.Fetch(parameters);
163+
tcs.SetResult(result);
164+
}
165+
catch (Exception ex)
166+
{
167+
Debug.LogError($"[MCP Unity] Error fetching resource {resource.Name}: {ex.Message}");
168+
tcs.SetResult(CreateErrorResponse(
169+
$"Failed to fetch resource {resource.Name}: {ex.Message}",
170+
"resource_fetch_error"
171+
));
172+
}
181173

182-
// Wait for the task to complete
183-
return await tcs.Task;
174+
yield return null;
184175
}
185176

186177
/// <summary>

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
[![](https://img.shields.io/github/last-commit/CoderGamester/mcp-unity 'Last Commit')](https://github.com/CoderGamester/mcp-unity/commits/main)
1111
[![](https://img.shields.io/badge/License-MIT-red.svg 'MIT License')](https://opensource.org/licenses/MIT)
1212

13-
<a href="https://glama.ai/mcp/servers/@CoderGamester/mcp-unity">
14-
<img width="380" height="200" src="https://glama.ai/mcp/servers/@CoderGamester/mcp-unity/badge" alt="Unity MCP server" />
15-
</a>
16-
1713
```
1814
,/(/. *(/,
1915
*/(((((/. *((((((*.
@@ -72,6 +68,10 @@ This MCP currently provides the following <ins>resources</ins>:
7268
- Node.js 18 or later - to [start the server](#start-server)
7369
- npm 9 or later - to [debug the server](#debug-server)
7470

71+
<a href="https://glama.ai/mcp/servers/@CoderGamester/mcp-unity">
72+
<img width="400" height="200" src="https://glama.ai/mcp/servers/@CoderGamester/mcp-unity/badge" alt="Unity MCP server" />
73+
</a>
74+
7575
## <a name="install-server"></a>Installation
7676

7777
Installing this MCP Unity Server is a multi-step process:

0 commit comments

Comments
 (0)