Allow users to easily add tools in the Asset folder (#324)
* Fix issue #308: Find py files in MCPForUnityTools and version.txt
This allows for auto finding new tools. A good dir on a custom tool would look like this:
CustomTool/
├── CustomTool.MCPEnabler.asmdef
├── CustomTool.MCPEnabler.asmdef.meta
├── ExternalAssetToolFunction.cs
├── ExternalAssetToolFunction.cs.meta
├── external_asset_tool_function.py
├── external_asset_tool_function.py.meta
├── version.txt
└── version.txt.meta
CS files are left in the tools folder. The asmdef is recommended to allow for dependency on MCPForUnity when MCP For Unity is installed:
asmdef example
{
"name": "CustomTool.MCPEnabler",
"rootNamespace": "MCPForUnity.Editor.Tools",
"references": [
"CustomTool",
"MCPForUnity.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
* Follow-up: address CodeRabbit feedback for #308 (<GetToolsFolderIdentifier was duplicated>)
* Follow-up: address CodeRabbit feedback for #308 – centralize GetToolsFolderIdentifier, fix tools copy dir, and limit scan scope
* Fixing so the MCP don't removes _skipDirs e.g. __pycache__
* skip empty folders with no py files
* Rabbit: "Fix identifier collision between different package roots."
* Update MCPForUnity/Editor/Helpers/ServerInstaller.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Rabbbit: Cleanup may delete server’s built-in tool subfolders — restrict to managed names.
* Fixed minor + missed onadding rabit change
* Revert "Fixed minor + missed onadding rabit change"
This reverts commit 571ca8c5de3d07da3791dad558677909a07e886d.
* refactor: remove Unity project tools copying and version tracking functionality
* refactor: consolidate module discovery logic into shared utility function
* Remove unused imports
* feat: add Python tool registry and sync system for MCP server integration
* feat: add auto-sync processor for Python tools with Unity editor integration
* feat: add menu item to reimport all Python files in project
Good to give users a manual option
* Fix infinite loop error
Don't react to PythonToolAsset changes - it only needs to react to Python file changes.
And we also batch asset edits to minimise the DB refreshes
* refactor: move Python tool sync menu items under Window/MCP For Unity/Tool Sync
* Update docs
* Remove duplicate header
* feat: add OnValidate handler to sync Python tools when asset is modified
This fixes the issue with deletions in the asset, now file removals are synced
* test: add unit tests for Python tools asset and sync services
* Update MCPForUnity/Editor/Helpers/PythonToolSyncProcessor.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* style: remove trailing whitespace from Python tool sync files
* test: remove incomplete unit tests from ToolSyncServiceTests
* perf: optimize Python file reimport by using AssetDatabase.FindAssets instead of GetAllAssetPaths
---------
Co-authored-by: Johan Holtby <72528418+JohanHoltby@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-18 12:18:25 +08:00
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using MCPForUnity.Editor.Data;
|
|
|
|
|
using MCPForUnity.Editor.Services;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace MCPForUnity.Editor.Helpers
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Automatically syncs Python tools to the MCP server when:
|
|
|
|
|
/// - PythonToolsAsset is modified
|
|
|
|
|
/// - Python files are imported/reimported
|
|
|
|
|
/// - Unity starts up
|
|
|
|
|
/// </summary>
|
|
|
|
|
[InitializeOnLoad]
|
|
|
|
|
public class PythonToolSyncProcessor : AssetPostprocessor
|
|
|
|
|
{
|
|
|
|
|
private const string SyncEnabledKey = "MCPForUnity.AutoSyncEnabled";
|
|
|
|
|
private static bool _isSyncing = false;
|
|
|
|
|
|
|
|
|
|
static PythonToolSyncProcessor()
|
|
|
|
|
{
|
|
|
|
|
// Sync on Unity startup
|
|
|
|
|
EditorApplication.delayCall += () =>
|
|
|
|
|
{
|
|
|
|
|
if (IsAutoSyncEnabled())
|
|
|
|
|
{
|
|
|
|
|
SyncAllTools();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called after any assets are imported, deleted, or moved
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void OnPostprocessAllAssets(
|
|
|
|
|
string[] importedAssets,
|
|
|
|
|
string[] deletedAssets,
|
|
|
|
|
string[] movedAssets,
|
|
|
|
|
string[] movedFromAssetPaths)
|
|
|
|
|
{
|
|
|
|
|
// Prevent infinite loop - don't process if we're currently syncing
|
|
|
|
|
if (_isSyncing || !IsAutoSyncEnabled())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool needsSync = false;
|
|
|
|
|
|
|
|
|
|
// Only check for .py file changes, not PythonToolsAsset changes
|
|
|
|
|
// (PythonToolsAsset changes are internal state updates from syncing)
|
|
|
|
|
foreach (string path in importedAssets.Concat(movedAssets))
|
|
|
|
|
{
|
|
|
|
|
// Check if any .py files were modified
|
|
|
|
|
if (path.EndsWith(".py"))
|
|
|
|
|
{
|
|
|
|
|
needsSync = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if any .py files were deleted
|
|
|
|
|
if (!needsSync && deletedAssets.Any(path => path.EndsWith(".py")))
|
|
|
|
|
{
|
|
|
|
|
needsSync = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (needsSync)
|
|
|
|
|
{
|
|
|
|
|
SyncAllTools();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Syncs all Python tools from all PythonToolsAsset instances to the MCP server
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void SyncAllTools()
|
|
|
|
|
{
|
|
|
|
|
// Prevent re-entrant calls
|
|
|
|
|
if (_isSyncing)
|
|
|
|
|
{
|
|
|
|
|
McpLog.Warn("Sync already in progress, skipping...");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_isSyncing = true;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (!ServerPathResolver.TryFindEmbeddedServerSource(out string srcPath))
|
|
|
|
|
{
|
|
|
|
|
McpLog.Warn("Cannot sync Python tools: MCP server source not found");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string toolsDir = Path.Combine(srcPath, "tools", "custom");
|
|
|
|
|
|
|
|
|
|
var result = MCPServiceLocator.ToolSync.SyncProjectTools(toolsDir);
|
|
|
|
|
|
|
|
|
|
if (result.Success)
|
|
|
|
|
{
|
|
|
|
|
if (result.CopiedCount > 0 || result.SkippedCount > 0)
|
|
|
|
|
{
|
|
|
|
|
McpLog.Info($"Python tools synced: {result.CopiedCount} copied, {result.SkippedCount} skipped");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
McpLog.Error($"Python tool sync failed with {result.ErrorCount} errors");
|
|
|
|
|
foreach (var msg in result.Messages)
|
|
|
|
|
{
|
|
|
|
|
McpLog.Error($" - {msg}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (System.Exception ex)
|
|
|
|
|
{
|
|
|
|
|
McpLog.Error($"Python tool sync exception: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_isSyncing = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if auto-sync is enabled (default: true)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static bool IsAutoSyncEnabled()
|
|
|
|
|
{
|
|
|
|
|
return EditorPrefs.GetBool(SyncEnabledKey, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Enables or disables auto-sync
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void SetAutoSyncEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
EditorPrefs.SetBool(SyncEnabledKey, enabled);
|
|
|
|
|
McpLog.Info($"Python tool auto-sync {(enabled ? "enabled" : "disabled")}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-24 12:50:29 +08:00
|
|
|
/// Reimport all Python files in the project
|
Allow users to easily add tools in the Asset folder (#324)
* Fix issue #308: Find py files in MCPForUnityTools and version.txt
This allows for auto finding new tools. A good dir on a custom tool would look like this:
CustomTool/
├── CustomTool.MCPEnabler.asmdef
├── CustomTool.MCPEnabler.asmdef.meta
├── ExternalAssetToolFunction.cs
├── ExternalAssetToolFunction.cs.meta
├── external_asset_tool_function.py
├── external_asset_tool_function.py.meta
├── version.txt
└── version.txt.meta
CS files are left in the tools folder. The asmdef is recommended to allow for dependency on MCPForUnity when MCP For Unity is installed:
asmdef example
{
"name": "CustomTool.MCPEnabler",
"rootNamespace": "MCPForUnity.Editor.Tools",
"references": [
"CustomTool",
"MCPForUnity.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
* Follow-up: address CodeRabbit feedback for #308 (<GetToolsFolderIdentifier was duplicated>)
* Follow-up: address CodeRabbit feedback for #308 – centralize GetToolsFolderIdentifier, fix tools copy dir, and limit scan scope
* Fixing so the MCP don't removes _skipDirs e.g. __pycache__
* skip empty folders with no py files
* Rabbit: "Fix identifier collision between different package roots."
* Update MCPForUnity/Editor/Helpers/ServerInstaller.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Rabbbit: Cleanup may delete server’s built-in tool subfolders — restrict to managed names.
* Fixed minor + missed onadding rabit change
* Revert "Fixed minor + missed onadding rabit change"
This reverts commit 571ca8c5de3d07da3791dad558677909a07e886d.
* refactor: remove Unity project tools copying and version tracking functionality
* refactor: consolidate module discovery logic into shared utility function
* Remove unused imports
* feat: add Python tool registry and sync system for MCP server integration
* feat: add auto-sync processor for Python tools with Unity editor integration
* feat: add menu item to reimport all Python files in project
Good to give users a manual option
* Fix infinite loop error
Don't react to PythonToolAsset changes - it only needs to react to Python file changes.
And we also batch asset edits to minimise the DB refreshes
* refactor: move Python tool sync menu items under Window/MCP For Unity/Tool Sync
* Update docs
* Remove duplicate header
* feat: add OnValidate handler to sync Python tools when asset is modified
This fixes the issue with deletions in the asset, now file removals are synced
* test: add unit tests for Python tools asset and sync services
* Update MCPForUnity/Editor/Helpers/PythonToolSyncProcessor.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* style: remove trailing whitespace from Python tool sync files
* test: remove incomplete unit tests from ToolSyncServiceTests
* perf: optimize Python file reimport by using AssetDatabase.FindAssets instead of GetAllAssetPaths
---------
Co-authored-by: Johan Holtby <72528418+JohanHoltby@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-18 12:18:25 +08:00
|
|
|
/// </summary>
|
|
|
|
|
public static void ReimportPythonFiles()
|
|
|
|
|
{
|
|
|
|
|
// Find all Python files (imported as TextAssets by PythonFileImporter)
|
|
|
|
|
var pythonGuids = AssetDatabase.FindAssets("t:TextAsset", new[] { "Assets" })
|
|
|
|
|
.Select(AssetDatabase.GUIDToAssetPath)
|
|
|
|
|
.Where(path => path.EndsWith(".py", System.StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
foreach (string path in pythonGuids)
|
|
|
|
|
{
|
|
|
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int count = pythonGuids.Length;
|
|
|
|
|
McpLog.Info($"Reimported {count} Python files");
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-24 12:50:29 +08:00
|
|
|
/// Manually trigger sync
|
Allow users to easily add tools in the Asset folder (#324)
* Fix issue #308: Find py files in MCPForUnityTools and version.txt
This allows for auto finding new tools. A good dir on a custom tool would look like this:
CustomTool/
├── CustomTool.MCPEnabler.asmdef
├── CustomTool.MCPEnabler.asmdef.meta
├── ExternalAssetToolFunction.cs
├── ExternalAssetToolFunction.cs.meta
├── external_asset_tool_function.py
├── external_asset_tool_function.py.meta
├── version.txt
└── version.txt.meta
CS files are left in the tools folder. The asmdef is recommended to allow for dependency on MCPForUnity when MCP For Unity is installed:
asmdef example
{
"name": "CustomTool.MCPEnabler",
"rootNamespace": "MCPForUnity.Editor.Tools",
"references": [
"CustomTool",
"MCPForUnity.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
* Follow-up: address CodeRabbit feedback for #308 (<GetToolsFolderIdentifier was duplicated>)
* Follow-up: address CodeRabbit feedback for #308 – centralize GetToolsFolderIdentifier, fix tools copy dir, and limit scan scope
* Fixing so the MCP don't removes _skipDirs e.g. __pycache__
* skip empty folders with no py files
* Rabbit: "Fix identifier collision between different package roots."
* Update MCPForUnity/Editor/Helpers/ServerInstaller.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Rabbbit: Cleanup may delete server’s built-in tool subfolders — restrict to managed names.
* Fixed minor + missed onadding rabit change
* Revert "Fixed minor + missed onadding rabit change"
This reverts commit 571ca8c5de3d07da3791dad558677909a07e886d.
* refactor: remove Unity project tools copying and version tracking functionality
* refactor: consolidate module discovery logic into shared utility function
* Remove unused imports
* feat: add Python tool registry and sync system for MCP server integration
* feat: add auto-sync processor for Python tools with Unity editor integration
* feat: add menu item to reimport all Python files in project
Good to give users a manual option
* Fix infinite loop error
Don't react to PythonToolAsset changes - it only needs to react to Python file changes.
And we also batch asset edits to minimise the DB refreshes
* refactor: move Python tool sync menu items under Window/MCP For Unity/Tool Sync
* Update docs
* Remove duplicate header
* feat: add OnValidate handler to sync Python tools when asset is modified
This fixes the issue with deletions in the asset, now file removals are synced
* test: add unit tests for Python tools asset and sync services
* Update MCPForUnity/Editor/Helpers/PythonToolSyncProcessor.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* style: remove trailing whitespace from Python tool sync files
* test: remove incomplete unit tests from ToolSyncServiceTests
* perf: optimize Python file reimport by using AssetDatabase.FindAssets instead of GetAllAssetPaths
---------
Co-authored-by: Johan Holtby <72528418+JohanHoltby@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-18 12:18:25 +08:00
|
|
|
/// </summary>
|
|
|
|
|
public static void ManualSync()
|
|
|
|
|
{
|
|
|
|
|
McpLog.Info("Manually syncing Python tools...");
|
|
|
|
|
SyncAllTools();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-24 12:50:29 +08:00
|
|
|
/// Toggle auto-sync
|
Allow users to easily add tools in the Asset folder (#324)
* Fix issue #308: Find py files in MCPForUnityTools and version.txt
This allows for auto finding new tools. A good dir on a custom tool would look like this:
CustomTool/
├── CustomTool.MCPEnabler.asmdef
├── CustomTool.MCPEnabler.asmdef.meta
├── ExternalAssetToolFunction.cs
├── ExternalAssetToolFunction.cs.meta
├── external_asset_tool_function.py
├── external_asset_tool_function.py.meta
├── version.txt
└── version.txt.meta
CS files are left in the tools folder. The asmdef is recommended to allow for dependency on MCPForUnity when MCP For Unity is installed:
asmdef example
{
"name": "CustomTool.MCPEnabler",
"rootNamespace": "MCPForUnity.Editor.Tools",
"references": [
"CustomTool",
"MCPForUnity.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
* Follow-up: address CodeRabbit feedback for #308 (<GetToolsFolderIdentifier was duplicated>)
* Follow-up: address CodeRabbit feedback for #308 – centralize GetToolsFolderIdentifier, fix tools copy dir, and limit scan scope
* Fixing so the MCP don't removes _skipDirs e.g. __pycache__
* skip empty folders with no py files
* Rabbit: "Fix identifier collision between different package roots."
* Update MCPForUnity/Editor/Helpers/ServerInstaller.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Rabbbit: Cleanup may delete server’s built-in tool subfolders — restrict to managed names.
* Fixed minor + missed onadding rabit change
* Revert "Fixed minor + missed onadding rabit change"
This reverts commit 571ca8c5de3d07da3791dad558677909a07e886d.
* refactor: remove Unity project tools copying and version tracking functionality
* refactor: consolidate module discovery logic into shared utility function
* Remove unused imports
* feat: add Python tool registry and sync system for MCP server integration
* feat: add auto-sync processor for Python tools with Unity editor integration
* feat: add menu item to reimport all Python files in project
Good to give users a manual option
* Fix infinite loop error
Don't react to PythonToolAsset changes - it only needs to react to Python file changes.
And we also batch asset edits to minimise the DB refreshes
* refactor: move Python tool sync menu items under Window/MCP For Unity/Tool Sync
* Update docs
* Remove duplicate header
* feat: add OnValidate handler to sync Python tools when asset is modified
This fixes the issue with deletions in the asset, now file removals are synced
* test: add unit tests for Python tools asset and sync services
* Update MCPForUnity/Editor/Helpers/PythonToolSyncProcessor.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* style: remove trailing whitespace from Python tool sync files
* test: remove incomplete unit tests from ToolSyncServiceTests
* perf: optimize Python file reimport by using AssetDatabase.FindAssets instead of GetAllAssetPaths
---------
Co-authored-by: Johan Holtby <72528418+JohanHoltby@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-18 12:18:25 +08:00
|
|
|
/// </summary>
|
|
|
|
|
public static void ToggleAutoSync()
|
|
|
|
|
{
|
|
|
|
|
SetAutoSyncEnabled(!IsAutoSyncEnabled());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Validate menu item (shows checkmark when enabled)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static bool ToggleAutoSyncValidate()
|
|
|
|
|
{
|
|
|
|
|
Menu.SetChecked("Window/MCP For Unity/Tool Sync/Auto-Sync Python Tools", IsAutoSyncEnabled());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|