Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e42612f
First pass at new UI
msanatan Oct 6, 2025
75eae7f
Point to new UI
msanatan Oct 6, 2025
582075a
Refactor: New Service-Based MCP Editor Window Architecture
msanatan Oct 9, 2025
44adf22
style: add flex-shrink and overflow handling to improve UI element sc…
msanatan Oct 9, 2025
b25433a
fix: update UI configuration and visibility when client status changes
msanatan Oct 9, 2025
44e6557
feat: add menu item to open legacy MCP configuration window
msanatan Oct 9, 2025
08c5c72
refactor: improve editor window lifecycle handling with proper update…
msanatan Oct 9, 2025
be197a6
feat: add auto-verification of bridge health when connected
msanatan Oct 9, 2025
4ffe9f3
fix: update Claude Code MCP server registration to use lowercase unit…
msanatan Oct 9, 2025
805f7d3
fix: add Claude CLI directory to PATH for node/nvm environments
msanatan Oct 9, 2025
2418b73
Clarify how users will see MCP tools
msanatan Oct 9, 2025
54beec1
Add a keyboard shortcut to open the window
msanatan Oct 9, 2025
cca04b4
feat: add server download UI and improve installation status messaging
msanatan Oct 10, 2025
4ddc21b
feat: add dynamic asset path detection to support both Package Manage…
msanatan Oct 10, 2025
69d307a
fix: replace unicode emojis with escaped characters in status messages
msanatan Oct 10, 2025
686504c
feat: add server package creation and GitHub release publishing to ve…
msanatan Oct 10, 2025
0cab9f9
fix: add v prefix to server package filename in release workflow
msanatan Oct 10, 2025
43810fd
Fix download location
msanatan Oct 10, 2025
396f1c1
style: improve dropdown and settings layout responsiveness with flex-…
msanatan Oct 10, 2025
b674514
feat: add package.json version detection and refactor path utilities
msanatan Oct 10, 2025
a07c9f2
refactor: simplify imports and use fully qualified names in ServerIns…
msanatan Oct 10, 2025
550fd77
refactor: replace Unity Debug.Log calls with custom McpLog class
msanatan Oct 10, 2025
89b5e38
fix: extract server files to temp directory before moving to final lo…
msanatan Oct 10, 2025
94d4f0f
docs: add v6 UI documentation and screenshots with service architectu…
msanatan Oct 10, 2025
fec1bfc
docs: add new UI Toolkit-based editor window with service architectur…
msanatan Oct 10, 2025
43a6fe0
feat: improve package path resolution to support Package Manager and …
msanatan Oct 11, 2025
a04980a
Change Claude Code's casing back to "UnityMCP"
msanatan Oct 11, 2025
62f25b5
fix: update success dialog text to clarify manual bridge start requir…
msanatan Oct 11, 2025
7f1fe1f
refactor: move RefreshDebounce and ManageScriptRefreshHelpers classes…
msanatan Oct 11, 2025
41d20ce
feat: add Asset Store fallback path detection for package root lookup
msanatan Oct 11, 2025
5a7b26f
fix: update server installation success message to be more descriptive
msanatan Oct 11, 2025
981642c
refactor: replace Unity Debug.Log calls with custom McpLog utility
msanatan Oct 11, 2025
2fa84bc
fix: add file existence check before opening configuration file
msanatan Oct 11, 2025
15aa737
refactor: simplify asset path handling and remove redundant helper na…
msanatan Oct 11, 2025
e92cede
docs: update code block syntax highlighting in UI changes doc
msanatan Oct 11, 2025
d5ec64f
docs: add code block syntax highlighting for file structure example
msanatan Oct 11, 2025
182e4e4
feat: import UnityEditor.UIElements namespace for UI components for U…
msanatan Oct 11, 2025
9b60693
refactor: rename Python server references to MCP server for consistency
msanatan Oct 11, 2025
93f0823
fix: reset client status label color after error state is cleared
msanatan Oct 11, 2025
dad7237
Replace the phrase "Python server" with "MCP server"
msanatan Oct 11, 2025
563fd83
MInor doc clarification
msanatan Oct 11, 2025
776aeb9
docs: add path override methods for UV and Claude CLI executables
msanatan Oct 11, 2025
e195dda
docs: update service locator registration method name from SetCustomI…
msanatan Oct 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/bump-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,30 @@ jobs:

git tag -a "$TAG" -m "Version ${NEW_VERSION}"
git push origin "$TAG"

