Skip to content

Commit cbe9b3a

Browse files
Merge pull request #87 from justinpbarnett/bugfix/python-server-status
Bugfix/python server status
2 parents 9f855d6 + 4a3f4e7 commit cbe9b3a

File tree

2 files changed

+82
-52
lines changed

2 files changed

+82
-52
lines changed

UnityMcpBridge/Editor/Helpers/ServerInstaller.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,7 @@ public static void EnsureServerInstalled()
3333
}
3434
else
3535
{
36-
string pyprojectPath = Path.Combine(
37-
saveLocation,
38-
ServerFolder,
39-
"src",
40-
"pyproject.toml"
41-
);
42-
string installedVersion = ParseVersionFromPyproject(
43-
File.ReadAllText(pyprojectPath)
44-
);
36+
string installedVersion = GetInstalledVersion();
4537
string latestVersion = GetLatestVersion();
4638

4739
if (IsNewerVersion(latestVersion, installedVersion))
@@ -148,10 +140,24 @@ private static void InstallServer(string location)
148140
RunCommand("git", $"checkout {BranchName}", workingDirectory: location);
149141
}
150142

143+
/// <summary>
144+
/// Fetches the currently installed version from the local pyproject.toml file.
145+
/// </summary>
146+
public static string GetInstalledVersion()
147+
{
148+
string pyprojectPath = Path.Combine(
149+
GetSaveLocation(),
150+
ServerFolder,
151+
"src",
152+
"pyproject.toml"
153+
);
154+
return ParseVersionFromPyproject(File.ReadAllText(pyprojectPath));
155+
}
156+
151157
/// <summary>
152158
/// Fetches the latest version from the GitHub pyproject.toml file.
153159
/// </summary>
154-
private static string GetLatestVersion()
160+
public static string GetLatestVersion()
155161
{
156162
using WebClient webClient = new();
157163
string pyprojectContent = webClient.DownloadString(PyprojectUrl);
@@ -188,7 +194,7 @@ private static string ParseVersionFromPyproject(string content)
188194
/// <summary>
189195
/// Compares two version strings to determine if the latest is newer.
190196
/// </summary>
191-
private static bool IsNewerVersion(string latest, string installed)
197+
public static bool IsNewerVersion(string latest, string installed)
192198
{
193199
int[] latestParts = latest.Split('.').Select(int.Parse).ToArray();
194200
int[] installedParts = installed.Split('.').Select(int.Parse).ToArray();

UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.IO;
4-
using System.Net.Sockets;
53
using System.Runtime.InteropServices;
6-
using System.Text;
7-
using System.Threading.Tasks;
84
using Newtonsoft.Json;
95
using UnityEditor;
106
using UnityEngine;
@@ -18,13 +14,11 @@ public class UnityMcpEditorWindow : EditorWindow
1814
{
1915
private bool isUnityBridgeRunning = false;
2016
private Vector2 scrollPosition;
21-
private string claudeConfigStatus = "Not configured";
22-
private string cursorConfigStatus = "Not configured";
23-
private string pythonServerStatus = "Not Connected";
24-
private Color pythonServerStatusColor = Color.red;
17+
private string pythonServerInstallationStatus = "Not Installed";
18+
private Color pythonServerInstallationStatusColor = Color.red;
2519
private const int unityPort = 6400; // Hardcoded Unity port
2620
private const int mcpPort = 6500; // Hardcoded MCP port
27-
private McpClients mcpClients = new();
21+
private readonly McpClients mcpClients = new();
2822

2923
[MenuItem("Window/Unity MCP")]
3024
public static void ShowWindow()
@@ -34,7 +28,8 @@ public static void ShowWindow()
3428

3529
private void OnEnable()
3630
{
37-
// Check initial states
31+
UpdatePythonServerInstallationStatus();
32+
3833
isUnityBridgeRunning = UnityMcpBridge.IsRunning;
3934
foreach (McpClient mcpClient in mcpClients.clients)
4035
{
@@ -57,12 +52,39 @@ private Color GetStatusColor(McpStatus status)
5752
};
5853
}
5954

55+
private void UpdatePythonServerInstallationStatus()
56+
{
57+
string serverPath = ServerInstaller.GetServerPath();
58+
59+
if (File.Exists(Path.Combine(serverPath, "server.py")))
60+
{
61+
string installedVersion = ServerInstaller.GetInstalledVersion();
62+
string latestVersion = ServerInstaller.GetLatestVersion();
63+
64+
if (ServerInstaller.IsNewerVersion(latestVersion, installedVersion))
65+
{
66+
pythonServerInstallationStatus = "Newer Version Available";
67+
pythonServerInstallationStatusColor = Color.yellow;
68+
}
69+
else
70+
{
71+
pythonServerInstallationStatus = "Up to Date";
72+
pythonServerInstallationStatusColor = Color.green;
73+
}
74+
}
75+
else
76+
{
77+
pythonServerInstallationStatus = "Not Installed";
78+
pythonServerInstallationStatusColor = Color.red;
79+
}
80+
}
81+
6082
private void ConfigurationSection(McpClient mcpClient)
6183
{
6284
// Calculate if we should use half-width layout
6385
// Minimum width for half-width layout is 400 pixels
6486
bool useHalfWidth = position.width >= 800;
65-
float sectionWidth = useHalfWidth ? position.width / 2 - 15 : position.width - 20;
87+
float sectionWidth = useHalfWidth ? (position.width / 2) - 15 : position.width - 20;
6688

6789
// Begin horizontal layout if using half-width
6890
if (useHalfWidth && mcpClients.clients.IndexOf(mcpClient) % 2 == 0)
@@ -106,9 +128,11 @@ private void ConfigurationSection(McpClient mcpClient)
106128
EditorGUILayout.Space(8);
107129

108130
// Configure button with improved styling
109-
GUIStyle buttonStyle = new(GUI.skin.button);
110-
buttonStyle.padding = new RectOffset(15, 15, 5, 5);
111-
buttonStyle.margin = new RectOffset(10, 10, 5, 5);
131+
GUIStyle buttonStyle = new(GUI.skin.button)
132+
{
133+
padding = new RectOffset(15, 15, 5, 5),
134+
margin = new RectOffset(10, 10, 5, 5),
135+
};
112136

113137
// Create muted button style for Manual Setup
114138
GUIStyle mutedButtonStyle = new(buttonStyle);
@@ -156,7 +180,11 @@ private void ConfigurationSection(McpClient mcpClient)
156180
private void DrawStatusDot(Rect statusRect, Color statusColor)
157181
{
158182
Rect dotRect = new(statusRect.x + 6, statusRect.y + 4, 12, 12);
159-
Vector3 center = new(dotRect.x + dotRect.width / 2, dotRect.y + dotRect.height / 2, 0);
183+
Vector3 center = new(
184+
dotRect.x + (dotRect.width / 2),
185+
dotRect.y + (dotRect.height / 2),
186+
0
187+
);
160188
float radius = dotRect.width / 2;
161189

162190
// Draw the main dot
@@ -191,14 +219,14 @@ private void OnGUI()
191219
);
192220
EditorGUILayout.Space(10);
193221

194-
// Python Server Status Section
222+
// Python Server Installation Status Section
195223
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
196224
EditorGUILayout.LabelField("Python Server Status", EditorStyles.boldLabel);
197225

198226
// Status indicator with colored dot
199-
var statusRect = EditorGUILayout.BeginHorizontal(GUILayout.Height(20));
200-
DrawStatusDot(statusRect, pythonServerStatusColor);
201-
EditorGUILayout.LabelField(" " + pythonServerStatus);
227+
Rect installStatusRect = EditorGUILayout.BeginHorizontal(GUILayout.Height(20));
228+
DrawStatusDot(installStatusRect, pythonServerInstallationStatusColor);
229+
EditorGUILayout.LabelField(" " + pythonServerInstallationStatus);
202230
EditorGUILayout.EndHorizontal();
203231

204232
EditorGUILayout.LabelField($"Unity Port: {unityPort}");
@@ -249,13 +277,13 @@ private void ToggleUnityBridge()
249277
private string WriteToConfig(string pythonDir, string configPath)
250278
{
251279
// Create configuration object for unityMCP
252-
var unityMCPConfig = new McpConfigServer
280+
McpConfigServer unityMCPConfig = new()
253281
{
254282
command = "uv",
255283
args = new[] { "--directory", pythonDir, "run", "server.py" },
256284
};
257285

258-
var jsonSettings = new JsonSerializerSettings { Formatting = Formatting.Indented };
286+
JsonSerializerSettings jsonSettings = new() { Formatting = Formatting.Indented };
259287

260288
// Read existing config if it exists
261289
string existingJson = "{}";
@@ -267,16 +295,13 @@ private string WriteToConfig(string pythonDir, string configPath)
267295
}
268296
catch (Exception e)
269297
{
270-
UnityEngine.Debug.LogWarning($"Error reading existing config: {e.Message}.");
298+
Debug.LogWarning($"Error reading existing config: {e.Message}.");
271299
}
272300
}
273301

274302
// Parse the existing JSON while preserving all properties
275303
dynamic existingConfig = JsonConvert.DeserializeObject(existingJson);
276-
if (existingConfig == null)
277-
{
278-
existingConfig = new Newtonsoft.Json.Linq.JObject();
279-
}
304+
existingConfig ??= new Newtonsoft.Json.Linq.JObject();
280305

281306
// Ensure mcpServers object exists
282307
if (existingConfig.mcpServers == null)
@@ -311,7 +336,7 @@ private void ShowManualInstructionsWindow(string configPath, McpClient mcpClient
311336
string pythonDir = FindPackagePythonDirectory();
312337

313338
// Create the manual configuration message
314-
var jsonConfig = new McpConfig
339+
McpConfig jsonConfig = new()
315340
{
316341
mcpServers = new McpConfigServers
317342
{
@@ -323,25 +348,26 @@ private void ShowManualInstructionsWindow(string configPath, McpClient mcpClient
323348
},
324349
};
325350

326-
var jsonSettings = new JsonSerializerSettings { Formatting = Formatting.Indented };
351+
JsonSerializerSettings jsonSettings = new() { Formatting = Formatting.Indented };
327352
string manualConfigJson = JsonConvert.SerializeObject(jsonConfig, jsonSettings);
328353

329354
ManualConfigEditorWindow.ShowWindow(configPath, manualConfigJson, mcpClient);
330355
}
331356

332357
private string FindPackagePythonDirectory()
333358
{
334-
string pythonDir = "/path/to/your/unity-mcp/Python";
359+
string pythonDir = ServerInstaller.GetServerPath();
335360

336361
try
337362
{
338363
// Try to find the package using Package Manager API
339-
var request = UnityEditor.PackageManager.Client.List();
364+
UnityEditor.PackageManager.Requests.ListRequest request =
365+
UnityEditor.PackageManager.Client.List();
340366
while (!request.IsCompleted) { } // Wait for the request to complete
341367

342368
if (request.Status == UnityEditor.PackageManager.StatusCode.Success)
343369
{
344-
foreach (var package in request.Result)
370+
foreach (UnityEditor.PackageManager.PackageInfo package in request.Result)
345371
{
346372
if (package.name == "com.justinpbarnett.unity-mcp")
347373
{
@@ -360,7 +386,7 @@ private string FindPackagePythonDirectory()
360386
}
361387
else if (request.Error != null)
362388
{
363-
UnityEngine.Debug.LogError("Failed to list packages: " + request.Error.message);
389+
Debug.LogError("Failed to list packages: " + request.Error.message);
364390
}
365391

366392
// If not found via Package Manager, try manual approaches
@@ -370,7 +396,7 @@ private string FindPackagePythonDirectory()
370396
Path.GetFullPath(Path.Combine(Application.dataPath, "unity-mcp", "Python")),
371397
};
372398

373-
foreach (var dir in possibleDirs)
399+
foreach (string dir in possibleDirs)
374400
{
375401
if (Directory.Exists(dir) && File.Exists(Path.Combine(dir, "server.py")))
376402
{
@@ -379,13 +405,11 @@ private string FindPackagePythonDirectory()
379405
}
380406

381407
// If still not found, return the placeholder path
382-
UnityEngine.Debug.LogWarning(
383-
"Could not find Python directory, using placeholder path"
384-
);
408+
Debug.LogWarning("Could not find Python directory, using placeholder path");
385409
}
386410
catch (Exception e)
387411
{
388-
UnityEngine.Debug.LogError($"Error finding package path: {e.Message}");
412+
Debug.LogError($"Error finding package path: {e.Message}");
389413
}
390414

391415
return pythonDir;
@@ -453,7 +477,7 @@ private string ConfigureMcpClient(McpClient mcpClient)
453477
}
454478

455479
ShowManualInstructionsWindow(configPath, mcpClient);
456-
UnityEngine.Debug.LogError(
480+
Debug.LogError(
457481
$"Failed to configure {mcpClient.name}: {e.Message}\n{e.StackTrace}"
458482
);
459483
return $"Failed to configure {mcpClient.name}";
@@ -471,7 +495,7 @@ McpClient mcpClient
471495
string pythonDir = FindPackagePythonDirectory();
472496

473497
// Create the manual configuration message
474-
var jsonConfig = new McpConfig
498+
McpConfig jsonConfig = new()
475499
{
476500
mcpServers = new McpConfigServers
477501
{
@@ -483,7 +507,7 @@ McpClient mcpClient
483507
},
484508
};
485509

486-
var jsonSettings = new JsonSerializerSettings { Formatting = Formatting.Indented };
510+
JsonSerializerSettings jsonSettings = new() { Formatting = Formatting.Indented };
487511
string manualConfigJson = JsonConvert.SerializeObject(jsonConfig, jsonSettings);
488512

489513
ManualConfigEditorWindow.ShowWindow(configPath, manualConfigJson, mcpClient);
@@ -518,7 +542,7 @@ private void CheckMcpConfiguration(McpClient mcpClient)
518542
}
519543

520544
string configJson = File.ReadAllText(configPath);
521-
var config = JsonConvert.DeserializeObject<McpConfig>(configJson);
545+
McpConfig config = JsonConvert.DeserializeObject<McpConfig>(configJson);
522546

523547
if (config?.mcpServers?.unityMCP != null)
524548
{

0 commit comments

Comments
 (0)