|
8 | 8 | using WebSocketSharp.Server; |
9 | 9 | using McpUnity.Tools; |
10 | 10 | using McpUnity.Resources; |
| 11 | +using Unity.EditorCoroutines.Editor; |
| 12 | +using System.Collections; |
11 | 13 |
|
12 | 14 | namespace McpUnity.Unity |
13 | 15 | { |
@@ -57,26 +59,29 @@ protected override async void OnMessage(MessageEventArgs e) |
57 | 59 | var method = requestJson["method"]?.ToString(); |
58 | 60 | var parameters = requestJson["params"] as JObject ?? new JObject(); |
59 | 61 | 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>(); |
62 | 64 |
|
63 | 65 | if (string.IsNullOrEmpty(method)) |
64 | 66 | { |
65 | | - responseJson = CreateErrorResponse("Missing method in request", "invalid_request"); |
| 67 | + tcs.SetResult(CreateErrorResponse("Missing method in request", "invalid_request")); |
66 | 68 | } |
67 | 69 | else if (_server.TryGetTool(method, out var tool)) |
68 | 70 | { |
69 | | - responseJson = await ExecuteTool(tool, parameters); |
| 71 | + EditorCoroutineUtility.StartCoroutineOwnerless(ExecuteTool(tool, parameters, tcs)); |
70 | 72 | } |
71 | 73 | else if (_server.TryGetResource(method, out var resource)) |
72 | 74 | { |
73 | | - responseJson = await FetchResource(resource, parameters); |
| 75 | + EditorCoroutineUtility.StartCoroutineOwnerless(FetchResourceCoroutine(resource, parameters, tcs)); |
74 | 76 | } |
75 | 77 | else |
76 | 78 | { |
77 | | - responseJson = CreateErrorResponse($"Unknown method: {method}", "unknown_method"); |
| 79 | + tcs.SetResult(CreateErrorResponse($"Unknown method: {method}", "unknown_method")); |
78 | 80 | } |
79 | 81 |
|
| 82 | + // Wait for the task to complete |
| 83 | + JObject responseJson = await tcs.Task; |
| 84 | + |
80 | 85 | // Format as JSON-RPC 2.0 response |
81 | 86 | JObject jsonRpcResponse = CreateResponse(requestId, responseJson); |
82 | 87 | string responseStr = jsonRpcResponse.ToString(Formatting.None); |
@@ -121,66 +126,52 @@ protected override void OnError(ErrorEventArgs e) |
121 | 126 | /// <summary> |
122 | 127 | /// Execute a tool with the provided parameters |
123 | 128 | /// </summary> |
124 | | - private async Task<JObject> ExecuteTool(McpToolBase tool, JObject parameters) |
| 129 | + private IEnumerator ExecuteTool(McpToolBase tool, JObject parameters, TaskCompletionSource<JObject> tcs) |
125 | 130 | { |
126 | | - // We need to dispatch to Unity's main thread |
127 | | - var tcs = new TaskCompletionSource<JObject>(); |
128 | | - |
129 | | - UnityEditor.EditorApplication.delayCall += () => |
| 131 | + try |
130 | 132 | { |
131 | | - try |
| 133 | + if (tool.IsAsync) |
132 | 134 | { |
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); |
142 | 136 | } |
143 | | - catch (Exception ex) |
| 137 | + else |
144 | 138 | { |
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); |
150 | 141 | } |
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 | + } |
152 | 151 |
|
153 | | - // Wait for the task to complete |
154 | | - return await tcs.Task; |
| 152 | + yield return null; |
155 | 153 | } |
156 | 154 |
|
157 | 155 | /// <summary> |
158 | 156 | /// Fetch a resource with the provided parameters |
159 | 157 | /// </summary> |
160 | | - private async Task<JObject> FetchResource(McpResourceBase resource, JObject parameters) |
| 158 | + private IEnumerator FetchResourceCoroutine(McpResourceBase resource, JObject parameters, TaskCompletionSource<JObject> tcs) |
161 | 159 | { |
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 |
166 | 161 | { |
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 | + } |
181 | 173 |
|
182 | | - // Wait for the task to complete |
183 | | - return await tcs.Task; |
| 174 | + yield return null; |
184 | 175 | } |
185 | 176 |
|
186 | 177 | /// <summary> |
|
0 commit comments