Skip to content

Commit 1d6d8c6

Browse files
authored
New UI and work without MCP server embedded (#313)
* First pass at new UI * Point to new UI * Refactor: New Service-Based MCP Editor Window Architecture We separate the business logic from the UI rendering of the new editor window with new services. I didn't go full Dependency Injection, not sure if I want to add those deps to the install as yet, but service location is fairly straightforward. Some differences with the old window: - No more Auto-Setup, users will manually decide what they want to do - Removed Python detection warning, we have a setup wizard now - Added explicit path overrides for `uv` and the MCP server itself * style: add flex-shrink and overflow handling to improve UI element scaling * fix: update UI configuration and visibility when client status changes * feat: add menu item to open legacy MCP configuration window * refactor: improve editor window lifecycle handling with proper update subscription * feat: add auto-verification of bridge health when connected * fix: update Claude Code MCP server registration to use lowercase unityMCP name and correct the manual installation instructions * fix: add Claude CLI directory to PATH for node/nvm environments * Clarify how users will see MCP tools * Add a keyboard shortcut to open the window * feat: add server download UI and improve installation status messaging This is needed for the Unity Asset Store, which doesn't have the Python server embedded. * feat: add dynamic asset path detection to support both Package Manager and Asset Store installations * fix: replace unicode emojis with escaped characters in status messages * feat: add server package creation and GitHub release publishing to version bump workflow * fix: add v prefix to server package filename in release workflow * Fix download location * style: improve dropdown and settings layout responsiveness with flex-shrink and max-width * feat: add package.json version detection and refactor path utilities * refactor: simplify imports and use fully qualified names in ServerInstaller.cs * refactor: replace Unity Debug.Log calls with custom McpLog class * fix: extract server files to temp directory before moving to final location * docs: add v6 UI documentation and screenshots with service architecture overview * docs: add new UI Toolkit-based editor window with service architecture and path overrides * feat: improve package path resolution to support Package Manager and Asset Store installations * Change Claude Code's casing back to "UnityMCP" There's no need to break anything as yet * fix: update success dialog text to clarify manual bridge start requirement * refactor: move RefreshDebounce and ManageScriptRefreshHelpers classes inside namespace * feat: add Asset Store fallback path detection for package root lookup * fix: update server installation success message to be more descriptive * refactor: replace Unity Debug.Log calls with custom McpLog utility * fix: add file existence check before opening configuration file * refactor: simplify asset path handling and remove redundant helper namespace references * docs: update code block syntax highlighting in UI changes doc * docs: add code block syntax highlighting for file structure example * feat: import UnityEditor.UIElements namespace for UI components for Unity 2021 compatibility * refactor: rename Python server references to MCP server for consistency * fix: reset client status label color after error state is cleared * Replace the phrase "Python server" with "MCP server" * MInor doc clarification * docs: add path override methods for UV and Claude CLI executables * docs: update service locator registration method name from SetCustomImplementation to Register
1 parent 2c53943 commit 1d6d8c6

34 files changed

+3482
-126
lines changed

.github/workflows/bump-version.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,30 @@ jobs:
108108
109109
git tag -a "$TAG" -m "Version ${NEW_VERSION}"
110110
git push origin "$TAG"
111+
112+
- name: Package server for release
113+
env:
114+
NEW_VERSION: ${{ steps.compute.outputs.new_version }}
115+
shell: bash
116+
run: |
117+
set -euo pipefail
118+
cd MCPForUnity/UnityMcpServer~
119+
zip -r ../../mcp-for-unity-server-v${NEW_VERSION}.zip .
120+
cd ../..
121+
ls -lh mcp-for-unity-server-v${NEW_VERSION}.zip
122+
echo "Server package created: mcp-for-unity-server-v${NEW_VERSION}.zip"
123+
124+
- name: Create GitHub release with server artifact
125+
env:
126+
NEW_VERSION: ${{ steps.compute.outputs.new_version }}
127+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
128+
shell: bash
129+
run: |
130+
set -euo pipefail
131+
TAG="v${NEW_VERSION}"
132+
133+
# Create release
134+
gh release create "$TAG" \
135+
--title "v${NEW_VERSION}" \
136+
--notes "Release v${NEW_VERSION}" \
137+
"mcp-for-unity-server-v${NEW_VERSION}.zip#MCP Server v${NEW_VERSION}"

MCPForUnity/Editor/Helpers/AssetPathUtility.cs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
using System;
2+
using System.IO;
3+
using Newtonsoft.Json.Linq;
4+
using UnityEditor;
5+
using UnityEngine;
6+
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
27

38
namespace MCPForUnity.Editor.Helpers
49
{
@@ -25,5 +30,133 @@ public static string SanitizeAssetPath(string path)
2530

2631
return path;
2732
}
33+
34+
/// <summary>
35+
/// Gets the MCP for Unity package root path.
36+
/// Works for registry Package Manager, local Package Manager, and Asset Store installations.
37+
/// </summary>
38+
/// <returns>The package root path (virtual for PM, absolute for Asset Store), or null if not found</returns>
39+
public static string GetMcpPackageRootPath()
40+
{
41+
try
42+
{
43+
// Try Package Manager first (registry and local installs)
44+
var packageInfo = PackageInfo.FindForAssembly(typeof(AssetPathUtility).Assembly);
45+
if (packageInfo != null && !string.IsNullOrEmpty(packageInfo.assetPath))
46+
{
47+
return packageInfo.assetPath;
48+
}
49+
50+
// Fallback to AssetDatabase for Asset Store installs (Assets/MCPForUnity)
51+
string[] guids = AssetDatabase.FindAssets($"t:Script {nameof(AssetPathUtility)}");
52+
53+
if (guids.Length == 0)
54+
{
55+
McpLog.Warn("Could not find AssetPathUtility script in AssetDatabase");
56+
return null;
57+
}
58+
59+
string scriptPath = AssetDatabase.GUIDToAssetPath(guids[0]);
60+
61+
// Script is at: {packageRoot}/Editor/Helpers/AssetPathUtility.cs
62+
// Extract {packageRoot}
63+
int editorIndex = scriptPath.IndexOf("/Editor/", StringComparison.Ordinal);
64+
65+
if (editorIndex >= 0)
66+
{
67+
return scriptPath.Substring(0, editorIndex);
68+
}
69+
70+
McpLog.Warn($"Could not determine package root from script path: {scriptPath}");
71+
return null;
72+
}
73+
catch (Exception ex)
74+
{
75+
McpLog.Error($"Failed to get package root path: {ex.Message}");
76+
return null;
77+
}
78+
}
79+
80+
/// <summary>
81+
/// Reads and parses the package.json file for MCP for Unity.
82+
/// Handles both Package Manager (registry/local) and Asset Store installations.
83+
/// </summary>
84+
/// <returns>JObject containing package.json data, or null if not found or parse failed</returns>
85+
public static JObject GetPackageJson()
86+
{
87+
try
88+
{
89+
string packageRoot = GetMcpPackageRootPath();
90+
if (string.IsNullOrEmpty(packageRoot))
91+
{
92+
return null;
93+
}
94+
95+
string packageJsonPath = Path.Combine(packageRoot, "package.json");
96+
97+
// Convert virtual asset path to file system path
98+
if (packageRoot.StartsWith("Packages/", StringComparison.OrdinalIgnoreCase))
99+
{
100+
// Package Manager install - must use PackageInfo.resolvedPath
101+
// Virtual paths like "Packages/..." don't work with File.Exists()
102+
// Registry packages live in Library/PackageCache/package@version/
103+
var packageInfo = PackageInfo.FindForAssembly(typeof(AssetPathUtility).Assembly);
104+
if (packageInfo != null && !string.IsNullOrEmpty(packageInfo.resolvedPath))
105+
{
106+
packageJsonPath = Path.Combine(packageInfo.resolvedPath, "package.json");
107+
}
108+
else
109+
{
110+
McpLog.Warn("Could not resolve Package Manager path for package.json");
111+
return null;
112+
}
113+
}
114+
else if (packageRoot.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
115+
{
116+
// Asset Store install - convert to absolute file system path
117+
// Application.dataPath is the absolute path to the Assets folder
118+
string relativePath = packageRoot.Substring("Assets/".Length);
119+
packageJsonPath = Path.Combine(Application.dataPath, relativePath, "package.json");
120+
}
121+
122+
if (!File.Exists(packageJsonPath))
123+
{
124+
McpLog.Warn($"package.json not found at: {packageJsonPath}");
125+
return null;
126+
}
127+
128+
string json = File.ReadAllText(packageJsonPath);
129+
return JObject.Parse(json);
130+
}
131+
catch (Exception ex)
132+
{
133+
McpLog.Warn($"Failed to read or parse package.json: {ex.Message}");
134+
return null;
135+
}
136+
}
137+
138+
/// <summary>
139+
/// Gets the version string from the package.json file.
140+
/// </summary>
141+
/// <returns>Version string, or "unknown" if not found</returns>
142+
public static string GetPackageVersion()
143+
{
144+
try
145+
{
146+
var packageJson = GetPackageJson();
147+
if (packageJson == null)
148+
{
149+
return "unknown";
150+
}
151+
152+
string version = packageJson["version"]?.ToString();
153+
return string.IsNullOrEmpty(version) ? "unknown" : version;
154+
}
155+
catch (Exception ex)
156+
{
157+
McpLog.Warn($"Failed to get package version: {ex.Message}");
158+
return "unknown";
159+
}
160+
}
28161
}
29162
}

