StdIoVersionMigration.cs•4.28 kB
using System;
using System.IO;
using System.Linq;
using MCPForUnity.Editor.Clients;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Services;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
namespace MCPForUnity.Editor.Migrations
{
/// <summary>
/// Keeps stdio MCP clients in sync with the current package version by rewriting their configs when the package updates.
/// </summary>
[InitializeOnLoad]
internal static class StdIoVersionMigration
{
private const string LastUpgradeKey = EditorPrefKeys.LastStdIoUpgradeVersion;
static StdIoVersionMigration()
{
if (Application.isBatchMode)
return;
EditorApplication.delayCall += RunMigrationIfNeeded;
}
private static void RunMigrationIfNeeded()
{
EditorApplication.delayCall -= RunMigrationIfNeeded;
string currentVersion = AssetPathUtility.GetPackageVersion();
if (string.IsNullOrEmpty(currentVersion) || string.Equals(currentVersion, "unknown", StringComparison.OrdinalIgnoreCase))
{
return;
}
string lastUpgradeVersion = string.Empty;
try { lastUpgradeVersion = EditorPrefs.GetString(LastUpgradeKey, string.Empty); } catch { }
if (string.Equals(lastUpgradeVersion, currentVersion, StringComparison.OrdinalIgnoreCase))
{
return; // Already refreshed for this package version
}
bool hadFailures = false;
bool touchedAny = false;
var configurators = McpClientRegistry.All.OfType<McpClientConfiguratorBase>().ToList();
foreach (var configurator in configurators)
{
try
{
if (!ConfigUsesStdIo(configurator.Client))
continue;
if (!configurator.SupportsAutoConfigure)
continue;
MCPServiceLocator.Client.ConfigureClient(configurator);
touchedAny = true;
}
catch (Exception ex)
{
hadFailures = true;
McpLog.Warn($"Failed to refresh stdio config for {configurator.DisplayName}: {ex.Message}");
}
}
if (!touchedAny)
{
// Nothing needed refreshing; still record version so we don't rerun every launch
try { EditorPrefs.SetString(LastUpgradeKey, currentVersion); } catch { }
return;
}
if (hadFailures)
{
McpLog.Warn("Stdio MCP upgrade encountered errors; will retry next session.");
return;
}
try
{
EditorPrefs.SetString(LastUpgradeKey, currentVersion);
}
catch { }
McpLog.Info($"Updated stdio MCP configs to package version {currentVersion}.");
}
private static bool ConfigUsesStdIo(McpClient client)
{
return JsonConfigUsesStdIo(client);
}
private static bool JsonConfigUsesStdIo(McpClient client)
{
string configPath = McpConfigurationHelper.GetClientConfigPath(client);
if (string.IsNullOrEmpty(configPath) || !File.Exists(configPath))
{
return false;
}
try
{
var root = JObject.Parse(File.ReadAllText(configPath));
JToken unityNode = null;
if (client.IsVsCodeLayout)
{
unityNode = root.SelectToken("servers.unityMCP")
?? root.SelectToken("mcp.servers.unityMCP");
}
else
{
unityNode = root.SelectToken("mcpServers.unityMCP");
}
if (unityNode == null) return false;
return unityNode["command"] != null;
}
catch
{
return false;
}
}
}
}