- name: Package server for release
env:
NEW_VERSION: ${{ steps.compute.outputs.new_version }}
shell: bash
run: |
set -euo pipefail
cd MCPForUnity/UnityMcpServer~
zip -r ../../mcp-for-unity-server-v${NEW_VERSION}.zip .
cd ../..
ls -lh mcp-for-unity-server-v${NEW_VERSION}.zip
echo "Server package created: mcp-for-unity-server-v${NEW_VERSION}.zip"

- name: Create GitHub release with server artifact
env:
NEW_VERSION: ${{ steps.compute.outputs.new_version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail
TAG="v${NEW_VERSION}"

# Create release
gh release create "$TAG" \
--title "v${NEW_VERSION}" \
--notes "Release v${NEW_VERSION}" \
"mcp-for-unity-server-v${NEW_VERSION}.zip#MCP Server v${NEW_VERSION}"
Comment on lines +124 to +137
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Skip release creation when it already exists

If the tag already lives on the remote (e.g., a rerun after a partial failure), the tag step exits early, but this block still executes. gh release create then crashes with “already exists,” causing the whole workflow to fail. Bail out when the release is present before attempting to create it.

       TAG="v${NEW_VERSION}"
 
+      if gh release view "$TAG" >/dev/null 2>&1; then
+        echo "Release $TAG already exists. Skipping creation."
+        exit 0
+      fi
+
       # Create release
       gh release create "$TAG" \
         --title "v${NEW_VERSION}" \
🤖 Prompt for AI Agents
.github/workflows/bump-version.yml around lines 124 to 137: the workflow
unconditionally runs gh release create which fails if the release/tag already
exists; modify the script to first check for an existing release for TAG (e.g.,
run gh release view "$TAG" and test its exit status), and if it exists emit a
log like "Release exists, skipping" and exit successfully before calling gh
release create; otherwise proceed to create the release as before. Ensure the
check uses the same GITHUB_TOKEN and that non-zero output from gh release view
triggers the create path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not an issue... if a tag was created and needed to be deleted, we would delete the tag and remove the bump commit before running this again

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msanatan, that makes sense! If you always clean up both the tag and commit together before re-running, the scenario where the tag exists without a release shouldn't occur. Your manual cleanup process sounds like a reasonable approach for handling partial failures.

Feel free to reach out if you'd like to revisit this in the future! 🐰

133 changes: 133 additions & 0 deletions MCPForUnity/Editor/Helpers/AssetPathUtility.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using System;
using System.IO;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;

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

return path;
}

/// <summary>
/// Gets the MCP for Unity package root path.
/// Works for registry Package Manager, local Package Manager, and Asset Store installations.
/// </summary>
/// <returns>The package root path (virtual for PM, absolute for Asset Store), or null if not found</returns>
public static string GetMcpPackageRootPath()
{
try
{
// Try Package Manager first (registry and local installs)
var packageInfo = PackageInfo.FindForAssembly(typeof(AssetPathUtility).Assembly);
if (packageInfo != null && !string.IsNullOrEmpty(packageInfo.assetPath))
{
return packageInfo.assetPath;
}

// Fallback to AssetDatabase for Asset Store installs (Assets/MCPForUnity)
string[] guids = AssetDatabase.FindAssets($"t:Script {nameof(AssetPathUtility)}");

if (guids.Length == 0)
{
McpLog.Warn("Could not find AssetPathUtility script in AssetDatabase");
return null;
}

string scriptPath = AssetDatabase.GUIDToAssetPath(guids[0]);

// Script is at: {packageRoot}/Editor/Helpers/AssetPathUtility.cs
// Extract {packageRoot}
int editorIndex = scriptPath.IndexOf("/Editor/", StringComparison.Ordinal);

if (editorIndex >= 0)
{
return scriptPath.Substring(0, editorIndex);
}

McpLog.Warn($"Could not determine package root from script path: {scriptPath}");
return null;
}
catch (Exception ex)
{
McpLog.Error($"Failed to get package root path: {ex.Message}");
return null;
}
}

/// <summary>
/// Reads and parses the package.json file for MCP for Unity.
/// Handles both Package Manager (registry/local) and Asset Store installations.
/// </summary>
/// <returns>JObject containing package.json data, or null if not found or parse failed</returns>
public static JObject GetPackageJson()
{
try
{
string packageRoot = GetMcpPackageRootPath();
if (string.IsNullOrEmpty(packageRoot))
{
return null;
}

string packageJsonPath = Path.Combine(packageRoot, "package.json");

// Convert virtual asset path to file system path
if (packageRoot.StartsWith("Packages/", StringComparison.OrdinalIgnoreCase))
{
// Package Manager install - must use PackageInfo.resolvedPath
// Virtual paths like "Packages/..." don't work with File.Exists()
// Registry packages live in Library/PackageCache/package@version/
var packageInfo = PackageInfo.FindForAssembly(typeof(AssetPathUtility).Assembly);
if (packageInfo != null && !string.IsNullOrEmpty(packageInfo.resolvedPath))
{
packageJsonPath = Path.Combine(packageInfo.resolvedPath, "package.json");
}
else
{
McpLog.Warn("Could not resolve Package Manager path for package.json");
return null;
}
}
else if (packageRoot.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
{
// Asset Store install - convert to absolute file system path
// Application.dataPath is the absolute path to the Assets folder
string relativePath = packageRoot.Substring("Assets/".Length);
packageJsonPath = Path.Combine(Application.dataPath, relativePath, "package.json");
}

if (!File.Exists(packageJsonPath))
{
McpLog.Warn($"package.json not found at: {packageJsonPath}");
return null;
}

string json = File.ReadAllText(packageJsonPath);
return JObject.Parse(json);
}
catch (Exception ex)
{
McpLog.Warn($"Failed to read or parse package.json: {ex.Message}");
return null;
}
}

/// <summary>
/// Gets the version string from the package.json file.
/// </summary>
/// <returns>Version string, or "unknown" if not found</returns>
public static string GetPackageVersion()
{
try
{
var packageJson = GetPackageJson();
if (packageJson == null)
{
return "unknown";
}

string version = packageJson["version"]?.ToString();
return string.IsNullOrEmpty(version) ? "unknown" : version;
}
catch (Exception ex)
{
McpLog.Warn($"Failed to get package version: {ex.Message}");
return "unknown";
}
}
}
}
4 changes: 2 additions & 2 deletions MCPForUnity/Editor/Helpers/McpPathResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
namespace MCPForUnity.Editor.Helpers
{
/// <summary>
/// Shared helper for resolving Python server directory paths with support for
/// Shared helper for resolving MCP server directory paths with support for
/// development mode, embedded servers, and installed packages
/// </summary>
public static class McpPathResolver
{
private const string USE_EMBEDDED_SERVER_KEY = "MCPForUnity.UseEmbeddedServer";

/// <summary>
/// Resolves the Python server directory path with comprehensive logic
/// Resolves the MCP server directory path with comprehensive logic
/// including development mode support and fallback mechanisms
/// </summary>
public static string FindPackagePythonDirectory(bool debugLogsEnabled = false)
Expand Down
3 changes: 1 addition & 2 deletions MCPForUnity/Editor/Helpers/PackageDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ static PackageDetector()

if (!string.IsNullOrEmpty(error))
{
Debug.LogWarning($"MCP for Unity: Auto-detect on load failed: {capturedEx}");
// Alternatively: Debug.LogException(capturedEx);
McpLog.Info($"Server check: {error}. Download via Window > MCP For Unity if needed.", always: false);
}
};
}
Expand Down
17 changes: 10 additions & 7 deletions MCPForUnity/Editor/Helpers/PackageInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace MCPForUnity.Editor.Helpers
{
/// <summary>
/// Handles automatic installation of the Python server when the package is first installed.
/// Handles automatic installation of the MCP server when the package is first installed.
/// </summary>
[InitializeOnLoad]
public static class PackageInstaller
Expand All @@ -25,18 +25,21 @@ private static void InstallServerOnFirstLoad()
{
try
{
Debug.Log("<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Installing Python server...");
ServerInstaller.EnsureServerInstalled();

// Mark as installed
// Mark as installed/checked
EditorPrefs.SetBool(InstallationFlagKey, true);

Debug.Log("<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Python server installation completed successfully.");
// Only log success if server was actually embedded and copied
if (ServerInstaller.HasEmbeddedServer())
{
McpLog.Info("MCP server installation completed successfully.");
}
}
catch (System.Exception ex)
catch (System.Exception)
{
Debug.LogError($"<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Failed to install Python server: {ex.Message}");
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.");
EditorPrefs.SetBool(InstallationFlagKey, true); // Mark as handled
McpLog.Info("Server installation pending. Open Window > MCP For Unity to download the server.");
}
}
}
Expand Down
Loading