MCPForUnity/Editor/Helpers/McpPathResolver.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
namespace MCPForUnity.Editor.Helpers
88
{
99
/// <summary>
10-
/// Shared helper for resolving Python server directory paths with support for
10+
/// Shared helper for resolving MCP server directory paths with support for
1111
/// development mode, embedded servers, and installed packages
1212
/// </summary>
1313
public static class McpPathResolver
1414
{
1515
private const string USE_EMBEDDED_SERVER_KEY = "MCPForUnity.UseEmbeddedServer";
1616

1717
/// <summary>
18-
/// Resolves the Python server directory path with comprehensive logic
18+
/// Resolves the MCP server directory path with comprehensive logic
1919
/// including development mode support and fallback mechanisms
2020
/// </summary>
2121
public static string FindPackagePythonDirectory(bool debugLogsEnabled = false)

MCPForUnity/Editor/Helpers/PackageDetector.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ static PackageDetector()
4949

5050
if (!string.IsNullOrEmpty(error))
5151
{
52-
Debug.LogWarning($"MCP for Unity: Auto-detect on load failed: {capturedEx}");
53-
// Alternatively: Debug.LogException(capturedEx);
52+
McpLog.Info($"Server check: {error}. Download via Window > MCP For Unity if needed.", always: false);
5453
}
5554
};
5655
}

MCPForUnity/Editor/Helpers/PackageInstaller.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace MCPForUnity.Editor.Helpers
55
{
66
/// <summary>
7-
/// Handles automatic installation of the Python server when the package is first installed.
7+
/// Handles automatic installation of the MCP server when the package is first installed.
88
/// </summary>
99
[InitializeOnLoad]
1010
public static class PackageInstaller
@@ -25,18 +25,21 @@ private static void InstallServerOnFirstLoad()
2525
{
2626
try
2727
{
28-
Debug.Log("<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Installing Python server...");
2928
ServerInstaller.EnsureServerInstalled();
3029

31-
// Mark as installed
30+
// Mark as installed/checked
3231
EditorPrefs.SetBool(InstallationFlagKey, true);
3332

34-
Debug.Log("<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Python server installation completed successfully.");
33+
// Only log success if server was actually embedded and copied
34+
if (ServerInstaller.HasEmbeddedServer())
35+
{
36+
McpLog.Info("MCP server installation completed successfully.");
37+
}
3538
}
36-
catch (System.Exception ex)
39+
catch (System.Exception)
3740
{
38-
Debug.LogError($"<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Failed to install Python server: {ex.Message}");
39-
Debug.LogWarning("<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: You may need to manually install the Python server. Check the MCP For Unity Window for instructions.");
41+
EditorPrefs.SetBool(InstallationFlagKey, true); // Mark as handled
42+
McpLog.Info("Server installation pending. Open Window > MCP For Unity to download the server.");
4043
}
4144
}
4245
}

0 commit comments

Comments
 (0)