#
tokens: 45266/50000 7/264 files (page 7/13)
lines: off (toggle) GitHub
raw markdown copy
This is page 7 of 13. Use http://codebase.md/justinpbarnett/unity-mcp?lines=false&page={x} to view the full context.

# Directory Structure

```
├── .claude
│   ├── prompts
│   │   ├── nl-unity-suite-nl.md
│   │   └── nl-unity-suite-t.md
│   └── settings.json
├── .github
│   ├── scripts
│   │   └── mark_skipped.py
│   └── workflows
│       ├── bump-version.yml
│       ├── claude-nl-suite.yml
│       ├── github-repo-stats.yml
│       └── unity-tests.yml
├── .gitignore
├── deploy-dev.bat
├── docs
│   ├── CURSOR_HELP.md
│   ├── CUSTOM_TOOLS.md
│   ├── README-DEV-zh.md
│   ├── README-DEV.md
│   ├── screenshots
│   │   ├── v5_01_uninstall.png
│   │   ├── v5_02_install.png
│   │   ├── v5_03_open_mcp_window.png
│   │   ├── v5_04_rebuild_mcp_server.png
│   │   ├── v5_05_rebuild_success.png
│   │   ├── v6_2_create_python_tools_asset.png
│   │   ├── v6_2_python_tools_asset.png
│   │   ├── v6_new_ui_asset_store_version.png
│   │   ├── v6_new_ui_dark.png
│   │   └── v6_new_ui_light.png
│   ├── TELEMETRY.md
│   ├── v5_MIGRATION.md
│   └── v6_NEW_UI_CHANGES.md
├── LICENSE
├── logo.png
├── mcp_source.py
├── MCPForUnity
│   ├── Editor
│   │   ├── AssemblyInfo.cs
│   │   ├── AssemblyInfo.cs.meta
│   │   ├── Data
│   │   │   ├── DefaultServerConfig.cs
│   │   │   ├── DefaultServerConfig.cs.meta
│   │   │   ├── McpClients.cs
│   │   │   ├── McpClients.cs.meta
│   │   │   ├── PythonToolsAsset.cs
│   │   │   └── PythonToolsAsset.cs.meta
│   │   ├── Data.meta
│   │   ├── Dependencies
│   │   │   ├── DependencyManager.cs
│   │   │   ├── DependencyManager.cs.meta
│   │   │   ├── Models
│   │   │   │   ├── DependencyCheckResult.cs
│   │   │   │   ├── DependencyCheckResult.cs.meta
│   │   │   │   ├── DependencyStatus.cs
│   │   │   │   └── DependencyStatus.cs.meta
│   │   │   ├── Models.meta
│   │   │   ├── PlatformDetectors
│   │   │   │   ├── IPlatformDetector.cs
│   │   │   │   ├── IPlatformDetector.cs.meta
│   │   │   │   ├── LinuxPlatformDetector.cs
│   │   │   │   ├── LinuxPlatformDetector.cs.meta
│   │   │   │   ├── MacOSPlatformDetector.cs
│   │   │   │   ├── MacOSPlatformDetector.cs.meta
│   │   │   │   ├── PlatformDetectorBase.cs
│   │   │   │   ├── PlatformDetectorBase.cs.meta
│   │   │   │   ├── WindowsPlatformDetector.cs
│   │   │   │   └── WindowsPlatformDetector.cs.meta
│   │   │   └── PlatformDetectors.meta
│   │   ├── Dependencies.meta
│   │   ├── External
│   │   │   ├── Tommy.cs
│   │   │   └── Tommy.cs.meta
│   │   ├── External.meta
│   │   ├── Helpers
│   │   │   ├── AssetPathUtility.cs
│   │   │   ├── AssetPathUtility.cs.meta
│   │   │   ├── CodexConfigHelper.cs
│   │   │   ├── CodexConfigHelper.cs.meta
│   │   │   ├── ConfigJsonBuilder.cs
│   │   │   ├── ConfigJsonBuilder.cs.meta
│   │   │   ├── ExecPath.cs
│   │   │   ├── ExecPath.cs.meta
│   │   │   ├── GameObjectSerializer.cs
│   │   │   ├── GameObjectSerializer.cs.meta
│   │   │   ├── McpConfigFileHelper.cs
│   │   │   ├── McpConfigFileHelper.cs.meta
│   │   │   ├── McpConfigurationHelper.cs
│   │   │   ├── McpConfigurationHelper.cs.meta
│   │   │   ├── McpLog.cs
│   │   │   ├── McpLog.cs.meta
│   │   │   ├── McpPathResolver.cs
│   │   │   ├── McpPathResolver.cs.meta
│   │   │   ├── PackageDetector.cs
│   │   │   ├── PackageDetector.cs.meta
│   │   │   ├── PackageInstaller.cs
│   │   │   ├── PackageInstaller.cs.meta
│   │   │   ├── PortManager.cs
│   │   │   ├── PortManager.cs.meta
│   │   │   ├── PythonToolSyncProcessor.cs
│   │   │   ├── PythonToolSyncProcessor.cs.meta
│   │   │   ├── Response.cs
│   │   │   ├── Response.cs.meta
│   │   │   ├── ServerInstaller.cs
│   │   │   ├── ServerInstaller.cs.meta
│   │   │   ├── ServerPathResolver.cs
│   │   │   ├── ServerPathResolver.cs.meta
│   │   │   ├── TelemetryHelper.cs
│   │   │   ├── TelemetryHelper.cs.meta
│   │   │   ├── Vector3Helper.cs
│   │   │   └── Vector3Helper.cs.meta
│   │   ├── Helpers.meta
│   │   ├── Importers
│   │   │   ├── PythonFileImporter.cs
│   │   │   └── PythonFileImporter.cs.meta
│   │   ├── Importers.meta
│   │   ├── MCPForUnity.Editor.asmdef
│   │   ├── MCPForUnity.Editor.asmdef.meta
│   │   ├── MCPForUnityBridge.cs
│   │   ├── MCPForUnityBridge.cs.meta
│   │   ├── Models
│   │   │   ├── Command.cs
│   │   │   ├── Command.cs.meta
│   │   │   ├── McpClient.cs
│   │   │   ├── McpClient.cs.meta
│   │   │   ├── McpConfig.cs
│   │   │   ├── McpConfig.cs.meta
│   │   │   ├── MCPConfigServer.cs
│   │   │   ├── MCPConfigServer.cs.meta
│   │   │   ├── MCPConfigServers.cs
│   │   │   ├── MCPConfigServers.cs.meta
│   │   │   ├── McpStatus.cs
│   │   │   ├── McpStatus.cs.meta
│   │   │   ├── McpTypes.cs
│   │   │   ├── McpTypes.cs.meta
│   │   │   ├── ServerConfig.cs
│   │   │   └── ServerConfig.cs.meta
│   │   ├── Models.meta
│   │   ├── Resources
│   │   │   ├── McpForUnityResourceAttribute.cs
│   │   │   ├── McpForUnityResourceAttribute.cs.meta
│   │   │   ├── MenuItems
│   │   │   │   ├── GetMenuItems.cs
│   │   │   │   └── GetMenuItems.cs.meta
│   │   │   ├── MenuItems.meta
│   │   │   ├── Tests
│   │   │   │   ├── GetTests.cs
│   │   │   │   └── GetTests.cs.meta
│   │   │   └── Tests.meta
│   │   ├── Resources.meta
│   │   ├── Services
│   │   │   ├── BridgeControlService.cs
│   │   │   ├── BridgeControlService.cs.meta
│   │   │   ├── ClientConfigurationService.cs
│   │   │   ├── ClientConfigurationService.cs.meta
│   │   │   ├── IBridgeControlService.cs
│   │   │   ├── IBridgeControlService.cs.meta
│   │   │   ├── IClientConfigurationService.cs
│   │   │   ├── IClientConfigurationService.cs.meta
│   │   │   ├── IPackageUpdateService.cs
│   │   │   ├── IPackageUpdateService.cs.meta
│   │   │   ├── IPathResolverService.cs
│   │   │   ├── IPathResolverService.cs.meta
│   │   │   ├── IPythonToolRegistryService.cs
│   │   │   ├── IPythonToolRegistryService.cs.meta
│   │   │   ├── ITestRunnerService.cs
│   │   │   ├── ITestRunnerService.cs.meta
│   │   │   ├── IToolSyncService.cs
│   │   │   ├── IToolSyncService.cs.meta
│   │   │   ├── MCPServiceLocator.cs
│   │   │   ├── MCPServiceLocator.cs.meta
│   │   │   ├── PackageUpdateService.cs
│   │   │   ├── PackageUpdateService.cs.meta
│   │   │   ├── PathResolverService.cs
│   │   │   ├── PathResolverService.cs.meta
│   │   │   ├── PythonToolRegistryService.cs
│   │   │   ├── PythonToolRegistryService.cs.meta
│   │   │   ├── TestRunnerService.cs
│   │   │   ├── TestRunnerService.cs.meta
│   │   │   ├── ToolSyncService.cs
│   │   │   └── ToolSyncService.cs.meta
│   │   ├── Services.meta
│   │   ├── Setup
│   │   │   ├── SetupWizard.cs
│   │   │   ├── SetupWizard.cs.meta
│   │   │   ├── SetupWizardWindow.cs
│   │   │   └── SetupWizardWindow.cs.meta
│   │   ├── Setup.meta
│   │   ├── Tools
│   │   │   ├── CommandRegistry.cs
│   │   │   ├── CommandRegistry.cs.meta
│   │   │   ├── ExecuteMenuItem.cs
│   │   │   ├── ExecuteMenuItem.cs.meta
│   │   │   ├── ManageAsset.cs
│   │   │   ├── ManageAsset.cs.meta
│   │   │   ├── ManageEditor.cs
│   │   │   ├── ManageEditor.cs.meta
│   │   │   ├── ManageGameObject.cs
│   │   │   ├── ManageGameObject.cs.meta
│   │   │   ├── ManageScene.cs
│   │   │   ├── ManageScene.cs.meta
│   │   │   ├── ManageScript.cs
│   │   │   ├── ManageScript.cs.meta
│   │   │   ├── ManageShader.cs
│   │   │   ├── ManageShader.cs.meta
│   │   │   ├── McpForUnityToolAttribute.cs
│   │   │   ├── McpForUnityToolAttribute.cs.meta
│   │   │   ├── Prefabs
│   │   │   │   ├── ManagePrefabs.cs
│   │   │   │   └── ManagePrefabs.cs.meta
│   │   │   ├── Prefabs.meta
│   │   │   ├── ReadConsole.cs
│   │   │   ├── ReadConsole.cs.meta
│   │   │   ├── RunTests.cs
│   │   │   └── RunTests.cs.meta
│   │   ├── Tools.meta
│   │   ├── Windows
│   │   │   ├── ManualConfigEditorWindow.cs
│   │   │   ├── ManualConfigEditorWindow.cs.meta
│   │   │   ├── MCPForUnityEditorWindow.cs
│   │   │   ├── MCPForUnityEditorWindow.cs.meta
│   │   │   ├── MCPForUnityEditorWindowNew.cs
│   │   │   ├── MCPForUnityEditorWindowNew.cs.meta
│   │   │   ├── MCPForUnityEditorWindowNew.uss
│   │   │   ├── MCPForUnityEditorWindowNew.uss.meta
│   │   │   ├── MCPForUnityEditorWindowNew.uxml
│   │   │   ├── MCPForUnityEditorWindowNew.uxml.meta
│   │   │   ├── VSCodeManualSetupWindow.cs
│   │   │   └── VSCodeManualSetupWindow.cs.meta
│   │   └── Windows.meta
│   ├── Editor.meta
│   ├── package.json
│   ├── package.json.meta
│   ├── README.md
│   ├── README.md.meta
│   ├── Runtime
│   │   ├── MCPForUnity.Runtime.asmdef
│   │   ├── MCPForUnity.Runtime.asmdef.meta
│   │   ├── Serialization
│   │   │   ├── UnityTypeConverters.cs
│   │   │   └── UnityTypeConverters.cs.meta
│   │   └── Serialization.meta
│   ├── Runtime.meta
│   └── UnityMcpServer~
│       └── src
│           ├── __init__.py
│           ├── config.py
│           ├── Dockerfile
│           ├── models.py
│           ├── module_discovery.py
│           ├── port_discovery.py
│           ├── pyproject.toml
│           ├── pyrightconfig.json
│           ├── registry
│           │   ├── __init__.py
│           │   ├── resource_registry.py
│           │   └── tool_registry.py
│           ├── reload_sentinel.py
│           ├── resources
│           │   ├── __init__.py
│           │   ├── menu_items.py
│           │   └── tests.py
│           ├── server_version.txt
│           ├── server.py
│           ├── telemetry_decorator.py
│           ├── telemetry.py
│           ├── test_telemetry.py
│           ├── tools
│           │   ├── __init__.py
│           │   ├── execute_menu_item.py
│           │   ├── manage_asset.py
│           │   ├── manage_editor.py
│           │   ├── manage_gameobject.py
│           │   ├── manage_prefabs.py
│           │   ├── manage_scene.py
│           │   ├── manage_script.py
│           │   ├── manage_shader.py
│           │   ├── read_console.py
│           │   ├── resource_tools.py
│           │   ├── run_tests.py
│           │   └── script_apply_edits.py
│           ├── unity_connection.py
│           └── uv.lock
├── prune_tool_results.py
├── README-zh.md
├── README.md
├── restore-dev.bat
├── scripts
│   └── validate-nlt-coverage.sh
├── test_unity_socket_framing.py
├── TestProjects
│   └── UnityMCPTests
│       ├── .gitignore
│       ├── Assets
│       │   ├── Editor.meta
│       │   ├── Scenes
│       │   │   ├── SampleScene.unity
│       │   │   └── SampleScene.unity.meta
│       │   ├── Scenes.meta
│       │   ├── Scripts
│       │   │   ├── Hello.cs
│       │   │   ├── Hello.cs.meta
│       │   │   ├── LongUnityScriptClaudeTest.cs
│       │   │   ├── LongUnityScriptClaudeTest.cs.meta
│       │   │   ├── TestAsmdef
│       │   │   │   ├── CustomComponent.cs
│       │   │   │   ├── CustomComponent.cs.meta
│       │   │   │   ├── TestAsmdef.asmdef
│       │   │   │   └── TestAsmdef.asmdef.meta
│       │   │   └── TestAsmdef.meta
│       │   ├── Scripts.meta
│       │   ├── Tests
│       │   │   ├── EditMode
│       │   │   │   ├── Data
│       │   │   │   │   ├── PythonToolsAssetTests.cs
│       │   │   │   │   └── PythonToolsAssetTests.cs.meta
│       │   │   │   ├── Data.meta
│       │   │   │   ├── Helpers
│       │   │   │   │   ├── CodexConfigHelperTests.cs
│       │   │   │   │   ├── CodexConfigHelperTests.cs.meta
│       │   │   │   │   ├── WriteToConfigTests.cs
│       │   │   │   │   └── WriteToConfigTests.cs.meta
│       │   │   │   ├── Helpers.meta
│       │   │   │   ├── MCPForUnityTests.Editor.asmdef
│       │   │   │   ├── MCPForUnityTests.Editor.asmdef.meta
│       │   │   │   ├── Resources
│       │   │   │   │   ├── GetMenuItemsTests.cs
│       │   │   │   │   └── GetMenuItemsTests.cs.meta
│       │   │   │   ├── Resources.meta
│       │   │   │   ├── Services
│       │   │   │   │   ├── PackageUpdateServiceTests.cs
│       │   │   │   │   ├── PackageUpdateServiceTests.cs.meta
│       │   │   │   │   ├── PythonToolRegistryServiceTests.cs
│       │   │   │   │   ├── PythonToolRegistryServiceTests.cs.meta
│       │   │   │   │   ├── ToolSyncServiceTests.cs
│       │   │   │   │   └── ToolSyncServiceTests.cs.meta
│       │   │   │   ├── Services.meta
│       │   │   │   ├── Tools
│       │   │   │   │   ├── AIPropertyMatchingTests.cs
│       │   │   │   │   ├── AIPropertyMatchingTests.cs.meta
│       │   │   │   │   ├── CommandRegistryTests.cs
│       │   │   │   │   ├── CommandRegistryTests.cs.meta
│       │   │   │   │   ├── ComponentResolverTests.cs
│       │   │   │   │   ├── ComponentResolverTests.cs.meta
│       │   │   │   │   ├── ExecuteMenuItemTests.cs
│       │   │   │   │   ├── ExecuteMenuItemTests.cs.meta
│       │   │   │   │   ├── ManageGameObjectTests.cs
│       │   │   │   │   ├── ManageGameObjectTests.cs.meta
│       │   │   │   │   ├── ManagePrefabsTests.cs
│       │   │   │   │   ├── ManagePrefabsTests.cs.meta
│       │   │   │   │   ├── ManageScriptValidationTests.cs
│       │   │   │   │   ├── ManageScriptValidationTests.cs.meta
│       │   │   │   │   └── MaterialMeshInstantiationTests.cs
│       │   │   │   ├── Tools.meta
│       │   │   │   ├── Windows
│       │   │   │   │   ├── ManualConfigJsonBuilderTests.cs
│       │   │   │   │   └── ManualConfigJsonBuilderTests.cs.meta
│       │   │   │   └── Windows.meta
│       │   │   └── EditMode.meta
│       │   └── Tests.meta
│       ├── Packages
│       │   └── manifest.json
│       └── ProjectSettings
│           ├── Packages
│           │   └── com.unity.testtools.codecoverage
│           │       └── Settings.json
│           └── ProjectVersion.txt
├── tests
│   ├── conftest.py
│   ├── test_edit_normalization_and_noop.py
│   ├── test_edit_strict_and_warnings.py
│   ├── test_find_in_file_minimal.py
│   ├── test_get_sha.py
│   ├── test_improved_anchor_matching.py
│   ├── test_logging_stdout.py
│   ├── test_manage_script_uri.py
│   ├── test_read_console_truncate.py
│   ├── test_read_resource_minimal.py
│   ├── test_resources_api.py
│   ├── test_script_editing.py
│   ├── test_script_tools.py
│   ├── test_telemetry_endpoint_validation.py
│   ├── test_telemetry_queue_worker.py
│   ├── test_telemetry_subaction.py
│   ├── test_transport_framing.py
│   └── test_validate_script_summary.py
├── tools
│   └── stress_mcp.py
└── UnityMcpBridge
    ├── Editor
    │   ├── AssemblyInfo.cs
    │   ├── AssemblyInfo.cs.meta
    │   ├── Data
    │   │   ├── DefaultServerConfig.cs
    │   │   ├── DefaultServerConfig.cs.meta
    │   │   ├── McpClients.cs
    │   │   └── McpClients.cs.meta
    │   ├── Data.meta
    │   ├── Dependencies
    │   │   ├── DependencyManager.cs
    │   │   ├── DependencyManager.cs.meta
    │   │   ├── Models
    │   │   │   ├── DependencyCheckResult.cs
    │   │   │   ├── DependencyCheckResult.cs.meta
    │   │   │   ├── DependencyStatus.cs
    │   │   │   └── DependencyStatus.cs.meta
    │   │   ├── Models.meta
    │   │   ├── PlatformDetectors
    │   │   │   ├── IPlatformDetector.cs
    │   │   │   ├── IPlatformDetector.cs.meta
    │   │   │   ├── LinuxPlatformDetector.cs
    │   │   │   ├── LinuxPlatformDetector.cs.meta
    │   │   │   ├── MacOSPlatformDetector.cs
    │   │   │   ├── MacOSPlatformDetector.cs.meta
    │   │   │   ├── PlatformDetectorBase.cs
    │   │   │   ├── PlatformDetectorBase.cs.meta
    │   │   │   ├── WindowsPlatformDetector.cs
    │   │   │   └── WindowsPlatformDetector.cs.meta
    │   │   └── PlatformDetectors.meta
    │   ├── Dependencies.meta
    │   ├── External
    │   │   ├── Tommy.cs
    │   │   └── Tommy.cs.meta
    │   ├── External.meta
    │   ├── Helpers
    │   │   ├── AssetPathUtility.cs
    │   │   ├── AssetPathUtility.cs.meta
    │   │   ├── CodexConfigHelper.cs
    │   │   ├── CodexConfigHelper.cs.meta
    │   │   ├── ConfigJsonBuilder.cs
    │   │   ├── ConfigJsonBuilder.cs.meta
    │   │   ├── ExecPath.cs
    │   │   ├── ExecPath.cs.meta
    │   │   ├── GameObjectSerializer.cs
    │   │   ├── GameObjectSerializer.cs.meta
    │   │   ├── McpConfigFileHelper.cs
    │   │   ├── McpConfigFileHelper.cs.meta
    │   │   ├── McpConfigurationHelper.cs
    │   │   ├── McpConfigurationHelper.cs.meta
    │   │   ├── McpLog.cs
    │   │   ├── McpLog.cs.meta
    │   │   ├── McpPathResolver.cs
    │   │   ├── McpPathResolver.cs.meta
    │   │   ├── PackageDetector.cs
    │   │   ├── PackageDetector.cs.meta
    │   │   ├── PackageInstaller.cs
    │   │   ├── PackageInstaller.cs.meta
    │   │   ├── PortManager.cs
    │   │   ├── PortManager.cs.meta
    │   │   ├── Response.cs
    │   │   ├── Response.cs.meta
    │   │   ├── ServerInstaller.cs
    │   │   ├── ServerInstaller.cs.meta
    │   │   ├── ServerPathResolver.cs
    │   │   ├── ServerPathResolver.cs.meta
    │   │   ├── TelemetryHelper.cs
    │   │   ├── TelemetryHelper.cs.meta
    │   │   ├── Vector3Helper.cs
    │   │   └── Vector3Helper.cs.meta
    │   ├── Helpers.meta
    │   ├── MCPForUnity.Editor.asmdef
    │   ├── MCPForUnity.Editor.asmdef.meta
    │   ├── MCPForUnityBridge.cs
    │   ├── MCPForUnityBridge.cs.meta
    │   ├── Models
    │   │   ├── Command.cs
    │   │   ├── Command.cs.meta
    │   │   ├── McpClient.cs
    │   │   ├── McpClient.cs.meta
    │   │   ├── McpConfig.cs
    │   │   ├── McpConfig.cs.meta
    │   │   ├── MCPConfigServer.cs
    │   │   ├── MCPConfigServer.cs.meta
    │   │   ├── MCPConfigServers.cs
    │   │   ├── MCPConfigServers.cs.meta
    │   │   ├── McpStatus.cs
    │   │   ├── McpStatus.cs.meta
    │   │   ├── McpTypes.cs
    │   │   ├── McpTypes.cs.meta
    │   │   ├── ServerConfig.cs
    │   │   └── ServerConfig.cs.meta
    │   ├── Models.meta
    │   ├── Setup
    │   │   ├── SetupWizard.cs
    │   │   ├── SetupWizard.cs.meta
    │   │   ├── SetupWizardWindow.cs
    │   │   └── SetupWizardWindow.cs.meta
    │   ├── Setup.meta
    │   ├── Tools
    │   │   ├── CommandRegistry.cs
    │   │   ├── CommandRegistry.cs.meta
    │   │   ├── ManageAsset.cs
    │   │   ├── ManageAsset.cs.meta
    │   │   ├── ManageEditor.cs
    │   │   ├── ManageEditor.cs.meta
    │   │   ├── ManageGameObject.cs
    │   │   ├── ManageGameObject.cs.meta
    │   │   ├── ManageScene.cs
    │   │   ├── ManageScene.cs.meta
    │   │   ├── ManageScript.cs
    │   │   ├── ManageScript.cs.meta
    │   │   ├── ManageShader.cs
    │   │   ├── ManageShader.cs.meta
    │   │   ├── McpForUnityToolAttribute.cs
    │   │   ├── McpForUnityToolAttribute.cs.meta
    │   │   ├── MenuItems
    │   │   │   ├── ManageMenuItem.cs
    │   │   │   ├── ManageMenuItem.cs.meta
    │   │   │   ├── MenuItemExecutor.cs
    │   │   │   ├── MenuItemExecutor.cs.meta
    │   │   │   ├── MenuItemsReader.cs
    │   │   │   └── MenuItemsReader.cs.meta
    │   │   ├── MenuItems.meta
    │   │   ├── Prefabs
    │   │   │   ├── ManagePrefabs.cs
    │   │   │   └── ManagePrefabs.cs.meta
    │   │   ├── Prefabs.meta
    │   │   ├── ReadConsole.cs
    │   │   └── ReadConsole.cs.meta
    │   ├── Tools.meta
    │   ├── Windows
    │   │   ├── ManualConfigEditorWindow.cs
    │   │   ├── ManualConfigEditorWindow.cs.meta
    │   │   ├── MCPForUnityEditorWindow.cs
    │   │   ├── MCPForUnityEditorWindow.cs.meta
    │   │   ├── VSCodeManualSetupWindow.cs
    │   │   └── VSCodeManualSetupWindow.cs.meta
    │   └── Windows.meta
    ├── Editor.meta
    ├── package.json
    ├── package.json.meta
    ├── README.md
    ├── README.md.meta
    ├── Runtime
    │   ├── MCPForUnity.Runtime.asmdef
    │   ├── MCPForUnity.Runtime.asmdef.meta
    │   ├── Serialization
    │   │   ├── UnityTypeConverters.cs
    │   │   └── UnityTypeConverters.cs.meta
    │   └── Serialization.meta
    ├── Runtime.meta
    └── UnityMcpServer~
        └── src
            ├── __init__.py
            ├── config.py
            ├── Dockerfile
            ├── port_discovery.py
            ├── pyproject.toml
            ├── pyrightconfig.json
            ├── registry
            │   ├── __init__.py
            │   └── tool_registry.py
            ├── reload_sentinel.py
            ├── server_version.txt
            ├── server.py
            ├── telemetry_decorator.py
            ├── telemetry.py
            ├── test_telemetry.py
            ├── tools
            │   ├── __init__.py
            │   ├── manage_asset.py
            │   ├── manage_editor.py
            │   ├── manage_gameobject.py
            │   ├── manage_menu_item.py
            │   ├── manage_prefabs.py
            │   ├── manage_scene.py
            │   ├── manage_script.py
            │   ├── manage_shader.py
            │   ├── read_console.py
            │   ├── resource_tools.py
            │   └── script_apply_edits.py
            ├── unity_connection.py
            └── uv.lock
```

# Files

--------------------------------------------------------------------------------
/MCPForUnity/Editor/Setup/SetupWizardWindow.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.Linq;
using MCPForUnity.Editor.Data;
using MCPForUnity.Editor.Dependencies;
using MCPForUnity.Editor.Dependencies.Models;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using UnityEditor;
using UnityEngine;

namespace MCPForUnity.Editor.Setup
{
    /// <summary>
    /// Setup wizard window for guiding users through dependency installation
    /// </summary>
    public class SetupWizardWindow : EditorWindow
    {
        private DependencyCheckResult _dependencyResult;
        private Vector2 _scrollPosition;
        private int _currentStep = 0;
        private McpClients _mcpClients;
        private int _selectedClientIndex = 0;

        private readonly string[] _stepTitles = {
            "Setup",
            "Configure",
            "Complete"
        };

        public static void ShowWindow(DependencyCheckResult dependencyResult = null)
        {
            var window = GetWindow<SetupWizardWindow>("MCP for Unity Setup");
            window.minSize = new Vector2(500, 400);
            window.maxSize = new Vector2(800, 600);
            window._dependencyResult = dependencyResult ?? DependencyManager.CheckAllDependencies();
            window.Show();
        }

        private void OnEnable()
        {
            if (_dependencyResult == null)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }

            _mcpClients = new McpClients();

            // Check client configurations on startup
            foreach (var client in _mcpClients.clients)
            {
                CheckClientConfiguration(client);
            }
        }

        private void OnGUI()
        {
            DrawHeader();
            DrawProgressBar();

            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);

            switch (_currentStep)
            {
                case 0: DrawSetupStep(); break;
                case 1: DrawConfigureStep(); break;
                case 2: DrawCompleteStep(); break;
            }

            EditorGUILayout.EndScrollView();

            DrawFooter();
        }

        private void DrawHeader()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            GUILayout.Label("MCP for Unity Setup Wizard", EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            GUILayout.Label($"Step {_currentStep + 1} of {_stepTitles.Length}");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();

            // Step title
            var titleStyle = new GUIStyle(EditorStyles.largeLabel)
            {
                fontSize = 16,
                fontStyle = FontStyle.Bold
            };
            EditorGUILayout.LabelField(_stepTitles[_currentStep], titleStyle);
            EditorGUILayout.Space();
        }

        private void DrawProgressBar()
        {
            var rect = EditorGUILayout.GetControlRect(false, 4);
            var progress = (_currentStep + 1) / (float)_stepTitles.Length;
            EditorGUI.ProgressBar(rect, progress, "");
            EditorGUILayout.Space();
        }

        private void DrawSetupStep()
        {
            // Welcome section
            DrawSectionTitle("MCP for Unity Setup");

            EditorGUILayout.LabelField(
                "This wizard will help you set up MCP for Unity to connect AI assistants with your Unity Editor.",
                EditorStyles.wordWrappedLabel
            );
            EditorGUILayout.Space();

            // Dependency check section
            EditorGUILayout.BeginHorizontal();
            DrawSectionTitle("System Check", 14);
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }
            EditorGUILayout.EndHorizontal();

            // Show simplified dependency status
            foreach (var dep in _dependencyResult.Dependencies)
            {
                DrawSimpleDependencyStatus(dep);
            }

            // Overall status and installation guidance
            EditorGUILayout.Space();
            if (!_dependencyResult.IsSystemReady)
            {
                // Only show critical warnings when dependencies are actually missing
                EditorGUILayout.HelpBox(
                    "⚠️ Missing Dependencies: MCP for Unity requires Python 3.10+ and UV package manager to function properly.",
                    MessageType.Warning
                );

                EditorGUILayout.Space();
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                DrawErrorStatus("Installation Required");

                var recommendations = DependencyManager.GetInstallationRecommendations();
                EditorGUILayout.LabelField(recommendations, EditorStyles.wordWrappedLabel);

                EditorGUILayout.Space();
                if (GUILayout.Button("Open Installation Links", GUILayout.Height(25)))
                {
                    OpenInstallationUrls();
                }
                EditorGUILayout.EndVertical();
            }
            else
            {
                DrawSuccessStatus("System Ready");
                EditorGUILayout.LabelField("All requirements are met. You can proceed to configure your AI clients.", EditorStyles.wordWrappedLabel);
            }
        }



        private void DrawCompleteStep()
        {
            DrawSectionTitle("Setup Complete");

            // Refresh dependency check with caching to avoid heavy operations on every repaint
            if (_dependencyResult == null || (DateTime.UtcNow - _dependencyResult.CheckedAt).TotalSeconds > 2)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }

            if (_dependencyResult.IsSystemReady)
            {
                DrawSuccessStatus("MCP for Unity Ready!");

                EditorGUILayout.HelpBox(
                    "🎉 MCP for Unity is now set up and ready to use!\n\n" +
                    "• Dependencies verified\n" +
                    "• MCP server ready\n" +
                    "• Client configuration accessible",
                    MessageType.Info
                );

                EditorGUILayout.Space();
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Documentation", GUILayout.Height(30)))
                {
                    Application.OpenURL("https://github.com/CoplayDev/unity-mcp");
                }
                if (GUILayout.Button("Client Settings", GUILayout.Height(30)))
                {
                    Windows.MCPForUnityEditorWindow.ShowWindow();
                }
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                DrawErrorStatus("Setup Incomplete - Package Non-Functional");

                EditorGUILayout.HelpBox(
                    "🚨 MCP for Unity CANNOT work - dependencies still missing!\n\n" +
                    "Install ALL required dependencies before the package will function.",
                    MessageType.Error
                );

                var missingDeps = _dependencyResult.GetMissingRequired();
                if (missingDeps.Count > 0)
                {
                    EditorGUILayout.Space();
                    EditorGUILayout.LabelField("Still Missing:", EditorStyles.boldLabel);
                    foreach (var dep in missingDeps)
                    {
                        EditorGUILayout.LabelField($"✗ {dep.Name}", EditorStyles.label);
                    }
                }

                EditorGUILayout.Space();
                if (GUILayout.Button("Go Back to Setup", GUILayout.Height(30)))
                {
                    _currentStep = 0;
                }
            }
        }

        // Helper methods for consistent UI components
        private void DrawSectionTitle(string title, int fontSize = 16)
        {
            var titleStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                fontSize = fontSize,
                fontStyle = FontStyle.Bold
            };
            EditorGUILayout.LabelField(title, titleStyle);
            EditorGUILayout.Space();
        }

        private void DrawSuccessStatus(string message)
        {
            var originalColor = GUI.color;
            GUI.color = Color.green;
            EditorGUILayout.LabelField($"✓ {message}", EditorStyles.boldLabel);
            GUI.color = originalColor;
            EditorGUILayout.Space();
        }

        private void DrawErrorStatus(string message)
        {
            var originalColor = GUI.color;
            GUI.color = Color.red;
            EditorGUILayout.LabelField($"✗ {message}", EditorStyles.boldLabel);
            GUI.color = originalColor;
            EditorGUILayout.Space();
        }

        private void DrawSimpleDependencyStatus(DependencyStatus dep)
        {
            EditorGUILayout.BeginHorizontal();

            var statusIcon = dep.IsAvailable ? "✓" : "✗";
            var statusColor = dep.IsAvailable ? Color.green : Color.red;

            var originalColor = GUI.color;
            GUI.color = statusColor;
            GUILayout.Label(statusIcon, GUILayout.Width(20));
            EditorGUILayout.LabelField(dep.Name, EditorStyles.boldLabel);
            GUI.color = originalColor;

            if (!dep.IsAvailable && !string.IsNullOrEmpty(dep.ErrorMessage))
            {
                EditorGUILayout.LabelField($"({dep.ErrorMessage})", EditorStyles.miniLabel);
            }

            EditorGUILayout.EndHorizontal();
        }

        private void DrawConfigureStep()
        {
            DrawSectionTitle("AI Client Configuration");

            // Check dependencies first (with caching to avoid heavy operations on every repaint)
            if (_dependencyResult == null || (DateTime.UtcNow - _dependencyResult.CheckedAt).TotalSeconds > 2)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }
            if (!_dependencyResult.IsSystemReady)
            {
                DrawErrorStatus("Cannot Configure - System Requirements Not Met");

                EditorGUILayout.HelpBox(
                    "Client configuration requires system dependencies to be installed first. Please complete setup before proceeding.",
                    MessageType.Warning
                );

                if (GUILayout.Button("Go Back to Setup", GUILayout.Height(30)))
                {
                    _currentStep = 0;
                }
                return;
            }

            EditorGUILayout.LabelField(
                "Configure your AI assistants to work with Unity. Select a client below to set it up:",
                EditorStyles.wordWrappedLabel
            );
            EditorGUILayout.Space();

            // Client selection and configuration
            if (_mcpClients.clients.Count > 0)
            {
                // Client selector dropdown
                string[] clientNames = _mcpClients.clients.Select(c => c.name).ToArray();
                EditorGUI.BeginChangeCheck();
                _selectedClientIndex = EditorGUILayout.Popup("Select AI Client:", _selectedClientIndex, clientNames);
                if (EditorGUI.EndChangeCheck())
                {
                    _selectedClientIndex = Mathf.Clamp(_selectedClientIndex, 0, _mcpClients.clients.Count - 1);
                    // Refresh client status when selection changes
                    CheckClientConfiguration(_mcpClients.clients[_selectedClientIndex]);
                }

                EditorGUILayout.Space();

                var selectedClient = _mcpClients.clients[_selectedClientIndex];
                DrawClientConfigurationInWizard(selectedClient);

                EditorGUILayout.Space();

                // Batch configuration option
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                EditorGUILayout.LabelField("Quick Setup", EditorStyles.boldLabel);
                EditorGUILayout.LabelField(
                    "Automatically configure all detected AI clients at once:",
                    EditorStyles.wordWrappedLabel
                );
                EditorGUILayout.Space();

                if (GUILayout.Button("Configure All Detected Clients", GUILayout.Height(30)))
                {
                    ConfigureAllClientsInWizard();
                }
                EditorGUILayout.EndVertical();
            }
            else
            {
                EditorGUILayout.HelpBox("No AI clients detected. Make sure you have Claude Code, Cursor, or VSCode installed.", MessageType.Info);
            }

            EditorGUILayout.Space();
            EditorGUILayout.HelpBox(
                "💡 You might need to restart your AI client after configuring.",
                MessageType.Info
            );
        }

        private void DrawFooter()
        {
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            // Back button
            GUI.enabled = _currentStep > 0;
            if (GUILayout.Button("Back", GUILayout.Width(60)))
            {
                _currentStep--;
            }

            GUILayout.FlexibleSpace();

            // Skip button
            if (GUILayout.Button("Skip", GUILayout.Width(60)))
            {
                bool dismiss = EditorUtility.DisplayDialog(
                    "Skip Setup",
                    "⚠️ Skipping setup will leave MCP for Unity non-functional!\n\n" +
                    "You can restart setup from: Window > MCP for Unity > Setup Wizard (Required)",
                    "Skip Anyway",
                    "Cancel"
                );

                if (dismiss)
                {
                    SetupWizard.MarkSetupDismissed();
                    Close();
                }
            }

            // Next/Done button
            GUI.enabled = true;
            string buttonText = _currentStep == _stepTitles.Length - 1 ? "Done" : "Next";

            if (GUILayout.Button(buttonText, GUILayout.Width(80)))
            {
                if (_currentStep == _stepTitles.Length - 1)
                {
                    SetupWizard.MarkSetupCompleted();
                    Close();
                }
                else
                {
                    _currentStep++;
                }
            }

            GUI.enabled = true;
            EditorGUILayout.EndHorizontal();
        }

        private void DrawClientConfigurationInWizard(McpClient client)
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            EditorGUILayout.LabelField($"{client.name} Configuration", EditorStyles.boldLabel);
            EditorGUILayout.Space();

            // Show current status
            var statusColor = GetClientStatusColor(client);
            var originalColor = GUI.color;
            GUI.color = statusColor;
            EditorGUILayout.LabelField($"Status: {client.configStatus}", EditorStyles.label);
            GUI.color = originalColor;

            EditorGUILayout.Space();

            // Configuration buttons
            EditorGUILayout.BeginHorizontal();

            if (client.mcpType == McpTypes.ClaudeCode)
            {
                // Special handling for Claude Code
                bool claudeAvailable = !string.IsNullOrEmpty(ExecPath.ResolveClaude());
                if (claudeAvailable)
                {
                    bool isConfigured = client.status == McpStatus.Configured;
                    string buttonText = isConfigured ? "Unregister" : "Register";
                    if (GUILayout.Button($"{buttonText} with Claude Code"))
                    {
                        if (isConfigured)
                        {
                            UnregisterFromClaudeCode(client);
                        }
                        else
                        {
                            RegisterWithClaudeCode(client);
                        }
                    }
                }
                else
                {
                    EditorGUILayout.HelpBox("Claude Code not found. Please install Claude Code first.", MessageType.Warning);
                    if (GUILayout.Button("Open Claude Code Website"))
                    {
                        Application.OpenURL("https://claude.ai/download");
                    }
                }
            }
            else
            {
                // Standard client configuration
                if (GUILayout.Button($"Configure {client.name}"))
                {
                    ConfigureClientInWizard(client);
                }

                if (GUILayout.Button("Manual Setup"))
                {
                    ShowManualSetupInWizard(client);
                }
            }

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
        }

        private Color GetClientStatusColor(McpClient client)
        {
            return client.status switch
            {
                McpStatus.Configured => Color.green,
                McpStatus.Running => Color.green,
                McpStatus.Connected => Color.green,
                McpStatus.IncorrectPath => Color.yellow,
                McpStatus.CommunicationError => Color.yellow,
                McpStatus.NoResponse => Color.yellow,
                _ => Color.red
            };
        }

        private void ConfigureClientInWizard(McpClient client)
        {
            try
            {
                string result = PerformClientConfiguration(client);

                EditorUtility.DisplayDialog(
                    $"{client.name} Configuration",
                    result,
                    "OK"
                );

                // Refresh client status
                CheckClientConfiguration(client);
                Repaint();
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog(
                    "Configuration Error",
                    $"Failed to configure {client.name}: {ex.Message}",
                    "OK"
                );
            }
        }

        private void ConfigureAllClientsInWizard()
        {
            int successCount = 0;
            int totalCount = _mcpClients.clients.Count;

            foreach (var client in _mcpClients.clients)
            {
                try
                {
                    if (client.mcpType == McpTypes.ClaudeCode)
                    {
                        if (!string.IsNullOrEmpty(ExecPath.ResolveClaude()) && client.status != McpStatus.Configured)
                        {
                            RegisterWithClaudeCode(client);
                            successCount++;
                        }
                        else if (client.status == McpStatus.Configured)
                        {
                            successCount++; // Already configured
                        }
                    }
                    else
                    {
                        string result = PerformClientConfiguration(client);
                        if (result.Contains("success", System.StringComparison.OrdinalIgnoreCase))
                        {
                            successCount++;
                        }
                    }

                    CheckClientConfiguration(client);
                }
                catch (System.Exception ex)
                {
                    McpLog.Error($"Failed to configure {client.name}: {ex.Message}");
                }
            }

            EditorUtility.DisplayDialog(
                "Batch Configuration Complete",
                $"Successfully configured {successCount} out of {totalCount} clients.\n\n" +
                "Restart your AI clients for changes to take effect.",
                "OK"
            );

            Repaint();
        }

        private void RegisterWithClaudeCode(McpClient client)
        {
            try
            {
                string pythonDir = McpPathResolver.FindPackagePythonDirectory();
                string claudePath = ExecPath.ResolveClaude();
                string uvPath = ExecPath.ResolveUv() ?? "uv";

                string args = $"mcp add UnityMCP -- \"{uvPath}\" run --directory \"{pythonDir}\" server.py";

                if (!ExecPath.TryRun(claudePath, args, null, out var stdout, out var stderr, 15000, McpPathResolver.GetPathPrepend()))
                {
                    if ((stdout + stderr).Contains("already exists", System.StringComparison.OrdinalIgnoreCase))
                    {
                        CheckClientConfiguration(client);
                        EditorUtility.DisplayDialog("Claude Code", "MCP for Unity is already registered with Claude Code.", "OK");
                    }
                    else
                    {
                        throw new System.Exception($"Registration failed: {stderr}");
                    }
                }
                else
                {
                    CheckClientConfiguration(client);
                    EditorUtility.DisplayDialog("Claude Code", "Successfully registered MCP for Unity with Claude Code!", "OK");
                }
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog("Registration Error", $"Failed to register with Claude Code: {ex.Message}", "OK");
            }
        }

        private void UnregisterFromClaudeCode(McpClient client)
        {
            try
            {
                string claudePath = ExecPath.ResolveClaude();
                if (ExecPath.TryRun(claudePath, "mcp remove UnityMCP", null, out var stdout, out var stderr, 10000, McpPathResolver.GetPathPrepend()))
                {
                    CheckClientConfiguration(client);
                    EditorUtility.DisplayDialog("Claude Code", "Successfully unregistered MCP for Unity from Claude Code.", "OK");
                }
                else
                {
                    throw new System.Exception($"Unregistration failed: {stderr}");
                }
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog("Unregistration Error", $"Failed to unregister from Claude Code: {ex.Message}", "OK");
            }
        }

        private string PerformClientConfiguration(McpClient client)
        {
            // This mirrors the logic from MCPForUnityEditorWindow.ConfigureMcpClient
            string configPath = McpConfigurationHelper.GetClientConfigPath(client);
            string pythonDir = McpPathResolver.FindPackagePythonDirectory();

            if (string.IsNullOrEmpty(pythonDir))
            {
                return "Manual configuration required - Python server directory not found.";
            }

            McpConfigurationHelper.EnsureConfigDirectoryExists(configPath);
            return McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
        }

        private void ShowManualSetupInWizard(McpClient client)
        {
            string configPath = McpConfigurationHelper.GetClientConfigPath(client);
            string pythonDir = McpPathResolver.FindPackagePythonDirectory();
            string uvPath = ServerInstaller.FindUvPath();

            if (string.IsNullOrEmpty(uvPath))
            {
                EditorUtility.DisplayDialog("Manual Setup", "UV package manager not found. Please install UV first.", "OK");
                return;
            }

            // Build manual configuration using the sophisticated helper logic
            string result = McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
            string manualConfig;

            if (result == "Configured successfully")
            {
                // Read back the configuration that was written
                try
                {
                    manualConfig = System.IO.File.ReadAllText(configPath);
                }
                catch
                {
                    manualConfig = "Configuration written successfully, but could not read back for display.";
                }
            }
            else
            {
                manualConfig = $"Configuration failed: {result}";
            }

            EditorUtility.DisplayDialog(
                $"Manual Setup - {client.name}",
                $"Configuration file location:\n{configPath}\n\n" +
                $"Configuration result:\n{manualConfig}",
                "OK"
            );
        }

        private void CheckClientConfiguration(McpClient client)
        {
            // Basic status check - could be enhanced to mirror MCPForUnityEditorWindow logic
            try
            {
                string configPath = McpConfigurationHelper.GetClientConfigPath(client);
                if (System.IO.File.Exists(configPath))
                {
                    client.configStatus = "Configured";
                    client.status = McpStatus.Configured;
                }
                else
                {
                    client.configStatus = "Not Configured";
                    client.status = McpStatus.NotConfigured;
                }
            }
            catch
            {
                client.configStatus = "Error";
                client.status = McpStatus.Error;
            }
        }

        private void OpenInstallationUrls()
        {
            var (pythonUrl, uvUrl) = DependencyManager.GetInstallationUrls();

            bool openPython = EditorUtility.DisplayDialog(
                "Open Installation URLs",
                "Open Python installation page?",
                "Yes",
                "No"
            );

            if (openPython)
            {
                Application.OpenURL(pythonUrl);
            }

            bool openUV = EditorUtility.DisplayDialog(
                "Open Installation URLs",
                "Open UV installation page?",
                "Yes",
                "No"
            );

            if (openUV)
            {
                Application.OpenURL(uvUrl);
            }
        }
    }
}

```

--------------------------------------------------------------------------------
/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.Collections.Generic;
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEditor;
using UnityEngine.TestTools;
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Tools;

namespace MCPForUnityTests.Editor.Tools
{
    public class ManageGameObjectTests
    {
        private GameObject testGameObject;

        [SetUp]
        public void SetUp()
        {
            // Create a test GameObject for each test
            testGameObject = new GameObject("TestObject");
        }

        [TearDown]
        public void TearDown()
        {
            // Clean up test GameObject
            if (testGameObject != null)
            {
                UnityEngine.Object.DestroyImmediate(testGameObject);
            }
        }

        [Test]
        public void HandleCommand_ReturnsError_ForNullParams()
        {
            var result = ManageGameObject.HandleCommand(null);

            Assert.IsNotNull(result, "Should return a result object");
            // Note: Actual error checking would need access to Response structure
        }

        [Test]
        public void HandleCommand_ReturnsError_ForEmptyParams()
        {
            var emptyParams = new JObject();
            var result = ManageGameObject.HandleCommand(emptyParams);

            Assert.IsNotNull(result, "Should return a result object for empty params");
        }

        [Test]
        public void HandleCommand_ProcessesValidCreateAction()
        {
            var createParams = new JObject
            {
                ["action"] = "create",
                ["name"] = "TestCreateObject"
            };

            var result = ManageGameObject.HandleCommand(createParams);

            Assert.IsNotNull(result, "Should return a result for valid create action");

            // Clean up - find and destroy the created object
            var createdObject = GameObject.Find("TestCreateObject");
            if (createdObject != null)
            {
                UnityEngine.Object.DestroyImmediate(createdObject);
            }
        }

        [Test]
        public void ComponentResolver_Integration_WorksWithRealComponents()
        {
            // Test that our ComponentResolver works with actual Unity components
            var transformResult = ComponentResolver.TryResolve("Transform", out Type transformType, out string error);

            Assert.IsTrue(transformResult, "Should resolve Transform component");
            Assert.AreEqual(typeof(Transform), transformType, "Should return correct Transform type");
            Assert.IsEmpty(error, "Should have no error for valid component");
        }

        [Test]
        public void ComponentResolver_Integration_WorksWithBuiltInComponents()
        {
            var components = new[]
            {
                ("Rigidbody", typeof(Rigidbody)),
                ("Collider", typeof(Collider)),
                ("Renderer", typeof(Renderer)),
                ("Camera", typeof(Camera)),
                ("Light", typeof(Light))
            };

            foreach (var (componentName, expectedType) in components)
            {
                var result = ComponentResolver.TryResolve(componentName, out Type actualType, out string error);

                // Some components might not resolve (abstract classes), but the method should handle gracefully
                if (result)
                {
                    Assert.IsTrue(expectedType.IsAssignableFrom(actualType),
                        $"{componentName} should resolve to assignable type");
                }
                else
                {
                    Assert.IsNotEmpty(error, $"Should have error message for {componentName}");
                }
            }
        }

        [Test]
        public void PropertyMatching_Integration_WorksWithRealGameObject()
        {
            // Add a Rigidbody to test real property matching
            var rigidbody = testGameObject.AddComponent<Rigidbody>();

            var properties = ComponentResolver.GetAllComponentProperties(typeof(Rigidbody));

            Assert.IsNotEmpty(properties, "Rigidbody should have properties");
            Assert.Contains("mass", properties, "Rigidbody should have mass property");
            Assert.Contains("useGravity", properties, "Rigidbody should have useGravity property");

            // Test AI suggestions
            var suggestions = ComponentResolver.GetAIPropertySuggestions("Use Gravity", properties);
            Assert.Contains("useGravity", suggestions, "Should suggest useGravity for 'Use Gravity'");
        }

        [Test]
        public void PropertyMatching_HandlesMonoBehaviourProperties()
        {
            var properties = ComponentResolver.GetAllComponentProperties(typeof(MonoBehaviour));

            Assert.IsNotEmpty(properties, "MonoBehaviour should have properties");
            Assert.Contains("enabled", properties, "MonoBehaviour should have enabled property");
            Assert.Contains("name", properties, "MonoBehaviour should have name property");
            Assert.Contains("tag", properties, "MonoBehaviour should have tag property");
        }

        [Test]
        public void PropertyMatching_HandlesCaseVariations()
        {
            var testProperties = new List<string> { "maxReachDistance", "playerHealth", "movementSpeed" };

            var testCases = new[]
            {
                ("max reach distance", "maxReachDistance"),
                ("Max Reach Distance", "maxReachDistance"),
                ("MAX_REACH_DISTANCE", "maxReachDistance"),
                ("player health", "playerHealth"),
                ("movement speed", "movementSpeed")
            };

            foreach (var (input, expected) in testCases)
            {
                var suggestions = ComponentResolver.GetAIPropertySuggestions(input, testProperties);
                Assert.Contains(expected, suggestions, $"Should suggest {expected} for input '{input}'");
            }
        }

        [Test]
        public void ErrorHandling_ReturnsHelpfulMessages()
        {
            // This test verifies that error messages are helpful and contain suggestions
            var testProperties = new List<string> { "mass", "velocity", "drag", "useGravity" };
            var suggestions = ComponentResolver.GetAIPropertySuggestions("weight", testProperties);

            // Even if no perfect match, should return valid list
            Assert.IsNotNull(suggestions, "Should return valid suggestions list");

            // Test with completely invalid input
            var badSuggestions = ComponentResolver.GetAIPropertySuggestions("xyz123invalid", testProperties);
            Assert.IsNotNull(badSuggestions, "Should handle invalid input gracefully");
        }

        [Test]
        public void PerformanceTest_CachingWorks()
        {
            var properties = ComponentResolver.GetAllComponentProperties(typeof(Transform));
            var input = "Test Property Name";

            // First call - populate cache
            var startTime = System.DateTime.UtcNow;
            var suggestions1 = ComponentResolver.GetAIPropertySuggestions(input, properties);
            var firstCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;

            // Second call - should use cache
            startTime = System.DateTime.UtcNow;
            var suggestions2 = ComponentResolver.GetAIPropertySuggestions(input, properties);
            var secondCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;

            Assert.AreEqual(suggestions1.Count, suggestions2.Count, "Cached results should be identical");
            CollectionAssert.AreEqual(suggestions1, suggestions2, "Cached results should match exactly");

            // Second call should be faster (though this test might be flaky)
            Assert.LessOrEqual(secondCallTime, firstCallTime * 2, "Cached call should not be significantly slower");
        }

        [Test]
        public void SetComponentProperties_CollectsAllFailuresAndAppliesValidOnes()
        {
            // Arrange - add Transform and Rigidbody components to test with
            var transform = testGameObject.transform;
            var rigidbody = testGameObject.AddComponent<Rigidbody>();

            // Create a params object with mixed valid and invalid properties
            var setPropertiesParams = new JObject
            {
                ["action"] = "modify",
                ["target"] = testGameObject.name,
                ["search_method"] = "by_name",
                ["componentProperties"] = new JObject
                {
                    ["Transform"] = new JObject
                    {
                        ["localPosition"] = new JObject { ["x"] = 1.0f, ["y"] = 2.0f, ["z"] = 3.0f },  // Valid
                        ["rotatoin"] = new JObject { ["x"] = 0.0f, ["y"] = 90.0f, ["z"] = 0.0f }, // Invalid (typo - should be rotation)
                        ["localScale"] = new JObject { ["x"] = 2.0f, ["y"] = 2.0f, ["z"] = 2.0f }      // Valid
                    },
                    ["Rigidbody"] = new JObject
                    {
                        ["mass"] = 5.0f,            // Valid
                        ["invalidProp"] = "test",   // Invalid - doesn't exist
                        ["useGravity"] = true       // Valid
                    }
                }
            };

            // Store original values to verify changes  
            var originalLocalPosition = transform.localPosition;
            var originalLocalScale = transform.localScale;
            var originalMass = rigidbody.mass;
            var originalUseGravity = rigidbody.useGravity;

            Debug.Log($"BEFORE TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");

            // Expect the warning logs from the invalid properties
            LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'rotatoin' not found"));
            LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'invalidProp' not found"));

            // Act
            var result = ManageGameObject.HandleCommand(setPropertiesParams);

            Debug.Log($"AFTER TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");
            Debug.Log($"AFTER TEST - LocalPosition: {transform.localPosition}");
            Debug.Log($"AFTER TEST - LocalScale: {transform.localScale}");

            // Assert - verify that valid properties were set despite invalid ones
            Assert.AreEqual(new Vector3(1.0f, 2.0f, 3.0f), transform.localPosition,
                "Valid localPosition should be set even with other invalid properties");
            Assert.AreEqual(new Vector3(2.0f, 2.0f, 2.0f), transform.localScale,
                "Valid localScale should be set even with other invalid properties");
            Assert.AreEqual(5.0f, rigidbody.mass, 0.001f,
                "Valid mass should be set even with other invalid properties");
            Assert.AreEqual(true, rigidbody.useGravity,
                "Valid useGravity should be set even with other invalid properties");

            // Verify the result indicates errors (since we had invalid properties)
            Assert.IsNotNull(result, "Should return a result object");

            // The collect-and-continue behavior means we should get an error response 
            // that contains info about the failed properties, but valid ones were still applied
            // This proves the collect-and-continue behavior is working

            // Harden: verify structured error response with failures list contains both invalid fields
            var successProp = result.GetType().GetProperty("success");
            Assert.IsNotNull(successProp, "Result should expose 'success' property");
            Assert.IsFalse((bool)successProp.GetValue(result), "Result.success should be false for partial failure");

            var dataProp = result.GetType().GetProperty("data");
            Assert.IsNotNull(dataProp, "Result should include 'data' with errors");
            var dataVal = dataProp.GetValue(result);
            Assert.IsNotNull(dataVal, "Result.data should not be null");
            var errorsProp = dataVal.GetType().GetProperty("errors");
            Assert.IsNotNull(errorsProp, "Result.data should include 'errors' list");
            var errorsEnum = errorsProp.GetValue(dataVal) as System.Collections.IEnumerable;
            Assert.IsNotNull(errorsEnum, "errors should be enumerable");

            bool foundRotatoin = false;
            bool foundInvalidProp = false;
            foreach (var err in errorsEnum)
            {
                string s = err?.ToString() ?? string.Empty;
                if (s.Contains("rotatoin")) foundRotatoin = true;
                if (s.Contains("invalidProp")) foundInvalidProp = true;
            }
            Assert.IsTrue(foundRotatoin, "errors should mention the misspelled 'rotatoin' property");
            Assert.IsTrue(foundInvalidProp, "errors should mention the 'invalidProp' property");
        }

        [Test]
        public void SetComponentProperties_ContinuesAfterException()
        {
            // Arrange - create scenario that might cause exceptions
            var rigidbody = testGameObject.AddComponent<Rigidbody>();

            // Set initial values that we'll change
            rigidbody.mass = 1.0f;
            rigidbody.useGravity = true;

            var setPropertiesParams = new JObject
            {
                ["action"] = "modify",
                ["target"] = testGameObject.name,
                ["search_method"] = "by_name",
                ["componentProperties"] = new JObject
                {
                    ["Rigidbody"] = new JObject
                    {
                        ["mass"] = 2.5f,                    // Valid - should be set
                        ["velocity"] = "invalid_type",      // Invalid type - will cause exception  
                        ["useGravity"] = false              // Valid - should still be set after exception
                    }
                }
            };

            // Expect the error logs from the invalid property
            LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex("Unexpected error converting token to UnityEngine.Vector3"));
            LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex("SetProperty.*Failed to set 'velocity'"));
            LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'velocity' not found"));

            // Act
            var result = ManageGameObject.HandleCommand(setPropertiesParams);

            // Assert - verify that valid properties before AND after the exception were still set
            Assert.AreEqual(2.5f, rigidbody.mass, 0.001f,
                "Mass should be set even if later property causes exception");
            Assert.AreEqual(false, rigidbody.useGravity,
                "UseGravity should be set even if previous property caused exception");

            Assert.IsNotNull(result, "Should return a result even with exceptions");

            // The key test: processing continued after the exception and set useGravity
            // This proves the collect-and-continue behavior works even with exceptions

            // Harden: verify structured error response contains velocity failure
            var successProp2 = result.GetType().GetProperty("success");
            Assert.IsNotNull(successProp2, "Result should expose 'success' property");
            Assert.IsFalse((bool)successProp2.GetValue(result), "Result.success should be false when an exception occurs for a property");

            var dataProp2 = result.GetType().GetProperty("data");
            Assert.IsNotNull(dataProp2, "Result should include 'data' with errors");
            var dataVal2 = dataProp2.GetValue(result);
            Assert.IsNotNull(dataVal2, "Result.data should not be null");
            var errorsProp2 = dataVal2.GetType().GetProperty("errors");
            Assert.IsNotNull(errorsProp2, "Result.data should include 'errors' list");
            var errorsEnum2 = errorsProp2.GetValue(dataVal2) as System.Collections.IEnumerable;
            Assert.IsNotNull(errorsEnum2, "errors should be enumerable");

            bool foundVelocityError = false;
            foreach (var err in errorsEnum2)
            {
                string s = err?.ToString() ?? string.Empty;
                if (s.Contains("velocity")) { foundVelocityError = true; break; }
            }
            Assert.IsTrue(foundVelocityError, "errors should include a message referencing 'velocity'");
        }

        [Test]
        public void GetComponentData_DoesNotInstantiateMaterialsInEditMode()
        {
            // Arrange - Create a GameObject with MeshRenderer and MeshFilter components
            var testObject = new GameObject("MaterialMeshTestObject");
            var meshRenderer = testObject.AddComponent<MeshRenderer>();
            var meshFilter = testObject.AddComponent<MeshFilter>();
            
            // Create a simple material and mesh for testing
            var testMaterial = new Material(Shader.Find("Standard"));
            var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            var testMesh = tempCube.GetComponent<MeshFilter>().sharedMesh;
            UnityEngine.Object.DestroyImmediate(tempCube);
            
            // Set the shared material and mesh (these should be used in edit mode)
            meshRenderer.sharedMaterial = testMaterial;
            meshFilter.sharedMesh = testMesh;
            
            // Act - Get component data which should trigger material/mesh property access
            var prevIgnore = LogAssert.ignoreFailingMessages;
            LogAssert.ignoreFailingMessages = true; // Avoid failing due to incidental editor logs during reflection
            object result;
            try
            {
                result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
            }
            finally
            {
                LogAssert.ignoreFailingMessages = prevIgnore;
            }
            
            // Assert - Basic success and shape tolerance
            Assert.IsNotNull(result, "GetComponentData should return a result");
            if (result is Dictionary<string, object> dict &&
                dict.TryGetValue("properties", out var propsObj) &&
                propsObj is Dictionary<string, object> properties)
            {
                Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial") || properties.ContainsKey("materials") || properties.ContainsKey("sharedMaterials"),
                    "Serialized data should include a material-related key when present.");
            }
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(testMaterial);
            UnityEngine.Object.DestroyImmediate(testObject);
        }

        [Test]
        public void GetComponentData_DoesNotInstantiateMeshesInEditMode()
        {
            // Arrange - Create a GameObject with MeshFilter component
            var testObject = new GameObject("MeshTestObject");
            var meshFilter = testObject.AddComponent<MeshFilter>();
            
            // Create a simple mesh for testing
            var tempSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            var testMesh = tempSphere.GetComponent<MeshFilter>().sharedMesh;
            UnityEngine.Object.DestroyImmediate(tempSphere);
            meshFilter.sharedMesh = testMesh;
            
            // Act - Get component data which should trigger mesh property access
            var prevIgnore2 = LogAssert.ignoreFailingMessages;
            LogAssert.ignoreFailingMessages = true;
            object result;
            try
            {
                result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
            }
            finally
            {
                LogAssert.ignoreFailingMessages = prevIgnore2;
            }
            
            // Assert - Basic success and shape tolerance
            Assert.IsNotNull(result, "GetComponentData should return a result");
            if (result is Dictionary<string, object> dict2 &&
                dict2.TryGetValue("properties", out var propsObj2) &&
                propsObj2 is Dictionary<string, object> properties2)
            {
                Assert.IsTrue(properties2.ContainsKey("mesh") || properties2.ContainsKey("sharedMesh"),
                    "Serialized data should include a mesh-related key when present.");
            }
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(testObject);
        }

        [Test]
        public void GetComponentData_UsesSharedMaterialInEditMode()
        {
            // Arrange - Create a GameObject with MeshRenderer
            var testObject = new GameObject("SharedMaterialTestObject");
            var meshRenderer = testObject.AddComponent<MeshRenderer>();
            
            // Create a test material
            var testMaterial = new Material(Shader.Find("Standard"));
            testMaterial.name = "TestMaterial";
            meshRenderer.sharedMaterial = testMaterial;
            
            // Act - Get component data in edit mode
            var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
            
            // Assert - Verify that the material property was accessed without instantiation
            Assert.IsNotNull(result, "GetComponentData should return a result");
            
            // Check that result is a dictionary with properties key
            if (result is Dictionary<string, object> resultDict && 
                resultDict.TryGetValue("properties", out var propertiesObj) &&
                propertiesObj is Dictionary<string, object> properties)
            {
                Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial"),
                    "Serialized data should include 'material' or 'sharedMaterial' when present.");
            }
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(testMaterial);
            UnityEngine.Object.DestroyImmediate(testObject);
        }

        [Test]
        public void GetComponentData_UsesSharedMeshInEditMode()
        {
            // Arrange - Create a GameObject with MeshFilter
            var testObject = new GameObject("SharedMeshTestObject");
            var meshFilter = testObject.AddComponent<MeshFilter>();
            
            // Create a test mesh
            var tempCylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
            var testMesh = tempCylinder.GetComponent<MeshFilter>().sharedMesh;
            UnityEngine.Object.DestroyImmediate(tempCylinder);
            testMesh.name = "TestMesh";
            meshFilter.sharedMesh = testMesh;
            
            // Act - Get component data in edit mode
            var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
            
            // Assert - Verify that the mesh property was accessed without instantiation
            Assert.IsNotNull(result, "GetComponentData should return a result");
            
            // Check that result is a dictionary with properties key
            if (result is Dictionary<string, object> resultDict && 
                resultDict.TryGetValue("properties", out var propertiesObj) &&
                propertiesObj is Dictionary<string, object> properties)
            {
                Assert.IsTrue(properties.ContainsKey("mesh") || properties.ContainsKey("sharedMesh"),
                    "Serialized data should include 'mesh' or 'sharedMesh' when present.");
            }
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(testObject);
        }

        [Test]
        public void GetComponentData_HandlesNullMaterialsAndMeshes()
        {
            // Arrange - Create a GameObject with MeshRenderer and MeshFilter but no materials/meshes
            var testObject = new GameObject("NullMaterialMeshTestObject");
            var meshRenderer = testObject.AddComponent<MeshRenderer>();
            var meshFilter = testObject.AddComponent<MeshFilter>();
            
            // Don't set any materials or meshes - they should be null
            
            // Act - Get component data
            var rendererResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
            var meshFilterResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
            
            // Assert - Verify that the operations succeeded even with null materials/meshes
            Assert.IsNotNull(rendererResult, "GetComponentData should handle null materials");
            Assert.IsNotNull(meshFilterResult, "GetComponentData should handle null meshes");
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(testObject);
        }

        [Test]
        public void GetComponentData_WorksWithMultipleMaterials()
        {
            // Arrange - Create a GameObject with MeshRenderer that has multiple materials
            var testObject = new GameObject("MultiMaterialTestObject");
            var meshRenderer = testObject.AddComponent<MeshRenderer>();
            
            // Create multiple test materials
            var material1 = new Material(Shader.Find("Standard"));
            material1.name = "TestMaterial1";
            var material2 = new Material(Shader.Find("Standard"));
            material2.name = "TestMaterial2";
            
            meshRenderer.sharedMaterials = new Material[] { material1, material2 };
            
            // Act - Get component data
            var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
            
            // Assert - Verify that the operation succeeded with multiple materials
            Assert.IsNotNull(result, "GetComponentData should handle multiple materials");
            
            // Clean up
            UnityEngine.Object.DestroyImmediate(material1);
            UnityEngine.Object.DestroyImmediate(material2);
            UnityEngine.Object.DestroyImmediate(testObject);
        }
    }
}

```

--------------------------------------------------------------------------------
/MCPForUnity/Editor/Helpers/GameObjectSerializer.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using MCPForUnity.Runtime.Serialization; // For Converters

namespace MCPForUnity.Editor.Helpers
{
    /// <summary>
    /// Handles serialization of GameObjects and Components for MCP responses.
    /// Includes reflection helpers and caching for performance.
    /// </summary> 
    public static class GameObjectSerializer
    {
        // --- Data Serialization ---

        /// <summary>
        /// Creates a serializable representation of a GameObject.
        /// </summary>
        public static object GetGameObjectData(GameObject go)
        {
            if (go == null)
                return null;
            return new
            {
                name = go.name,
                instanceID = go.GetInstanceID(),
                tag = go.tag,
                layer = go.layer,
                activeSelf = go.activeSelf,
                activeInHierarchy = go.activeInHierarchy,
                isStatic = go.isStatic,
                scenePath = go.scene.path, // Identify which scene it belongs to
                transform = new // Serialize transform components carefully to avoid JSON issues
                {
                    // Serialize Vector3 components individually to prevent self-referencing loops.
                    // The default serializer can struggle with properties like Vector3.normalized.
                    position = new
                    {
                        x = go.transform.position.x,
                        y = go.transform.position.y,
                        z = go.transform.position.z,
                    },
                    localPosition = new
                    {
                        x = go.transform.localPosition.x,
                        y = go.transform.localPosition.y,
                        z = go.transform.localPosition.z,
                    },
                    rotation = new
                    {
                        x = go.transform.rotation.eulerAngles.x,
                        y = go.transform.rotation.eulerAngles.y,
                        z = go.transform.rotation.eulerAngles.z,
                    },
                    localRotation = new
                    {
                        x = go.transform.localRotation.eulerAngles.x,
                        y = go.transform.localRotation.eulerAngles.y,
                        z = go.transform.localRotation.eulerAngles.z,
                    },
                    scale = new
                    {
                        x = go.transform.localScale.x,
                        y = go.transform.localScale.y,
                        z = go.transform.localScale.z,
                    },
                    forward = new
                    {
                        x = go.transform.forward.x,
                        y = go.transform.forward.y,
                        z = go.transform.forward.z,
                    },
                    up = new
                    {
                        x = go.transform.up.x,
                        y = go.transform.up.y,
                        z = go.transform.up.z,
                    },
                    right = new
                    {
                        x = go.transform.right.x,
                        y = go.transform.right.y,
                        z = go.transform.right.z,
                    },
                },
                parentInstanceID = go.transform.parent?.gameObject.GetInstanceID() ?? 0, // 0 if no parent
                // Optionally include components, but can be large
                // components = go.GetComponents<Component>().Select(c => GetComponentData(c)).ToList()
                // Or just component names:
                componentNames = go.GetComponents<Component>()
                    .Select(c => c.GetType().FullName)
                    .ToList(),
            };
        }

        // --- Metadata Caching for Reflection ---
        private class CachedMetadata
        {
            public readonly List<PropertyInfo> SerializableProperties;
            public readonly List<FieldInfo> SerializableFields;

            public CachedMetadata(List<PropertyInfo> properties, List<FieldInfo> fields)
            {
                SerializableProperties = properties;
                SerializableFields = fields;
            }
        }
        // Key becomes Tuple<Type, bool>
        private static readonly Dictionary<Tuple<Type, bool>, CachedMetadata> _metadataCache = new Dictionary<Tuple<Type, bool>, CachedMetadata>();
        // --- End Metadata Caching ---

        /// <summary>
        /// Creates a serializable representation of a Component, attempting to serialize
        /// public properties and fields using reflection, with caching and control over non-public fields.
        /// </summary>
        // Add the flag parameter here
        public static object GetComponentData(Component c, bool includeNonPublicSerializedFields = true)
        {
            // --- Add Early Logging --- 
            // Debug.Log($"[GetComponentData] Starting for component: {c?.GetType()?.FullName ?? "null"} (ID: {c?.GetInstanceID() ?? 0})");
            // --- End Early Logging ---

            if (c == null) return null;
            Type componentType = c.GetType();

            // --- Special handling for Transform to avoid reflection crashes and problematic properties --- 
            if (componentType == typeof(Transform))
            {
                Transform tr = c as Transform;
                // Debug.Log($"[GetComponentData] Manually serializing Transform (ID: {tr.GetInstanceID()})");
                return new Dictionary<string, object>
                {
                    { "typeName", componentType.FullName },
                    { "instanceID", tr.GetInstanceID() },
                    // Manually extract known-safe properties. Avoid Quaternion 'rotation' and 'lossyScale'.
                    { "position", CreateTokenFromValue(tr.position, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "localPosition", CreateTokenFromValue(tr.localPosition, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "eulerAngles", CreateTokenFromValue(tr.eulerAngles, typeof(Vector3))?.ToObject<object>() ?? new JObject() }, // Use Euler angles
                    { "localEulerAngles", CreateTokenFromValue(tr.localEulerAngles, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "localScale", CreateTokenFromValue(tr.localScale, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "right", CreateTokenFromValue(tr.right, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "up", CreateTokenFromValue(tr.up, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "forward", CreateTokenFromValue(tr.forward, typeof(Vector3))?.ToObject<object>() ?? new JObject() },
                    { "parentInstanceID", tr.parent?.gameObject.GetInstanceID() ?? 0 },
                    { "rootInstanceID", tr.root?.gameObject.GetInstanceID() ?? 0 },
                    { "childCount", tr.childCount },
                    // Include standard Object/Component properties
                    { "name", tr.name },
                    { "tag", tr.tag },
                    { "gameObjectInstanceID", tr.gameObject?.GetInstanceID() ?? 0 }
                };
            }
            // --- End Special handling for Transform --- 

            // --- Special handling for Camera to avoid matrix-related crashes ---
            if (componentType == typeof(Camera))
            {
                Camera cam = c as Camera;
                var cameraProperties = new Dictionary<string, object>();

                // List of safe properties to serialize
                var safeProperties = new Dictionary<string, Func<object>>
                {
                    { "nearClipPlane", () => cam.nearClipPlane },
                    { "farClipPlane", () => cam.farClipPlane },
                    { "fieldOfView", () => cam.fieldOfView },
                    { "renderingPath", () => (int)cam.renderingPath },
                    { "actualRenderingPath", () => (int)cam.actualRenderingPath },
                    { "allowHDR", () => cam.allowHDR },
                    { "allowMSAA", () => cam.allowMSAA },
                    { "allowDynamicResolution", () => cam.allowDynamicResolution },
                    { "forceIntoRenderTexture", () => cam.forceIntoRenderTexture },
                    { "orthographicSize", () => cam.orthographicSize },
                    { "orthographic", () => cam.orthographic },
                    { "opaqueSortMode", () => (int)cam.opaqueSortMode },
                    { "transparencySortMode", () => (int)cam.transparencySortMode },
                    { "depth", () => cam.depth },
                    { "aspect", () => cam.aspect },
                    { "cullingMask", () => cam.cullingMask },
                    { "eventMask", () => cam.eventMask },
                    { "backgroundColor", () => cam.backgroundColor },
                    { "clearFlags", () => (int)cam.clearFlags },
                    { "stereoEnabled", () => cam.stereoEnabled },
                    { "stereoSeparation", () => cam.stereoSeparation },
                    { "stereoConvergence", () => cam.stereoConvergence },
                    { "enabled", () => cam.enabled },
                    { "name", () => cam.name },
                    { "tag", () => cam.tag },
                    { "gameObject", () => new { name = cam.gameObject.name, instanceID = cam.gameObject.GetInstanceID() } }
                };

                foreach (var prop in safeProperties)
                {
                    try
                    {
                        var value = prop.Value();
                        if (value != null)
                        {
                            AddSerializableValue(cameraProperties, prop.Key, value.GetType(), value);
                        }
                    }
                    catch (Exception)
                    {
                        // Silently skip any property that fails
                        continue;
                    }
                }

                return new Dictionary<string, object>
                {
                    { "typeName", componentType.FullName },
                    { "instanceID", cam.GetInstanceID() },
                    { "properties", cameraProperties }
                };
            }
            // --- End Special handling for Camera ---

            var data = new Dictionary<string, object>
            {
                { "typeName", componentType.FullName },
                { "instanceID", c.GetInstanceID() }
            };

            // --- Get Cached or Generate Metadata (using new cache key) ---
            Tuple<Type, bool> cacheKey = new Tuple<Type, bool>(componentType, includeNonPublicSerializedFields);
            if (!_metadataCache.TryGetValue(cacheKey, out CachedMetadata cachedData))
            {
                var propertiesToCache = new List<PropertyInfo>();
                var fieldsToCache = new List<FieldInfo>();

                // Traverse the hierarchy from the component type up to MonoBehaviour
                Type currentType = componentType;
                while (currentType != null && currentType != typeof(MonoBehaviour) && currentType != typeof(object))
                {
                    // Get properties declared only at the current type level
                    BindingFlags propFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    foreach (var propInfo in currentType.GetProperties(propFlags))
                    {
                        // Basic filtering (readable, not indexer, not transform which is handled elsewhere)
                        if (!propInfo.CanRead || propInfo.GetIndexParameters().Length > 0 || propInfo.Name == "transform") continue;
                        // Add if not already added (handles overrides - keep the most derived version)
                        if (!propertiesToCache.Any(p => p.Name == propInfo.Name))
                        {
                            propertiesToCache.Add(propInfo);
                        }
                    }

                    // Get fields declared only at the current type level (both public and non-public)
                    BindingFlags fieldFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var declaredFields = currentType.GetFields(fieldFlags);

                    // Process the declared Fields for caching
                foreach (var fieldInfo in declaredFields)
                    {
                        if (fieldInfo.Name.EndsWith("k__BackingField")) continue; // Skip backing fields

                        // Add if not already added (handles hiding - keep the most derived version)
                        if (fieldsToCache.Any(f => f.Name == fieldInfo.Name)) continue;

                    bool shouldInclude = false;
                    if (includeNonPublicSerializedFields)
                    {
                        // If TRUE, include Public OR any NonPublic with [SerializeField] (private/protected/internal)
                        var hasSerializeField = fieldInfo.IsDefined(typeof(SerializeField), inherit: true);
                        shouldInclude = fieldInfo.IsPublic || (!fieldInfo.IsPublic && hasSerializeField);
                    }
                    else // includeNonPublicSerializedFields is FALSE
                    {
                        // If FALSE, include ONLY if it is explicitly Public.
                        shouldInclude = fieldInfo.IsPublic;
                    }

                        if (shouldInclude)
                        {
                            fieldsToCache.Add(fieldInfo);
                        }
                    }

                    // Move to the base type
                    currentType = currentType.BaseType;
                }
                // --- End Hierarchy Traversal ---

                cachedData = new CachedMetadata(propertiesToCache, fieldsToCache);
                _metadataCache[cacheKey] = cachedData; // Add to cache with combined key
            }
            // --- End Get Cached or Generate Metadata ---

            // --- Use cached metadata ---
            var serializablePropertiesOutput = new Dictionary<string, object>();

            // --- Add Logging Before Property Loop ---
            // Debug.Log($"[GetComponentData] Starting property loop for {componentType.Name}...");
            // --- End Logging Before Property Loop ---

            // Use cached properties
            foreach (var propInfo in cachedData.SerializableProperties)
            {
                string propName = propInfo.Name;

                // --- Skip known obsolete/problematic Component shortcut properties ---
                bool skipProperty = false;
                if (propName == "rigidbody" || propName == "rigidbody2D" || propName == "camera" ||
                    propName == "light" || propName == "animation" || propName == "constantForce" ||
                    propName == "renderer" || propName == "audio" || propName == "networkView" ||
                    propName == "collider" || propName == "collider2D" || propName == "hingeJoint" ||
                    propName == "particleSystem" ||
                    // Also skip potentially problematic Matrix properties prone to cycles/errors
                    propName == "worldToLocalMatrix" || propName == "localToWorldMatrix")
                {
                    // Debug.Log($"[GetComponentData] Explicitly skipping generic property: {propName}"); // Optional log
                    skipProperty = true;
                }
                // --- End Skip Generic Properties ---

                // --- Skip specific potentially problematic Camera properties ---
                if (componentType == typeof(Camera) &&
                    (propName == "pixelRect" ||
                     propName == "rect" ||
                     propName == "cullingMatrix" ||
                     propName == "useOcclusionCulling" ||
                     propName == "worldToCameraMatrix" ||
                     propName == "projectionMatrix" ||
                     propName == "nonJitteredProjectionMatrix" ||
                     propName == "previousViewProjectionMatrix" ||
                     propName == "cameraToWorldMatrix"))
                {
                    // Debug.Log($"[GetComponentData] Explicitly skipping Camera property: {propName}");
                    skipProperty = true;
                }
                // --- End Skip Camera Properties ---

                // --- Skip specific potentially problematic Transform properties ---
                if (componentType == typeof(Transform) &&
                    (propName == "lossyScale" ||
                     propName == "rotation" ||
                     propName == "worldToLocalMatrix" ||
                     propName == "localToWorldMatrix"))
                {
                    // Debug.Log($"[GetComponentData] Explicitly skipping Transform property: {propName}");
                    skipProperty = true;
                }
                // --- End Skip Transform Properties ---

                // Skip if flagged
                if (skipProperty)
                {
                    continue;
                }

                try
                {
                    // --- Add detailed logging --- 
                    // Debug.Log($"[GetComponentData] Accessing: {componentType.Name}.{propName}");
                    // --- End detailed logging ---
                    
                    // --- Special handling for material/mesh properties in edit mode ---
                    object value;
                    if (!Application.isPlaying && (propName == "material" || propName == "materials" || propName == "mesh"))
                    {
                        // In edit mode, use sharedMaterial/sharedMesh to avoid instantiation warnings
                        if ((propName == "material" || propName == "materials") && c is Renderer renderer)
                        {
                            if (propName == "material")
                                value = renderer.sharedMaterial;
                            else // materials
                                value = renderer.sharedMaterials;
                        }
                        else if (propName == "mesh" && c is MeshFilter meshFilter)
                        {
                            value = meshFilter.sharedMesh;
                        }
                        else
                        {
                            // Fallback to normal property access if type doesn't match
                            value = propInfo.GetValue(c);
                        }
                    }
                    else
                    {
                        value = propInfo.GetValue(c);
                    }
                    // --- End special handling ---
                    
                    Type propType = propInfo.PropertyType;
                    AddSerializableValue(serializablePropertiesOutput, propName, propType, value);
                }
                catch (Exception)
                {
                    // Debug.LogWarning($"Could not read property {propName} on {componentType.Name}");
                }
            }

            // --- Add Logging Before Field Loop ---
            // Debug.Log($"[GetComponentData] Starting field loop for {componentType.Name}...");
            // --- End Logging Before Field Loop ---

            // Use cached fields
            foreach (var fieldInfo in cachedData.SerializableFields)
            {
                try
                {
                    // --- Add detailed logging for fields --- 
                    // Debug.Log($"[GetComponentData] Accessing Field: {componentType.Name}.{fieldInfo.Name}");
                    // --- End detailed logging for fields ---
                    object value = fieldInfo.GetValue(c);
                    string fieldName = fieldInfo.Name;
                    Type fieldType = fieldInfo.FieldType;
                    AddSerializableValue(serializablePropertiesOutput, fieldName, fieldType, value);
                }
                catch (Exception)
                {
                    // Debug.LogWarning($"Could not read field {fieldInfo.Name} on {componentType.Name}");
                }
            }
            // --- End Use cached metadata ---

            if (serializablePropertiesOutput.Count > 0)
            {
                data["properties"] = serializablePropertiesOutput;
            }

            return data;
        }

        // Helper function to decide how to serialize different types
        private static void AddSerializableValue(Dictionary<string, object> dict, string name, Type type, object value)
        {
            // Simplified: Directly use CreateTokenFromValue which uses the serializer
            if (value == null)
            {
                dict[name] = null;
                return;
            }

            try
            {
                // Use the helper that employs our custom serializer settings
                JToken token = CreateTokenFromValue(value, type);
                if (token != null) // Check if serialization succeeded in the helper
                {
                    // Convert JToken back to a basic object structure for the dictionary
                    dict[name] = ConvertJTokenToPlainObject(token);
                }
                // If token is null, it means serialization failed and a warning was logged.
            }
            catch (Exception e)
            {
                // Catch potential errors during JToken conversion or addition to dictionary
                Debug.LogWarning($"[AddSerializableValue] Error processing value for '{name}' (Type: {type.FullName}): {e.Message}. Skipping.");
            }
        }

        // Helper to convert JToken back to basic object structure
        private static object ConvertJTokenToPlainObject(JToken token)
        {
            if (token == null) return null;

            switch (token.Type)
            {
                case JTokenType.Object:
                    var objDict = new Dictionary<string, object>();
                    foreach (var prop in ((JObject)token).Properties())
                    {
                        objDict[prop.Name] = ConvertJTokenToPlainObject(prop.Value);
                    }
                    return objDict;

                case JTokenType.Array:
                    var list = new List<object>();
                    foreach (var item in (JArray)token)
                    {
                        list.Add(ConvertJTokenToPlainObject(item));
                    }
                    return list;

                case JTokenType.Integer:
                    return token.ToObject<long>(); // Use long for safety
                case JTokenType.Float:
                    return token.ToObject<double>(); // Use double for safety
                case JTokenType.String:
                    return token.ToObject<string>();
                case JTokenType.Boolean:
                    return token.ToObject<bool>();
                case JTokenType.Date:
                    return token.ToObject<DateTime>();
                case JTokenType.Guid:
                    return token.ToObject<Guid>();
                case JTokenType.Uri:
                    return token.ToObject<Uri>();
                case JTokenType.TimeSpan:
                    return token.ToObject<TimeSpan>();
                case JTokenType.Bytes:
                    return token.ToObject<byte[]>();
                case JTokenType.Null:
                    return null;
                case JTokenType.Undefined:
                    return null; // Treat undefined as null

                default:
                    // Fallback for simple value types not explicitly listed
                    if (token is JValue jValue && jValue.Value != null)
                    {
                        return jValue.Value;
                    }
                    // Debug.LogWarning($"Unsupported JTokenType encountered: {token.Type}. Returning null.");
                    return null;
            }
        }

        // --- Define custom JsonSerializerSettings for OUTPUT ---
        private static readonly JsonSerializerSettings _outputSerializerSettings = new JsonSerializerSettings
        {
            Converters = new List<JsonConverter>
            {
                new Vector3Converter(),
                new Vector2Converter(),
                new QuaternionConverter(),
                new ColorConverter(),
                new RectConverter(),
                new BoundsConverter(),
                new UnityEngineObjectConverter() // Handles serialization of references
            },
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            // ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } // Example if needed
        };
        private static readonly JsonSerializer _outputSerializer = JsonSerializer.Create(_outputSerializerSettings);
        // --- End Define custom JsonSerializerSettings ---

        // Helper to create JToken using the output serializer
        private static JToken CreateTokenFromValue(object value, Type type)
        {
            if (value == null) return JValue.CreateNull();

            try
            {
                // Use the pre-configured OUTPUT serializer instance
                return JToken.FromObject(value, _outputSerializer);
            }
            catch (JsonSerializationException e)
            {
                Debug.LogWarning($"[GameObjectSerializer] Newtonsoft.Json Error serializing value of type {type.FullName}: {e.Message}. Skipping property/field.");
                return null; // Indicate serialization failure
            }
            catch (Exception e) // Catch other unexpected errors
            {
                Debug.LogWarning($"[GameObjectSerializer] Unexpected error serializing value of type {type.FullName}: {e}. Skipping property/field.");
                return null; // Indicate serialization failure
            }
        }
    }
}

```

--------------------------------------------------------------------------------
/UnityMcpBridge/Editor/Setup/SetupWizardWindow.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.Linq;
using MCPForUnity.Editor.Data;
using MCPForUnity.Editor.Dependencies;
using MCPForUnity.Editor.Dependencies.Models;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using UnityEditor;
using UnityEngine;

namespace MCPForUnity.Editor.Setup
{
    /// <summary>
    /// Setup wizard window for guiding users through dependency installation
    /// </summary>
    public class SetupWizardWindow : EditorWindow
    {
        private DependencyCheckResult _dependencyResult;
        private Vector2 _scrollPosition;
        private int _currentStep = 0;
        private McpClients _mcpClients;
        private int _selectedClientIndex = 0;

        private readonly string[] _stepTitles = {
            "Setup",
            "Configure",
            "Complete"
        };

        public static void ShowWindow(DependencyCheckResult dependencyResult = null)
        {
            var window = GetWindow<SetupWizardWindow>("MCP for Unity Setup");
            window.minSize = new Vector2(500, 400);
            window.maxSize = new Vector2(800, 600);
            window._dependencyResult = dependencyResult ?? DependencyManager.CheckAllDependencies();
            window.Show();
        }

        private void OnEnable()
        {
            if (_dependencyResult == null)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }

            _mcpClients = new McpClients();

            // Check client configurations on startup
            foreach (var client in _mcpClients.clients)
            {
                CheckClientConfiguration(client);
            }
        }

        private void OnGUI()
        {
            DrawHeader();
            DrawProgressBar();

            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);

            switch (_currentStep)
            {
                case 0: DrawSetupStep(); break;
                case 1: DrawConfigureStep(); break;
                case 2: DrawCompleteStep(); break;
            }

            EditorGUILayout.EndScrollView();

            DrawFooter();
        }

        private void DrawHeader()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            GUILayout.Label("MCP for Unity Setup Wizard", EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            GUILayout.Label($"Step {_currentStep + 1} of {_stepTitles.Length}");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();

            // Step title
            var titleStyle = new GUIStyle(EditorStyles.largeLabel)
            {
                fontSize = 16,
                fontStyle = FontStyle.Bold
            };
            EditorGUILayout.LabelField(_stepTitles[_currentStep], titleStyle);
            EditorGUILayout.Space();
        }

        private void DrawProgressBar()
        {
            var rect = EditorGUILayout.GetControlRect(false, 4);
            var progress = (_currentStep + 1) / (float)_stepTitles.Length;
            EditorGUI.ProgressBar(rect, progress, "");
            EditorGUILayout.Space();
        }

        private void DrawSetupStep()
        {
            // Welcome section
            DrawSectionTitle("MCP for Unity Setup");

            EditorGUILayout.LabelField(
                "This wizard will help you set up MCP for Unity to connect AI assistants with your Unity Editor.",
                EditorStyles.wordWrappedLabel
            );
            EditorGUILayout.Space();

            // Dependency check section
            EditorGUILayout.BeginHorizontal();
            DrawSectionTitle("System Check", 14);
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }
            EditorGUILayout.EndHorizontal();

            // Show simplified dependency status
            foreach (var dep in _dependencyResult.Dependencies)
            {
                DrawSimpleDependencyStatus(dep);
            }

            // Overall status and installation guidance
            EditorGUILayout.Space();
            if (!_dependencyResult.IsSystemReady)
            {
                // Only show critical warnings when dependencies are actually missing
                EditorGUILayout.HelpBox(
                    "⚠️ Missing Dependencies: MCP for Unity requires Python 3.10+ and UV package manager to function properly.",
                    MessageType.Warning
                );

                EditorGUILayout.Space();
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                DrawErrorStatus("Installation Required");

                var recommendations = DependencyManager.GetInstallationRecommendations();
                EditorGUILayout.LabelField(recommendations, EditorStyles.wordWrappedLabel);

                EditorGUILayout.Space();
                if (GUILayout.Button("Open Installation Links", GUILayout.Height(25)))
                {
                    OpenInstallationUrls();
                }
                EditorGUILayout.EndVertical();
            }
            else
            {
                DrawSuccessStatus("System Ready");
                EditorGUILayout.LabelField("All requirements are met. You can proceed to configure your AI clients.", EditorStyles.wordWrappedLabel);
            }
        }



        private void DrawCompleteStep()
        {
            DrawSectionTitle("Setup Complete");

            // Refresh dependency check with caching to avoid heavy operations on every repaint
            if (_dependencyResult == null || (DateTime.UtcNow - _dependencyResult.CheckedAt).TotalSeconds > 2)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }

            if (_dependencyResult.IsSystemReady)
            {
                DrawSuccessStatus("MCP for Unity Ready!");

                EditorGUILayout.HelpBox(
                    "🎉 MCP for Unity is now set up and ready to use!\n\n" +
                    "• Dependencies verified\n" +
                    "• MCP server ready\n" +
                    "• Client configuration accessible",
                    MessageType.Info
                );

                EditorGUILayout.Space();
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Documentation", GUILayout.Height(30)))
                {
                    Application.OpenURL("https://github.com/CoplayDev/unity-mcp");
                }
                if (GUILayout.Button("Client Settings", GUILayout.Height(30)))
                {
                    Windows.MCPForUnityEditorWindow.ShowWindow();
                }
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                DrawErrorStatus("Setup Incomplete - Package Non-Functional");

                EditorGUILayout.HelpBox(
                    "🚨 MCP for Unity CANNOT work - dependencies still missing!\n\n" +
                    "Install ALL required dependencies before the package will function.",
                    MessageType.Error
                );

                var missingDeps = _dependencyResult.GetMissingRequired();
                if (missingDeps.Count > 0)
                {
                    EditorGUILayout.Space();
                    EditorGUILayout.LabelField("Still Missing:", EditorStyles.boldLabel);
                    foreach (var dep in missingDeps)
                    {
                        EditorGUILayout.LabelField($"✗ {dep.Name}", EditorStyles.label);
                    }
                }

                EditorGUILayout.Space();
                if (GUILayout.Button("Go Back to Setup", GUILayout.Height(30)))
                {
                    _currentStep = 0;
                }
            }
        }

        // Helper methods for consistent UI components
        private void DrawSectionTitle(string title, int fontSize = 16)
        {
            var titleStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                fontSize = fontSize,
                fontStyle = FontStyle.Bold
            };
            EditorGUILayout.LabelField(title, titleStyle);
            EditorGUILayout.Space();
        }

        private void DrawSuccessStatus(string message)
        {
            var originalColor = GUI.color;
            GUI.color = Color.green;
            EditorGUILayout.LabelField($"✓ {message}", EditorStyles.boldLabel);
            GUI.color = originalColor;
            EditorGUILayout.Space();
        }

        private void DrawErrorStatus(string message)
        {
            var originalColor = GUI.color;
            GUI.color = Color.red;
            EditorGUILayout.LabelField($"✗ {message}", EditorStyles.boldLabel);
            GUI.color = originalColor;
            EditorGUILayout.Space();
        }

        private void DrawSimpleDependencyStatus(DependencyStatus dep)
        {
            EditorGUILayout.BeginHorizontal();

            var statusIcon = dep.IsAvailable ? "✓" : "✗";
            var statusColor = dep.IsAvailable ? Color.green : Color.red;

            var originalColor = GUI.color;
            GUI.color = statusColor;
            GUILayout.Label(statusIcon, GUILayout.Width(20));
            EditorGUILayout.LabelField(dep.Name, EditorStyles.boldLabel);
            GUI.color = originalColor;

            if (!dep.IsAvailable && !string.IsNullOrEmpty(dep.ErrorMessage))
            {
                EditorGUILayout.LabelField($"({dep.ErrorMessage})", EditorStyles.miniLabel);
            }

            EditorGUILayout.EndHorizontal();
        }

        private void DrawConfigureStep()
        {
            DrawSectionTitle("AI Client Configuration");

            // Check dependencies first (with caching to avoid heavy operations on every repaint)
            if (_dependencyResult == null || (DateTime.UtcNow - _dependencyResult.CheckedAt).TotalSeconds > 2)
            {
                _dependencyResult = DependencyManager.CheckAllDependencies();
            }
            if (!_dependencyResult.IsSystemReady)
            {
                DrawErrorStatus("Cannot Configure - System Requirements Not Met");

                EditorGUILayout.HelpBox(
                    "Client configuration requires system dependencies to be installed first. Please complete setup before proceeding.",
                    MessageType.Warning
                );

                if (GUILayout.Button("Go Back to Setup", GUILayout.Height(30)))
                {
                    _currentStep = 0;
                }
                return;
            }

            EditorGUILayout.LabelField(
                "Configure your AI assistants to work with Unity. Select a client below to set it up:",
                EditorStyles.wordWrappedLabel
            );
            EditorGUILayout.Space();

            // Client selection and configuration
            if (_mcpClients.clients.Count > 0)
            {
                // Client selector dropdown
                string[] clientNames = _mcpClients.clients.Select(c => c.name).ToArray();
                EditorGUI.BeginChangeCheck();
                _selectedClientIndex = EditorGUILayout.Popup("Select AI Client:", _selectedClientIndex, clientNames);
                if (EditorGUI.EndChangeCheck())
                {
                    _selectedClientIndex = Mathf.Clamp(_selectedClientIndex, 0, _mcpClients.clients.Count - 1);
                    // Refresh client status when selection changes
                    CheckClientConfiguration(_mcpClients.clients[_selectedClientIndex]);
                }

                EditorGUILayout.Space();

                var selectedClient = _mcpClients.clients[_selectedClientIndex];
                DrawClientConfigurationInWizard(selectedClient);

                EditorGUILayout.Space();

                // Batch configuration option
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                EditorGUILayout.LabelField("Quick Setup", EditorStyles.boldLabel);
                EditorGUILayout.LabelField(
                    "Automatically configure all detected AI clients at once:",
                    EditorStyles.wordWrappedLabel
                );
                EditorGUILayout.Space();

                if (GUILayout.Button("Configure All Detected Clients", GUILayout.Height(30)))
                {
                    ConfigureAllClientsInWizard();
                }
                EditorGUILayout.EndVertical();
            }
            else
            {
                EditorGUILayout.HelpBox("No AI clients detected. Make sure you have Claude Code, Cursor, or VSCode installed.", MessageType.Info);
            }

            EditorGUILayout.Space();
            EditorGUILayout.HelpBox(
                "💡 You might need to restart your AI client after configuring.",
                MessageType.Info
            );
        }

        private void DrawFooter()
        {
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();

            // Back button
            GUI.enabled = _currentStep > 0;
            if (GUILayout.Button("Back", GUILayout.Width(60)))
            {
                _currentStep--;
            }

            GUILayout.FlexibleSpace();

            // Skip button
            if (GUILayout.Button("Skip", GUILayout.Width(60)))
            {
                bool dismiss = EditorUtility.DisplayDialog(
                    "Skip Setup",
                    "⚠️ Skipping setup will leave MCP for Unity non-functional!\n\n" +
                    "You can restart setup from: Window > MCP for Unity > Setup Wizard (Required)",
                    "Skip Anyway",
                    "Cancel"
                );

                if (dismiss)
                {
                    SetupWizard.MarkSetupDismissed();
                    Close();
                }
            }

            // Next/Done button
            GUI.enabled = true;
            string buttonText = _currentStep == _stepTitles.Length - 1 ? "Done" : "Next";

            if (GUILayout.Button(buttonText, GUILayout.Width(80)))
            {
                if (_currentStep == _stepTitles.Length - 1)
                {
                    SetupWizard.MarkSetupCompleted();
                    Close();
                }
                else
                {
                    _currentStep++;
                }
            }

            GUI.enabled = true;
            EditorGUILayout.EndHorizontal();
        }

        private void DrawClientConfigurationInWizard(McpClient client)
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            EditorGUILayout.LabelField($"{client.name} Configuration", EditorStyles.boldLabel);
            EditorGUILayout.Space();

            // Show current status
            var statusColor = GetClientStatusColor(client);
            var originalColor = GUI.color;
            GUI.color = statusColor;
            EditorGUILayout.LabelField($"Status: {client.configStatus}", EditorStyles.label);
            GUI.color = originalColor;

            EditorGUILayout.Space();

            // Configuration buttons
            EditorGUILayout.BeginHorizontal();

            if (client.mcpType == McpTypes.ClaudeCode)
            {
                // Special handling for Claude Code
                bool claudeAvailable = !string.IsNullOrEmpty(ExecPath.ResolveClaude());
                if (claudeAvailable)
                {
                    bool isConfigured = client.status == McpStatus.Configured;
                    string buttonText = isConfigured ? "Unregister" : "Register";
                    if (GUILayout.Button($"{buttonText} with Claude Code"))
                    {
                        if (isConfigured)
                        {
                            UnregisterFromClaudeCode(client);
                        }
                        else
                        {
                            RegisterWithClaudeCode(client);
                        }
                    }
                }
                else
                {
                    EditorGUILayout.HelpBox("Claude Code not found. Please install Claude Code first.", MessageType.Warning);
                    if (GUILayout.Button("Open Claude Code Website"))
                    {
                        Application.OpenURL("https://claude.ai/download");
                    }
                }
            }
            else
            {
                // Standard client configuration
                if (GUILayout.Button($"Configure {client.name}"))
                {
                    ConfigureClientInWizard(client);
                }

                if (GUILayout.Button("Manual Setup"))
                {
                    ShowManualSetupInWizard(client);
                }
            }

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
        }

        private Color GetClientStatusColor(McpClient client)
        {
            return client.status switch
            {
                McpStatus.Configured => Color.green,
                McpStatus.Running => Color.green,
                McpStatus.Connected => Color.green,
                McpStatus.IncorrectPath => Color.yellow,
                McpStatus.CommunicationError => Color.yellow,
                McpStatus.NoResponse => Color.yellow,
                _ => Color.red
            };
        }

        private void ConfigureClientInWizard(McpClient client)
        {
            try
            {
                string result = PerformClientConfiguration(client);

                EditorUtility.DisplayDialog(
                    $"{client.name} Configuration",
                    result,
                    "OK"
                );

                // Refresh client status
                CheckClientConfiguration(client);
                Repaint();
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog(
                    "Configuration Error",
                    $"Failed to configure {client.name}: {ex.Message}",
                    "OK"
                );
            }
        }

        private void ConfigureAllClientsInWizard()
        {
            int successCount = 0;
            int totalCount = _mcpClients.clients.Count;

            foreach (var client in _mcpClients.clients)
            {
                try
                {
                    if (client.mcpType == McpTypes.ClaudeCode)
                    {
                        if (!string.IsNullOrEmpty(ExecPath.ResolveClaude()) && client.status != McpStatus.Configured)
                        {
                            RegisterWithClaudeCode(client);
                            successCount++;
                        }
                        else if (client.status == McpStatus.Configured)
                        {
                            successCount++; // Already configured
                        }
                    }
                    else
                    {
                        string result = PerformClientConfiguration(client);
                        if (result.Contains("success", System.StringComparison.OrdinalIgnoreCase))
                        {
                            successCount++;
                        }
                    }

                    CheckClientConfiguration(client);
                }
                catch (System.Exception ex)
                {
                    McpLog.Error($"Failed to configure {client.name}: {ex.Message}");
                }
            }

            EditorUtility.DisplayDialog(
                "Batch Configuration Complete",
                $"Successfully configured {successCount} out of {totalCount} clients.\n\n" +
                "Restart your AI clients for changes to take effect.",
                "OK"
            );

            Repaint();
        }

        private void RegisterWithClaudeCode(McpClient client)
        {
            try
            {
                string pythonDir = McpPathResolver.FindPackagePythonDirectory();
                string claudePath = ExecPath.ResolveClaude();
                string uvPath = ExecPath.ResolveUv() ?? "uv";

                string args = $"mcp add UnityMCP -- \"{uvPath}\" run --directory \"{pythonDir}\" server.py";

                if (!ExecPath.TryRun(claudePath, args, null, out var stdout, out var stderr, 15000, McpPathResolver.GetPathPrepend()))
                {
                    if ((stdout + stderr).Contains("already exists", System.StringComparison.OrdinalIgnoreCase))
                    {
                        CheckClientConfiguration(client);
                        EditorUtility.DisplayDialog("Claude Code", "MCP for Unity is already registered with Claude Code.", "OK");
                    }
                    else
                    {
                        throw new System.Exception($"Registration failed: {stderr}");
                    }
                }
                else
                {
                    CheckClientConfiguration(client);
                    EditorUtility.DisplayDialog("Claude Code", "Successfully registered MCP for Unity with Claude Code!", "OK");
                }
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog("Registration Error", $"Failed to register with Claude Code: {ex.Message}", "OK");
            }
        }

        private void UnregisterFromClaudeCode(McpClient client)
        {
            try
            {
                string claudePath = ExecPath.ResolveClaude();
                if (ExecPath.TryRun(claudePath, "mcp remove UnityMCP", null, out var stdout, out var stderr, 10000, McpPathResolver.GetPathPrepend()))
                {
                    CheckClientConfiguration(client);
                    EditorUtility.DisplayDialog("Claude Code", "Successfully unregistered MCP for Unity from Claude Code.", "OK");
                }
                else
                {
                    throw new System.Exception($"Unregistration failed: {stderr}");
                }
            }
            catch (System.Exception ex)
            {
                EditorUtility.DisplayDialog("Unregistration Error", $"Failed to unregister from Claude Code: {ex.Message}", "OK");
            }
        }

        private string PerformClientConfiguration(McpClient client)
        {
            // This mirrors the logic from MCPForUnityEditorWindow.ConfigureMcpClient
            string configPath = McpConfigurationHelper.GetClientConfigPath(client);
            string pythonDir = McpPathResolver.FindPackagePythonDirectory();

            if (string.IsNullOrEmpty(pythonDir))
            {
                return "Manual configuration required - Python server directory not found.";
            }

            McpConfigurationHelper.EnsureConfigDirectoryExists(configPath);
            // Use TOML writer for Codex; JSON writer for others
            if (client != null && client.mcpType == McpTypes.Codex)
            {
                return McpConfigurationHelper.ConfigureCodexClient(pythonDir, configPath, client);
            }
            else
            {
                return McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
            }
        }

        private void ShowManualSetupInWizard(McpClient client)
        {
            string configPath = McpConfigurationHelper.GetClientConfigPath(client);
            string pythonDir = McpPathResolver.FindPackagePythonDirectory();
            string uvPath = ServerInstaller.FindUvPath();

            if (string.IsNullOrEmpty(uvPath))
            {
                EditorUtility.DisplayDialog("Manual Setup", "UV package manager not found. Please install UV first.", "OK");
                return;
            }

            // Build manual configuration using the sophisticated helper logic
            string result = (client != null && client.mcpType == McpTypes.Codex)
                ? McpConfigurationHelper.ConfigureCodexClient(pythonDir, configPath, client)
                : McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
            string manualConfig;

            if (result == "Configured successfully")
            {
                // Read back the configuration that was written
                try
                {
                    manualConfig = System.IO.File.ReadAllText(configPath);
                }
                catch
                {
                    manualConfig = "Configuration written successfully, but could not read back for display.";
                }
            }
            else
            {
                manualConfig = $"Configuration failed: {result}";
            }

            EditorUtility.DisplayDialog(
                $"Manual Setup - {client.name}",
                $"Configuration file location:\n{configPath}\n\n" +
                $"Configuration result:\n{manualConfig}",
                "OK"
            );
        }

        private void CheckClientConfiguration(McpClient client)
        {
            // Basic status check - could be enhanced to mirror MCPForUnityEditorWindow logic
            try
            {
                string configPath = McpConfigurationHelper.GetClientConfigPath(client);
                if (System.IO.File.Exists(configPath))
                {
                    client.configStatus = "Configured";
                    client.status = McpStatus.Configured;
                }
                else
                {
                    client.configStatus = "Not Configured";
                    client.status = McpStatus.NotConfigured;
                }
            }
            catch
            {
                client.configStatus = "Error";
                client.status = McpStatus.Error;
            }
        }

        private void OpenInstallationUrls()
        {
            var (pythonUrl, uvUrl) = DependencyManager.GetInstallationUrls();

            bool openPython = EditorUtility.DisplayDialog(
                "Open Installation URLs",
                "Open Python installation page?",
                "Yes",
                "No"
            );

            if (openPython)
            {
                Application.OpenURL(pythonUrl);
            }

            bool openUV = EditorUtility.DisplayDialog(
                "Open Installation URLs",
                "Open UV installation page?",
                "Yes",
                "No"
            );

            if (openUV)
            {
                Application.OpenURL(uvUrl);
            }
        }
    }
}

```

--------------------------------------------------------------------------------
/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace MCPForUnity.Editor.Helpers
{
    public static class ServerInstaller
    {
        private const string RootFolder = "UnityMCP";
        private const string ServerFolder = "UnityMcpServer";
        private const string VersionFileName = "server_version.txt";

        /// <summary>
        /// Ensures the mcp-for-unity-server is installed locally by copying from the embedded package source.
        /// No network calls or Git operations are performed.
        /// </summary>
        public static void EnsureServerInstalled()
        {
            try
            {
                string saveLocation = GetSaveLocation();
                TryCreateMacSymlinkForAppSupport();
                string destRoot = Path.Combine(saveLocation, ServerFolder);
                string destSrc = Path.Combine(destRoot, "src");

                // Detect legacy installs and version state (logs)
                DetectAndLogLegacyInstallStates(destRoot);

                // Resolve embedded source and versions
                if (!TryGetEmbeddedServerSource(out string embeddedSrc))
                {
                    throw new Exception("Could not find embedded UnityMcpServer/src in the package.");
                }
                string embeddedVer = ReadVersionFile(Path.Combine(embeddedSrc, VersionFileName)) ?? "unknown";
                string installedVer = ReadVersionFile(Path.Combine(destSrc, VersionFileName));

                bool destHasServer = File.Exists(Path.Combine(destSrc, "server.py"));
                bool needOverwrite = !destHasServer
                                     || string.IsNullOrEmpty(installedVer)
                                     || (!string.IsNullOrEmpty(embeddedVer) && CompareSemverSafe(installedVer, embeddedVer) < 0);

                // Ensure destination exists
                Directory.CreateDirectory(destRoot);

                if (needOverwrite)
                {
                    // Copy the entire UnityMcpServer folder (parent of src)
                    string embeddedRoot = Path.GetDirectoryName(embeddedSrc) ?? embeddedSrc; // go up from src to UnityMcpServer
                    CopyDirectoryRecursive(embeddedRoot, destRoot);
                    // Write/refresh version file
                    try { File.WriteAllText(Path.Combine(destSrc, VersionFileName), embeddedVer ?? "unknown"); } catch { }
                    McpLog.Info($"Installed/updated server to {destRoot} (version {embeddedVer}).");
                }

                // Cleanup legacy installs that are missing version or older than embedded
                foreach (var legacyRoot in GetLegacyRootsForDetection())
                {
                    try
                    {
                        string legacySrc = Path.Combine(legacyRoot, "src");
                        if (!File.Exists(Path.Combine(legacySrc, "server.py"))) continue;
                        string legacyVer = ReadVersionFile(Path.Combine(legacySrc, VersionFileName));
                        bool legacyOlder = string.IsNullOrEmpty(legacyVer)
                                           || (!string.IsNullOrEmpty(embeddedVer) && CompareSemverSafe(legacyVer, embeddedVer) < 0);
                        if (legacyOlder)
                        {
                            TryKillUvForPath(legacySrc);
                            try
                            {
                                Directory.Delete(legacyRoot, recursive: true);
                                McpLog.Info($"Removed legacy server at '{legacyRoot}'.");
                            }
                            catch (Exception ex)
                            {
                                McpLog.Warn($"Failed to remove legacy server at '{legacyRoot}': {ex.Message}");
                            }
                        }
                    }
                    catch { }
                }

                // Clear overrides that might point at legacy locations
                try
                {
                    EditorPrefs.DeleteKey("MCPForUnity.ServerSrc");
                    EditorPrefs.DeleteKey("MCPForUnity.PythonDirOverride");
                }
                catch { }
                return;
            }
            catch (Exception ex)
            {
                // If a usable server is already present (installed or embedded), don't fail hard—just warn.
                bool hasInstalled = false;
                try { hasInstalled = File.Exists(Path.Combine(GetServerPath(), "server.py")); } catch { }

                if (hasInstalled || TryGetEmbeddedServerSource(out _))
                {
                    McpLog.Warn($"Using existing server; skipped install. Details: {ex.Message}");
                    return;
                }

                McpLog.Error($"Failed to ensure server installation: {ex.Message}");
            }
        }

        public static string GetServerPath()
        {
            return Path.Combine(GetSaveLocation(), ServerFolder, "src");
        }

        /// <summary>
        /// Gets the platform-specific save location for the server.
        /// </summary>
        private static string GetSaveLocation()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                // Use per-user LocalApplicationData for canonical install location
                var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
                                   ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, "AppData", "Local");
                return Path.Combine(localAppData, RootFolder);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                var xdg = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
                if (string.IsNullOrEmpty(xdg))
                {
                    xdg = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty,
                                       ".local", "share");
                }
                return Path.Combine(xdg, RootFolder);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // On macOS, use LocalApplicationData (~/Library/Application Support)
                var localAppSupport = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                // Unity/Mono may map LocalApplicationData to ~/.local/share on macOS; normalize to Application Support
                bool looksLikeXdg = !string.IsNullOrEmpty(localAppSupport) && localAppSupport.Replace('\\', '/').Contains("/.local/share");
                if (string.IsNullOrEmpty(localAppSupport) || looksLikeXdg)
                {
                    // Fallback: construct from $HOME
                    var home = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ?? string.Empty;
                    localAppSupport = Path.Combine(home, "Library", "Application Support");
                }
                TryCreateMacSymlinkForAppSupport();
                return Path.Combine(localAppSupport, RootFolder);
            }
            throw new Exception("Unsupported operating system.");
        }

        /// <summary>
        /// On macOS, create a no-spaces symlink ~/Library/AppSupport -> ~/Library/Application Support
        /// to mitigate arg parsing and quoting issues in some MCP clients.
        /// Safe to call repeatedly.
        /// </summary>
        private static void TryCreateMacSymlinkForAppSupport()
        {
            try
            {
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return;
                string home = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ?? string.Empty;
                if (string.IsNullOrEmpty(home)) return;

                string canonical = Path.Combine(home, "Library", "Application Support");
                string symlink = Path.Combine(home, "Library", "AppSupport");

                // If symlink exists already, nothing to do
                if (Directory.Exists(symlink) || File.Exists(symlink)) return;

                // Create symlink only if canonical exists
                if (!Directory.Exists(canonical)) return;

                // Use 'ln -s' to create a directory symlink (macOS)
                var psi = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = "/bin/ln",
                    Arguments = $"-s \"{canonical}\" \"{symlink}\"",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                };
                using var p = System.Diagnostics.Process.Start(psi);
                p?.WaitForExit(2000);
            }
            catch { /* best-effort */ }
        }

        private static bool IsDirectoryWritable(string path)
        {
            try
            {
                File.Create(Path.Combine(path, "test.txt")).Dispose();
                File.Delete(Path.Combine(path, "test.txt"));
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Checks if the server is installed at the specified location.
        /// </summary>
        private static bool IsServerInstalled(string location)
        {
            return Directory.Exists(location)
                && File.Exists(Path.Combine(location, ServerFolder, "src", "server.py"));
        }

        /// <summary>
        /// Detects legacy installs or older versions and logs findings (no deletion yet).
        /// </summary>
        private static void DetectAndLogLegacyInstallStates(string canonicalRoot)
        {
            try
            {
                string canonicalSrc = Path.Combine(canonicalRoot, "src");
                // Normalize canonical root for comparisons
                string normCanonicalRoot = NormalizePathSafe(canonicalRoot);
                string embeddedSrc = null;
                TryGetEmbeddedServerSource(out embeddedSrc);

                string embeddedVer = ReadVersionFile(Path.Combine(embeddedSrc ?? string.Empty, VersionFileName));
                string installedVer = ReadVersionFile(Path.Combine(canonicalSrc, VersionFileName));

                // Legacy paths (macOS/Linux .config; Windows roaming as example)
                foreach (var legacyRoot in GetLegacyRootsForDetection())
                {
                    // Skip logging for the canonical root itself
                    if (PathsEqualSafe(legacyRoot, normCanonicalRoot))
                        continue;
                    string legacySrc = Path.Combine(legacyRoot, "src");
                    bool hasServer = File.Exists(Path.Combine(legacySrc, "server.py"));
                    string legacyVer = ReadVersionFile(Path.Combine(legacySrc, VersionFileName));

                    if (hasServer)
                    {
                        // Case 1: No version file
                        if (string.IsNullOrEmpty(legacyVer))
                        {
                            McpLog.Info("Detected legacy install without version file at: " + legacyRoot, always: false);
                        }

                        // Case 2: Lives in legacy path
                        McpLog.Info("Detected legacy install path: " + legacyRoot, always: false);

                        // Case 3: Has version but appears older than embedded
                        if (!string.IsNullOrEmpty(embeddedVer) && !string.IsNullOrEmpty(legacyVer) && CompareSemverSafe(legacyVer, embeddedVer) < 0)
                        {
                            McpLog.Info($"Legacy install version {legacyVer} is older than embedded {embeddedVer}", always: false);
                        }
                    }
                }

                // Also log if canonical is missing version (treated as older)
                if (Directory.Exists(canonicalRoot))
                {
                    if (string.IsNullOrEmpty(installedVer))
                    {
                        McpLog.Info("Canonical install missing version file (treat as older). Path: " + canonicalRoot, always: false);
                    }
                    else if (!string.IsNullOrEmpty(embeddedVer) && CompareSemverSafe(installedVer, embeddedVer) < 0)
                    {
                        McpLog.Info($"Canonical install version {installedVer} is older than embedded {embeddedVer}", always: false);
                    }
                }
            }
            catch (Exception ex)
            {
                McpLog.Warn("Detect legacy/version state failed: " + ex.Message);
            }
        }

        private static string NormalizePathSafe(string path)
        {
            try { return string.IsNullOrEmpty(path) ? path : Path.GetFullPath(path.Trim()); }
            catch { return path; }
        }

        private static bool PathsEqualSafe(string a, string b)
        {
            if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) return false;
            string na = NormalizePathSafe(a);
            string nb = NormalizePathSafe(b);
            try
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    return string.Equals(na, nb, StringComparison.OrdinalIgnoreCase);
                }
                return string.Equals(na, nb, StringComparison.Ordinal);
            }
            catch { return false; }
        }

        private static IEnumerable<string> GetLegacyRootsForDetection()
        {
            var roots = new System.Collections.Generic.List<string>();
            string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;
            // macOS/Linux legacy
            roots.Add(Path.Combine(home, ".config", "UnityMCP", "UnityMcpServer"));
            roots.Add(Path.Combine(home, ".local", "share", "UnityMCP", "UnityMcpServer"));
            // Windows roaming example
            try
            {
                string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty;
                if (!string.IsNullOrEmpty(roaming))
                    roots.Add(Path.Combine(roaming, "UnityMCP", "UnityMcpServer"));
                // Windows legacy: early installers/dev scripts used %LOCALAPPDATA%\Programs\UnityMCP\UnityMcpServer
                // Detect this location so we can clean up older copies during install/update.
                string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty;
                if (!string.IsNullOrEmpty(localAppData))
                    roots.Add(Path.Combine(localAppData, "Programs", "UnityMCP", "UnityMcpServer"));
            }
            catch { }
            return roots;
        }

        private static void TryKillUvForPath(string serverSrcPath)
        {
            try
            {
                if (string.IsNullOrEmpty(serverSrcPath)) return;
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;

                var psi = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = "/usr/bin/pgrep",
                    Arguments = $"-f \"uv .*--directory {serverSrcPath}\"",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                };
                using var p = System.Diagnostics.Process.Start(psi);
                if (p == null) return;
                string outp = p.StandardOutput.ReadToEnd();
                p.WaitForExit(1500);
                if (p.ExitCode == 0 && !string.IsNullOrEmpty(outp))
                {
                    foreach (var line in outp.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (int.TryParse(line.Trim(), out int pid))
                        {
                            try { System.Diagnostics.Process.GetProcessById(pid).Kill(); } catch { }
                        }
                    }
                }
            }
            catch { }
        }

        private static string ReadVersionFile(string path)
        {
            try
            {
                if (string.IsNullOrEmpty(path) || !File.Exists(path)) return null;
                string v = File.ReadAllText(path).Trim();
                return string.IsNullOrEmpty(v) ? null : v;
            }
            catch { return null; }
        }

        private static int CompareSemverSafe(string a, string b)
        {
            try
            {
                if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) return 0;
                var ap = a.Split('.');
                var bp = b.Split('.');
                for (int i = 0; i < Math.Max(ap.Length, bp.Length); i++)
                {
                    int ai = (i < ap.Length && int.TryParse(ap[i], out var t1)) ? t1 : 0;
                    int bi = (i < bp.Length && int.TryParse(bp[i], out var t2)) ? t2 : 0;
                    if (ai != bi) return ai.CompareTo(bi);
                }
                return 0;
            }
            catch { return 0; }
        }

        /// <summary>
        /// Attempts to locate the embedded UnityMcpServer/src directory inside the installed package
        /// or common development locations.
        /// </summary>
        private static bool TryGetEmbeddedServerSource(out string srcPath)
        {
            return ServerPathResolver.TryFindEmbeddedServerSource(out srcPath);
        }

        private static readonly string[] _skipDirs = { ".venv", "__pycache__", ".pytest_cache", ".mypy_cache", ".git" };
        private static void CopyDirectoryRecursive(string sourceDir, string destinationDir)
        {
            Directory.CreateDirectory(destinationDir);

            foreach (string filePath in Directory.GetFiles(sourceDir))
            {
                string fileName = Path.GetFileName(filePath);
                string destFile = Path.Combine(destinationDir, fileName);
                File.Copy(filePath, destFile, overwrite: true);
            }

            foreach (string dirPath in Directory.GetDirectories(sourceDir))
            {
                string dirName = Path.GetFileName(dirPath);
                foreach (var skip in _skipDirs)
                {
                    if (dirName.Equals(skip, StringComparison.OrdinalIgnoreCase))
                        goto NextDir;
                }
                try { if ((File.GetAttributes(dirPath) & FileAttributes.ReparsePoint) != 0) continue; } catch { }
                string destSubDir = Path.Combine(destinationDir, dirName);
                CopyDirectoryRecursive(dirPath, destSubDir);
            NextDir:;
            }
        }

        public static bool RebuildMcpServer()
        {
            try
            {
                // Find embedded source
                if (!TryGetEmbeddedServerSource(out string embeddedSrc))
                {
                    Debug.LogError("RebuildMcpServer: Could not find embedded server source.");
                    return false;
                }

                string saveLocation = GetSaveLocation();
                string destRoot = Path.Combine(saveLocation, ServerFolder);
                string destSrc = Path.Combine(destRoot, "src");

                // Kill any running uv processes for this server
                TryKillUvForPath(destSrc);

                // Delete the entire installed server directory
                if (Directory.Exists(destRoot))
                {
                    try
                    {
                        Directory.Delete(destRoot, recursive: true);
                        Debug.Log($"<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Deleted existing server at {destRoot}");
                    }
                    catch (Exception ex)
                    {
                        Debug.LogError($"Failed to delete existing server: {ex.Message}");
                        return false;
                    }
                }

                // Re-copy from embedded source
                string embeddedRoot = Path.GetDirectoryName(embeddedSrc) ?? embeddedSrc;
                Directory.CreateDirectory(destRoot);
                CopyDirectoryRecursive(embeddedRoot, destRoot);

                // Write version file
                string embeddedVer = ReadVersionFile(Path.Combine(embeddedSrc, VersionFileName)) ?? "unknown";
                try
                {
                    File.WriteAllText(Path.Combine(destSrc, VersionFileName), embeddedVer);
                }
                catch (Exception ex)
                {
                    Debug.LogWarning($"Failed to write version file: {ex.Message}");
                }

                Debug.Log($"<b><color=#2EA3FF>MCP-FOR-UNITY</color></b>: Server rebuilt successfully at {destRoot} (version {embeddedVer})");
                return true;
            }
            catch (Exception ex)
            {
                Debug.LogError($"RebuildMcpServer failed: {ex.Message}");
                return false;
            }
        }

        internal static string FindUvPath()
        {
            // Allow user override via EditorPrefs
            try
            {
                string overridePath = EditorPrefs.GetString("MCPForUnity.UvPath", string.Empty);
                if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath))
                {
                    if (ValidateUvBinary(overridePath)) return overridePath;
                }
            }
            catch { }

            string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;

            // Platform-specific candidate lists
            string[] candidates;
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty;
                string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty;
                string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty;

                // Fast path: resolve from PATH first
                try
                {
                    var wherePsi = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "where",
                        Arguments = "uv.exe",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    };
                    using var wp = System.Diagnostics.Process.Start(wherePsi);
                    string output = wp.StandardOutput.ReadToEnd().Trim();
                    wp.WaitForExit(1500);
                    if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output))
                    {
                        foreach (var line in output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            string path = line.Trim();
                            if (File.Exists(path) && ValidateUvBinary(path)) return path;
                        }
                    }
                }
                catch { }

                // Windows Store (PythonSoftwareFoundation) install location probe
                // Example: %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.13_*\LocalCache\local-packages\Python313\Scripts\uv.exe
                try
                {
                    string pkgsRoot = Path.Combine(localAppData, "Packages");
                    if (Directory.Exists(pkgsRoot))
                    {
                        var pythonPkgs = Directory.GetDirectories(pkgsRoot, "PythonSoftwareFoundation.Python.*", SearchOption.TopDirectoryOnly)
                                                 .OrderByDescending(p => p, StringComparer.OrdinalIgnoreCase);
                        foreach (var pkg in pythonPkgs)
                        {
                            string localCache = Path.Combine(pkg, "LocalCache", "local-packages");
                            if (!Directory.Exists(localCache)) continue;
                            var pyRoots = Directory.GetDirectories(localCache, "Python*", SearchOption.TopDirectoryOnly)
                                                   .OrderByDescending(d => d, StringComparer.OrdinalIgnoreCase);
                            foreach (var pyRoot in pyRoots)
                            {
                                string uvExe = Path.Combine(pyRoot, "Scripts", "uv.exe");
                                if (File.Exists(uvExe) && ValidateUvBinary(uvExe)) return uvExe;
                            }
                        }
                    }
                }
                catch { }

                candidates = new[]
                {
                    // Preferred: WinGet Links shims (stable entrypoints)
                    // Per-user shim (LOCALAPPDATA) → machine-wide shim (Program Files\WinGet\Links)
                    Path.Combine(localAppData, "Microsoft", "WinGet", "Links", "uv.exe"),
                    Path.Combine(programFiles, "WinGet", "Links", "uv.exe"),

                    // Common per-user installs
                    Path.Combine(localAppData, @"Programs\Python\Python313\Scripts\uv.exe"),
                    Path.Combine(localAppData, @"Programs\Python\Python312\Scripts\uv.exe"),
                    Path.Combine(localAppData, @"Programs\Python\Python311\Scripts\uv.exe"),
                    Path.Combine(localAppData, @"Programs\Python\Python310\Scripts\uv.exe"),
                    Path.Combine(appData, @"Python\Python313\Scripts\uv.exe"),
                    Path.Combine(appData, @"Python\Python312\Scripts\uv.exe"),
                    Path.Combine(appData, @"Python\Python311\Scripts\uv.exe"),
                    Path.Combine(appData, @"Python\Python310\Scripts\uv.exe"),

                    // Program Files style installs (if a native installer was used)
                    Path.Combine(programFiles, @"uv\uv.exe"),

                    // Try simple name resolution later via PATH
                    "uv.exe",
                    "uv"
                };
            }
            else
            {
                candidates = new[]
                {
                    "/opt/homebrew/bin/uv",
                    "/usr/local/bin/uv",
                    "/usr/bin/uv",
                    "/opt/local/bin/uv",
                    Path.Combine(home, ".local", "bin", "uv"),
                    "/opt/homebrew/opt/uv/bin/uv",
                    // Framework Python installs
                    "/Library/Frameworks/Python.framework/Versions/3.13/bin/uv",
                    "/Library/Frameworks/Python.framework/Versions/3.12/bin/uv",
                    // Fallback to PATH resolution by name
                    "uv"
                };
            }

            foreach (string c in candidates)
            {
                try
                {
                    if (File.Exists(c) && ValidateUvBinary(c)) return c;
                }
                catch { /* ignore */ }
            }

            // Use platform-appropriate which/where to resolve from PATH (non-Windows handled here; Windows tried earlier)
            try
            {
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var whichPsi = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "/usr/bin/which",
                        Arguments = "uv",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    };
                    try
                    {
                        // Prepend common user-local and package manager locations so 'which' can see them in Unity's GUI env
                        string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;
                        string prepend = string.Join(":", new[]
                        {
                            System.IO.Path.Combine(homeDir, ".local", "bin"),
                            "/opt/homebrew/bin",
                            "/usr/local/bin",
                            "/usr/bin",
                            "/bin"
                        });
                        string currentPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
                        whichPsi.EnvironmentVariables["PATH"] = string.IsNullOrEmpty(currentPath) ? prepend : (prepend + ":" + currentPath);
                    }
                    catch { }
                    using var wp = System.Diagnostics.Process.Start(whichPsi);
                    string output = wp.StandardOutput.ReadToEnd().Trim();
                    wp.WaitForExit(3000);
                    if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output))
                    {
                        if (ValidateUvBinary(output)) return output;
                    }
                }
            }
            catch { }

            // Manual PATH scan
            try
            {
                string pathEnv = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
                string[] parts = pathEnv.Split(Path.PathSeparator);
                foreach (string part in parts)
                {
                    try
                    {
                        // Check both uv and uv.exe
                        string candidateUv = Path.Combine(part, "uv");
                        string candidateUvExe = Path.Combine(part, "uv.exe");
                        if (File.Exists(candidateUv) && ValidateUvBinary(candidateUv)) return candidateUv;
                        if (File.Exists(candidateUvExe) && ValidateUvBinary(candidateUvExe)) return candidateUvExe;
                    }
                    catch { }
                }
            }
            catch { }

            return null;
        }

        private static bool ValidateUvBinary(string uvPath)
        {
            try
            {
                var psi = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = uvPath,
                    Arguments = "--version",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                };
                using var p = System.Diagnostics.Process.Start(psi);
                if (!p.WaitForExit(5000)) { try { p.Kill(); } catch { } return false; }
                if (p.ExitCode == 0)
                {
                    string output = p.StandardOutput.ReadToEnd().Trim();
                    return output.StartsWith("uv ");
                }
            }
            catch { }
            return false;
        }
    }
}

```

--------------------------------------------------------------------------------
/TestProjects/UnityMCPTests/Assets/Scripts/LongUnityScriptClaudeTest.cs:
--------------------------------------------------------------------------------

```csharp
using UnityEngine;
using System.Collections.Generic;

// Standalone, dependency-free long script for Claude NL/T editing tests.
// Intentionally verbose to simulate a complex gameplay script without external packages.
public class LongUnityScriptClaudeTest : MonoBehaviour
{
    [Header("Core References")]
    public Transform reachOrigin;
    public Animator animator;

    [Header("State")]
    private Transform currentTarget;
    private Transform previousTarget;
    private float lastTargetFoundTime;

    [Header("Held Objects")]
    private readonly List<Transform> heldObjects = new List<Transform>();

    // Accumulators used by padding methods to avoid complete no-ops
    private int padAccumulator = 0;
    private Vector3 padVector = Vector3.zero;


    [Header("Tuning")]
    public float maxReachDistance = 2f;
    public float maxHorizontalDistance = 1.0f;
    public float maxVerticalDistance = 1.0f;

    // Public accessors used by NL tests
    public bool HasTarget() { return currentTarget != null; }
    public Transform GetCurrentTarget() => currentTarget;

    // Simple selection logic (self-contained)
    private Transform FindBestTarget()
    {
        if (reachOrigin == null) return null;
        // Dummy: prefer previously seen target within distance
        if (currentTarget != null && Vector3.Distance(reachOrigin.position, currentTarget.position) <= maxReachDistance)
            return currentTarget;
        return null;
    }

    private void HandleTargetSwitch(Transform next)
    {
        if (next == currentTarget) return;
        previousTarget = currentTarget;
        currentTarget = next;
        lastTargetFoundTime = Time.time;
    }

    private void LateUpdate()
    {
        // Keep file long with harmless per-frame work
        if (currentTarget == null && previousTarget != null)
        {
            // decay previous reference over time
            if (Time.time - lastTargetFoundTime > 0.5f) previousTarget = null;
        }
    }

    // NL tests sometimes add comments above Update() as an anchor
    private void Update()
    {
        if (reachOrigin == null) return;
        var best = FindBestTarget();
        if (best != null) HandleTargetSwitch(best);
    }


    // Dummy reach/hold API (no external deps)
    public void OnObjectHeld(Transform t)
    {
        if (t == null) return;
        if (!heldObjects.Contains(t)) heldObjects.Add(t);
        animator?.SetInteger("objectsHeld", heldObjects.Count);
    }

    public void OnObjectPlaced()
    {
        if (heldObjects.Count == 0) return;
        heldObjects.RemoveAt(heldObjects.Count - 1);
        animator?.SetInteger("objectsHeld", heldObjects.Count);
    }

    // More padding: repetitive blocks with slight variations
    #region Padding Blocks
    private Vector3 AccumulateBlend(Transform t)
    {
        if (t == null || reachOrigin == null) return Vector3.zero;
        Vector3 local = reachOrigin.InverseTransformPoint(t.position);
        float bx = Mathf.Clamp(local.x / Mathf.Max(0.001f, maxHorizontalDistance), -1f, 1f);
        float by = Mathf.Clamp(local.y / Mathf.Max(0.001f, maxVerticalDistance), -1f, 1f);
        return new Vector3(bx, by, 0f);
    }

    private void ApplyBlend(Vector3 blend)
    {
        if (animator == null) return;
        animator.SetFloat("reachX", blend.x);
        animator.SetFloat("reachY", blend.y);
    }

    public void TickBlendOnce()
    {
        var b = AccumulateBlend(currentTarget);
        ApplyBlend(b);
    }

    // A long series of small no-op methods to bulk up the file without adding deps
    private void Step001() { }
    private void Step002() { }
    private void Step003() { }
    private void Step004() { }
    private void Step005() { }
    private void Step006() { }
    private void Step007() { }
    private void Step008() { }
    private void Step009() { }
    private void Step010() { }
    private void Step011() { }
    private void Step012() { }
    private void Step013() { }
    private void Step014() { }
    private void Step015() { }
    private void Step016() { }
    private void Step017() { }
    private void Step018() { }
    private void Step019() { }
    private void Step020() { }
    private void Step021() { }
    private void Step022() { }
    private void Step023() { }
    private void Step024() { }
    private void Step025() { }
    private void Step026() { }
    private void Step027() { }
    private void Step028() { }
    private void Step029() { }
    private void Step030() { }
    private void Step031() { }
    private void Step032() { }
    private void Step033() { }
    private void Step034() { }
    private void Step035() { }
    private void Step036() { }
    private void Step037() { }
    private void Step038() { }
    private void Step039() { }
    private void Step040() { }
    private void Step041() { }
    private void Step042() { }
    private void Step043() { }
    private void Step044() { }
    private void Step045() { }
    private void Step046() { }
    private void Step047() { }
    private void Step048() { }
    private void Step049() { }
    private void Step050() { }
    #endregion
    #region MassivePadding
    private void Pad0051()
    {
    }
    private void Pad0052()
    {
    }
    private void Pad0053()
    {
    }
    private void Pad0054()
    {
    }
    private void Pad0055()
    {
    }
    private void Pad0056()
    {
    }
    private void Pad0057()
    {
    }
    private void Pad0058()
    {
    }
    private void Pad0059()
    {
    }
    private void Pad0060()
    {
    }
    private void Pad0061()
    {
    }
    private void Pad0062()
    {
    }
    private void Pad0063()
    {
    }
    private void Pad0064()
    {
    }
    private void Pad0065()
    {
    }
    private void Pad0066()
    {
    }
    private void Pad0067()
    {
    }
    private void Pad0068()
    {
    }
    private void Pad0069()
    {
    }
    private void Pad0070()
    {
    }
    private void Pad0071()
    {
    }
    private void Pad0072()
    {
    }
    private void Pad0073()
    {
    }
    private void Pad0074()
    {
    }
    private void Pad0075()
    {
    }
    private void Pad0076()
    {
    }
    private void Pad0077()
    {
    }
    private void Pad0078()
    {
    }
    private void Pad0079()
    {
    }
    private void Pad0080()
    {
    }
    private void Pad0081()
    {
    }
    private void Pad0082()
    {
    }
    private void Pad0083()
    {
    }
    private void Pad0084()
    {
    }
    private void Pad0085()
    {
    }
    private void Pad0086()
    {
    }
    private void Pad0087()
    {
    }
    private void Pad0088()
    {
    }
    private void Pad0089()
    {
    }
    private void Pad0090()
    {
    }
    private void Pad0091()
    {
    }
    private void Pad0092()
    {
    }
    private void Pad0093()
    {
    }
    private void Pad0094()
    {
    }
    private void Pad0095()
    {
    }
    private void Pad0096()
    {
    }
    private void Pad0097()
    {
    }
    private void Pad0098()
    {
    }
    private void Pad0099()
    {
    }
    private void Pad0100()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 100) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0101()
    {
    }
    private void Pad0102()
    {
    }
    private void Pad0103()
    {
    }
    private void Pad0104()
    {
    }
    private void Pad0105()
    {
    }
    private void Pad0106()
    {
    }
    private void Pad0107()
    {
    }
    private void Pad0108()
    {
    }
    private void Pad0109()
    {
    }
    private void Pad0110()
    {
    }
    private void Pad0111()
    {
    }
    private void Pad0112()
    {
    }
    private void Pad0113()
    {
    }
    private void Pad0114()
    {
    }
    private void Pad0115()
    {
    }
    private void Pad0116()
    {
    }
    private void Pad0117()
    {
    }
    private void Pad0118()
    {
    }
    private void Pad0119()
    {
    }
    private void Pad0120()
    {
    }
    private void Pad0121()
    {
    }
    private void Pad0122()
    {
    }
    private void Pad0123()
    {
    }
    private void Pad0124()
    {
    }
    private void Pad0125()
    {
    }
    private void Pad0126()
    {
    }
    private void Pad0127()
    {
    }
    private void Pad0128()
    {
    }
    private void Pad0129()
    {
    }
    private void Pad0130()
    {
    }
    private void Pad0131()
    {
    }
    private void Pad0132()
    {
    }
    private void Pad0133()
    {
    }
    private void Pad0134()
    {
    }
    private void Pad0135()
    {
    }
    private void Pad0136()
    {
    }
    private void Pad0137()
    {
    }
    private void Pad0138()
    {
    }
    private void Pad0139()
    {
    }
    private void Pad0140()
    {
    }
    private void Pad0141()
    {
    }
    private void Pad0142()
    {
    }
    private void Pad0143()
    {
    }
    private void Pad0144()
    {
    }
    private void Pad0145()
    {
    }
    private void Pad0146()
    {
    }
    private void Pad0147()
    {
    }
    private void Pad0148()
    {
    }
    private void Pad0149()
    {
    }
    private void Pad0150()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 150) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0151()
    {
    }
    private void Pad0152()
    {
    }
    private void Pad0153()
    {
    }
    private void Pad0154()
    {
    }
    private void Pad0155()
    {
    }
    private void Pad0156()
    {
    }
    private void Pad0157()
    {
    }
    private void Pad0158()
    {
    }
    private void Pad0159()
    {
    }
    private void Pad0160()
    {
    }
    private void Pad0161()
    {
    }
    private void Pad0162()
    {
    }
    private void Pad0163()
    {
    }
    private void Pad0164()
    {
    }
    private void Pad0165()
    {
    }
    private void Pad0166()
    {
    }
    private void Pad0167()
    {
    }
    private void Pad0168()
    {
    }
    private void Pad0169()
    {
    }
    private void Pad0170()
    {
    }
    private void Pad0171()
    {
    }
    private void Pad0172()
    {
    }
    private void Pad0173()
    {
    }
    private void Pad0174()
    {
    }
    private void Pad0175()
    {
    }
    private void Pad0176()
    {
    }
    private void Pad0177()
    {
    }
    private void Pad0178()
    {
    }
    private void Pad0179()
    {
    }
    private void Pad0180()
    {
    }
    private void Pad0181()
    {
    }
    private void Pad0182()
    {
    }
    private void Pad0183()
    {
    }
    private void Pad0184()
    {
    }
    private void Pad0185()
    {
    }
    private void Pad0186()
    {
    }
    private void Pad0187()
    {
    }
    private void Pad0188()
    {
    }
    private void Pad0189()
    {
    }
    private void Pad0190()
    {
    }
    private void Pad0191()
    {
    }
    private void Pad0192()
    {
    }
    private void Pad0193()
    {
    }
    private void Pad0194()
    {
    }
    private void Pad0195()
    {
    }
    private void Pad0196()
    {
    }
    private void Pad0197()
    {
    }
    private void Pad0198()
    {
    }
    private void Pad0199()
    {
    }
    private void Pad0200()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 200) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0201()
    {
    }
    private void Pad0202()
    {
    }
    private void Pad0203()
    {
    }
    private void Pad0204()
    {
    }
    private void Pad0205()
    {
    }
    private void Pad0206()
    {
    }
    private void Pad0207()
    {
    }
    private void Pad0208()
    {
    }
    private void Pad0209()
    {
    }
    private void Pad0210()
    {
    }
    private void Pad0211()
    {
    }
    private void Pad0212()
    {
    }
    private void Pad0213()
    {
    }
    private void Pad0214()
    {
    }
    private void Pad0215()
    {
    }
    private void Pad0216()
    {
    }
    private void Pad0217()
    {
    }
    private void Pad0218()
    {
    }
    private void Pad0219()
    {
    }
    private void Pad0220()
    {
    }
    private void Pad0221()
    {
    }
    private void Pad0222()
    {
    }
    private void Pad0223()
    {
    }
    private void Pad0224()
    {
    }
    private void Pad0225()
    {
    }
    private void Pad0226()
    {
    }
    private void Pad0227()
    {
    }
    private void Pad0228()
    {
    }
    private void Pad0229()
    {
    }
    private void Pad0230()
    {
    }
    private void Pad0231()
    {
    }
    private void Pad0232()
    {
    }
    private void Pad0233()
    {
    }
    private void Pad0234()
    {
    }
    private void Pad0235()
    {
    }
    private void Pad0236()
    {
    }
    private void Pad0237()
    {
    }
    private void Pad0238()
    {
    }
    private void Pad0239()
    {
    }
    private void Pad0240()
    {
    }
    private void Pad0241()
    {
    }
    private void Pad0242()
    {
    }
    private void Pad0243()
    {
    }
    private void Pad0244()
    {
    }
    private void Pad0245()
    {
    }
    private void Pad0246()
    {
    }
    private void Pad0247()
    {
    }
    private void Pad0248()
    {
    }
    private void Pad0249()
    {
    }
    private void Pad0250()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 250) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0251()
    {
    }
    private void Pad0252()
    {
    }
    private void Pad0253()
    {
    }
    private void Pad0254()
    {
    }
    private void Pad0255()
    {
    }
    private void Pad0256()
    {
    }
    private void Pad0257()
    {
    }
    private void Pad0258()
    {
    }
    private void Pad0259()
    {
    }
    private void Pad0260()
    {
    }
    private void Pad0261()
    {
    }
    private void Pad0262()
    {
    }
    private void Pad0263()
    {
    }
    private void Pad0264()
    {
    }
    private void Pad0265()
    {
    }
    private void Pad0266()
    {
    }
    private void Pad0267()
    {
    }
    private void Pad0268()
    {
    }
    private void Pad0269()
    {
    }
    private void Pad0270()
    {
    }
    private void Pad0271()
    {
    }
    private void Pad0272()
    {
    }
    private void Pad0273()
    {
    }
    private void Pad0274()
    {
    }
    private void Pad0275()
    {
    }
    private void Pad0276()
    {
    }
    private void Pad0277()
    {
    }
    private void Pad0278()
    {
    }
    private void Pad0279()
    {
    }
    private void Pad0280()
    {
    }
    private void Pad0281()
    {
    }
    private void Pad0282()
    {
    }
    private void Pad0283()
    {
    }
    private void Pad0284()
    {
    }
    private void Pad0285()
    {
    }
    private void Pad0286()
    {
    }
    private void Pad0287()
    {
    }
    private void Pad0288()
    {
    }
    private void Pad0289()
    {
    }
    private void Pad0290()
    {
    }
    private void Pad0291()
    {
    }
    private void Pad0292()
    {
    }
    private void Pad0293()
    {
    }
    private void Pad0294()
    {
    }
    private void Pad0295()
    {
    }
    private void Pad0296()
    {
    }
    private void Pad0297()
    {
    }
    private void Pad0298()
    {
    }
    private void Pad0299()
    {
    }
    private void Pad0300()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 300) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0301()
    {
    }
    private void Pad0302()
    {
    }
    private void Pad0303()
    {
    }
    private void Pad0304()
    {
    }
    private void Pad0305()
    {
    }
    private void Pad0306()
    {
    }
    private void Pad0307()
    {
    }
    private void Pad0308()
    {
    }
    private void Pad0309()
    {
    }
    private void Pad0310()
    {
    }
    private void Pad0311()
    {
    }
    private void Pad0312()
    {
    }
    private void Pad0313()
    {
    }
    private void Pad0314()
    {
    }
    private void Pad0315()
    {
    }
    private void Pad0316()
    {
    }
    private void Pad0317()
    {
    }
    private void Pad0318()
    {
    }
    private void Pad0319()
    {
    }
    private void Pad0320()
    {
    }
    private void Pad0321()
    {
    }
    private void Pad0322()
    {
    }
    private void Pad0323()
    {
    }
    private void Pad0324()
    {
    }
    private void Pad0325()
    {
    }
    private void Pad0326()
    {
    }
    private void Pad0327()
    {
    }
    private void Pad0328()
    {
    }
    private void Pad0329()
    {
    }
    private void Pad0330()
    {
    }
    private void Pad0331()
    {
    }
    private void Pad0332()
    {
    }
    private void Pad0333()
    {
    }
    private void Pad0334()
    {
    }
    private void Pad0335()
    {
    }
    private void Pad0336()
    {
    }
    private void Pad0337()
    {
    }
    private void Pad0338()
    {
    }
    private void Pad0339()
    {
    }
    private void Pad0340()
    {
    }
    private void Pad0341()
    {
    }
    private void Pad0342()
    {
    }
    private void Pad0343()
    {
    }
    private void Pad0344()
    {
    }
    private void Pad0345()
    {
    }
    private void Pad0346()
    {
    }
    private void Pad0347()
    {
    }
    private void Pad0348()
    {
    }
    private void Pad0349()
    {
    }
    private void Pad0350()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 350) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0351()
    {
    }
    private void Pad0352()
    {
    }
    private void Pad0353()
    {
    }
    private void Pad0354()
    {
    }
    private void Pad0355()
    {
    }
    private void Pad0356()
    {
    }
    private void Pad0357()
    {
    }
    private void Pad0358()
    {
    }
    private void Pad0359()
    {
    }
    private void Pad0360()
    {
    }
    private void Pad0361()
    {
    }
    private void Pad0362()
    {
    }
    private void Pad0363()
    {
    }
    private void Pad0364()
    {
    }
    private void Pad0365()
    {
    }
    private void Pad0366()
    {
    }
    private void Pad0367()
    {
    }
    private void Pad0368()
    {
    }
    private void Pad0369()
    {
    }
    private void Pad0370()
    {
    }
    private void Pad0371()
    {
    }
    private void Pad0372()
    {
    }
    private void Pad0373()
    {
    }
    private void Pad0374()
    {
    }
    private void Pad0375()
    {
    }
    private void Pad0376()
    {
    }
    private void Pad0377()
    {
    }
    private void Pad0378()
    {
    }
    private void Pad0379()
    {
    }
    private void Pad0380()
    {
    }
    private void Pad0381()
    {
    }
    private void Pad0382()
    {
    }
    private void Pad0383()
    {
    }
    private void Pad0384()
    {
    }
    private void Pad0385()
    {
    }
    private void Pad0386()
    {
    }
    private void Pad0387()
    {
    }
    private void Pad0388()
    {
    }
    private void Pad0389()
    {
    }
    private void Pad0390()
    {
    }
    private void Pad0391()
    {
    }
    private void Pad0392()
    {
    }
    private void Pad0393()
    {
    }
    private void Pad0394()
    {
    }
    private void Pad0395()
    {
    }
    private void Pad0396()
    {
    }
    private void Pad0397()
    {
    }
    private void Pad0398()
    {
    }
    private void Pad0399()
    {
    }
    private void Pad0400()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 400) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0401()
    {
    }
    private void Pad0402()
    {
    }
    private void Pad0403()
    {
    }
    private void Pad0404()
    {
    }
    private void Pad0405()
    {
    }
    private void Pad0406()
    {
    }
    private void Pad0407()
    {
    }
    private void Pad0408()
    {
    }
    private void Pad0409()
    {
    }
    private void Pad0410()
    {
    }
    private void Pad0411()
    {
    }
    private void Pad0412()
    {
    }
    private void Pad0413()
    {
    }
    private void Pad0414()
    {
    }
    private void Pad0415()
    {
    }
    private void Pad0416()
    {
    }
    private void Pad0417()
    {
    }
    private void Pad0418()
    {
    }
    private void Pad0419()
    {
    }
    private void Pad0420()
    {
    }
    private void Pad0421()
    {
    }
    private void Pad0422()
    {
    }
    private void Pad0423()
    {
    }
    private void Pad0424()
    {
    }
    private void Pad0425()
    {
    }
    private void Pad0426()
    {
    }
    private void Pad0427()
    {
    }
    private void Pad0428()
    {
    }
    private void Pad0429()
    {
    }
    private void Pad0430()
    {
    }
    private void Pad0431()
    {
    }
    private void Pad0432()
    {
    }
    private void Pad0433()
    {
    }
    private void Pad0434()
    {
    }
    private void Pad0435()
    {
    }
    private void Pad0436()
    {
    }
    private void Pad0437()
    {
    }
    private void Pad0438()
    {
    }
    private void Pad0439()
    {
    }
    private void Pad0440()
    {
    }
    private void Pad0441()
    {
    }
    private void Pad0442()
    {
    }
    private void Pad0443()
    {
    }
    private void Pad0444()
    {
    }
    private void Pad0445()
    {
    }
    private void Pad0446()
    {
    }
    private void Pad0447()
    {
    }
    private void Pad0448()
    {
    }
    private void Pad0449()
    {
    }
    private void Pad0450()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 450) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0451()
    {
    }
    private void Pad0452()
    {
    }
    private void Pad0453()
    {
    }
    private void Pad0454()
    {
    }
    private void Pad0455()
    {
    }
    private void Pad0456()
    {
    }
    private void Pad0457()
    {
    }
    private void Pad0458()
    {
    }
    private void Pad0459()
    {
    }
    private void Pad0460()
    {
    }
    private void Pad0461()
    {
    }
    private void Pad0462()
    {
    }
    private void Pad0463()
    {
    }
    private void Pad0464()
    {
    }
    private void Pad0465()
    {
    }
    private void Pad0466()
    {
    }
    private void Pad0467()
    {
    }
    private void Pad0468()
    {
    }
    private void Pad0469()
    {
    }
    private void Pad0470()
    {
    }
    private void Pad0471()
    {
    }
    private void Pad0472()
    {
    }
    private void Pad0473()
    {
    }
    private void Pad0474()
    {
    }
    private void Pad0475()
    {
    }
    private void Pad0476()
    {
    }
    private void Pad0477()
    {
    }
    private void Pad0478()
    {
    }
    private void Pad0479()
    {
    }
    private void Pad0480()
    {
    }
    private void Pad0481()
    {
    }
    private void Pad0482()
    {
    }
    private void Pad0483()
    {
    }
    private void Pad0484()
    {
    }
    private void Pad0485()
    {
    }
    private void Pad0486()
    {
    }
    private void Pad0487()
    {
    }
    private void Pad0488()
    {
    }
    private void Pad0489()
    {
    }
    private void Pad0490()
    {
    }
    private void Pad0491()
    {
    }
    private void Pad0492()
    {
    }
    private void Pad0493()
    {
    }
    private void Pad0494()
    {
    }
    private void Pad0495()
    {
    }
    private void Pad0496()
    {
    }
    private void Pad0497()
    {
    }
    private void Pad0498()
    {
    }
    private void Pad0499()
    {
    }
    private void Pad0500()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 500) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0501()
    {
    }
    private void Pad0502()
    {
    }
    private void Pad0503()
    {
    }
    private void Pad0504()
    {
    }
    private void Pad0505()
    {
    }
    private void Pad0506()
    {
    }
    private void Pad0507()
    {
    }
    private void Pad0508()
    {
    }
    private void Pad0509()
    {
    }
    private void Pad0510()
    {
    }
    private void Pad0511()
    {
    }
    private void Pad0512()
    {
    }
    private void Pad0513()
    {
    }
    private void Pad0514()
    {
    }
    private void Pad0515()
    {
    }
    private void Pad0516()
    {
    }
    private void Pad0517()
    {
    }
    private void Pad0518()
    {
    }
    private void Pad0519()
    {
    }
    private void Pad0520()
    {
    }
    private void Pad0521()
    {
    }
    private void Pad0522()
    {
    }
    private void Pad0523()
    {
    }
    private void Pad0524()
    {
    }
    private void Pad0525()
    {
    }
    private void Pad0526()
    {
    }
    private void Pad0527()
    {
    }
    private void Pad0528()
    {
    }
    private void Pad0529()
    {
    }
    private void Pad0530()
    {
    }
    private void Pad0531()
    {
    }
    private void Pad0532()
    {
    }
    private void Pad0533()
    {
    }
    private void Pad0534()
    {
    }
    private void Pad0535()
    {
    }
    private void Pad0536()
    {
    }
    private void Pad0537()
    {
    }
    private void Pad0538()
    {
    }
    private void Pad0539()
    {
    }
    private void Pad0540()
    {
    }
    private void Pad0541()
    {
    }
    private void Pad0542()
    {
    }
    private void Pad0543()
    {
    }
    private void Pad0544()
    {
    }
    private void Pad0545()
    {
    }
    private void Pad0546()
    {
    }
    private void Pad0547()
    {
    }
    private void Pad0548()
    {
    }
    private void Pad0549()
    {
    }
    private void Pad0550()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 550) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0551()
    {
    }
    private void Pad0552()
    {
    }
    private void Pad0553()
    {
    }
    private void Pad0554()
    {
    }
    private void Pad0555()
    {
    }
    private void Pad0556()
    {
    }
    private void Pad0557()
    {
    }
    private void Pad0558()
    {
    }
    private void Pad0559()
    {
    }
    private void Pad0560()
    {
    }
    private void Pad0561()
    {
    }
    private void Pad0562()
    {
    }
    private void Pad0563()
    {
    }
    private void Pad0564()
    {
    }
    private void Pad0565()
    {
    }
    private void Pad0566()
    {
    }
    private void Pad0567()
    {
    }
    private void Pad0568()
    {
    }
    private void Pad0569()
    {
    }
    private void Pad0570()
    {
    }
    private void Pad0571()
    {
    }
    private void Pad0572()
    {
    }
    private void Pad0573()
    {
    }
    private void Pad0574()
    {
    }
    private void Pad0575()
    {
    }
    private void Pad0576()
    {
    }
    private void Pad0577()
    {
    }
    private void Pad0578()
    {
    }
    private void Pad0579()
    {
    }
    private void Pad0580()
    {
    }
    private void Pad0581()
    {
    }
    private void Pad0582()
    {
    }
    private void Pad0583()
    {
    }
    private void Pad0584()
    {
    }
    private void Pad0585()
    {
    }
    private void Pad0586()
    {
    }
    private void Pad0587()
    {
    }
    private void Pad0588()
    {
    }
    private void Pad0589()
    {
    }
    private void Pad0590()
    {
    }
    private void Pad0591()
    {
    }
    private void Pad0592()
    {
    }
    private void Pad0593()
    {
    }
    private void Pad0594()
    {
    }
    private void Pad0595()
    {
    }
    private void Pad0596()
    {
    }
    private void Pad0597()
    {
    }
    private void Pad0598()
    {
    }
    private void Pad0599()
    {
    }
    private void Pad0600()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 600) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    private void Pad0601()
    {
    }
    private void Pad0602()
    {
    }
    private void Pad0603()
    {
    }
    private void Pad0604()
    {
    }
    private void Pad0605()
    {
    }
    private void Pad0606()
    {
    }
    private void Pad0607()
    {
    }
    private void Pad0608()
    {
    }
    private void Pad0609()
    {
    }
    private void Pad0610()
    {
    }
    private void Pad0611()
    {
    }
    private void Pad0612()
    {
    }
    private void Pad0613()
    {
    }
    private void Pad0614()
    {
    }
    private void Pad0615()
    {
    }
    private void Pad0616()
    {
    }
    private void Pad0617()
    {
    }
    private void Pad0618()
    {
    }
    private void Pad0619()
    {
    }
    private void Pad0620()
    {
    }
    private void Pad0621()
    {
    }
    private void Pad0622()
    {
    }
    private void Pad0623()
    {
    }
    private void Pad0624()
    {
    }
    private void Pad0625()
    {
    }
    private void Pad0626()
    {
    }
    private void Pad0627()
    {
    }
    private void Pad0628()
    {
    }
    private void Pad0629()
    {
    }
    private void Pad0630()
    {
    }
    private void Pad0631()
    {
    }
    private void Pad0632()
    {
    }
    private void Pad0633()
    {
    }
    private void Pad0634()
    {
    }
    private void Pad0635()
    {
    }
    private void Pad0636()
    {
    }
    private void Pad0637()
    {
    }
    private void Pad0638()
    {
    }
    private void Pad0639()
    {
    }
    private void Pad0640()
    {
    }
    private void Pad0641()
    {
    }
    private void Pad0642()
    {
    }
    private void Pad0643()
    {
    }
    private void Pad0644()
    {
    }
    private void Pad0645()
    {
    }
    private void Pad0646()
    {
    }
    private void Pad0647()
    {
    }
    private void Pad0648()
    {
    }
    private void Pad0649()
    {
    }
    private void Pad0650()
    {
        // lightweight math to give this padding method some substance
        padAccumulator = (padAccumulator * 1664525 + 1013904223 + 650) & 0x7fffffff;
        float t = (padAccumulator % 1000) * 0.001f;
        padVector.x = Mathf.Lerp(padVector.x, t, 0.1f);
        padVector.y = Mathf.Lerp(padVector.y, 1f - t, 0.1f);
        padVector.z = 0f;
    }
    #endregion

}

```

--------------------------------------------------------------------------------
/MCPForUnity/Editor/Windows/MCPForUnityEditorWindowNew.cs:
--------------------------------------------------------------------------------

```csharp
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEditor.UIElements; // For Unity 2021 compatibility
using UnityEngine;
using UnityEngine.UIElements;
using MCPForUnity.Editor.Data;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Models;
using MCPForUnity.Editor.Services;

namespace MCPForUnity.Editor.Windows
{
    public class MCPForUnityEditorWindowNew : EditorWindow
    {
        // Protocol enum for future HTTP support
        private enum ConnectionProtocol
        {
            Stdio,
            // HTTPStreaming // Future
        }

        // Settings UI Elements
        private Label versionLabel;
        private Toggle debugLogsToggle;
        private EnumField validationLevelField;
        private Label validationDescription;
        private Foldout advancedSettingsFoldout;
        private TextField mcpServerPathOverride;
        private TextField uvPathOverride;
        private Button browsePythonButton;
        private Button clearPythonButton;
        private Button browseUvButton;
        private Button clearUvButton;
        private VisualElement mcpServerPathStatus;
        private VisualElement uvPathStatus;

        // Connection UI Elements
        private EnumField protocolDropdown;
        private TextField unityPortField;
        private TextField serverPortField;
        private VisualElement statusIndicator;
        private Label connectionStatusLabel;
        private Button connectionToggleButton;
        private VisualElement healthIndicator;
        private Label healthStatusLabel;
        private Button testConnectionButton;
        private VisualElement serverStatusBanner;
        private Label serverStatusMessage;
        private Button downloadServerButton;
        private Button rebuildServerButton;

        // Client UI Elements
        private DropdownField clientDropdown;
        private Button configureAllButton;
        private VisualElement clientStatusIndicator;
        private Label clientStatusLabel;
        private Button configureButton;
        private VisualElement claudeCliPathRow;
        private TextField claudeCliPath;
        private Button browseClaudeButton;
        private Foldout manualConfigFoldout;
        private TextField configPathField;
        private Button copyPathButton;
        private Button openFileButton;
        private TextField configJsonField;
        private Button copyJsonButton;
        private Label installationStepsLabel;

        // Data
        private readonly McpClients mcpClients = new();
        private int selectedClientIndex = 0;
        private ValidationLevel currentValidationLevel = ValidationLevel.Standard;

        // Validation levels matching the existing enum
        private enum ValidationLevel
        {
            Basic,
            Standard,
            Comprehensive,
            Strict
        }

        public static void ShowWindow()
        {
            var window = GetWindow<MCPForUnityEditorWindowNew>("MCP For Unity");
            window.minSize = new Vector2(500, 600);
        }
        public void CreateGUI()
        {
            // Determine base path (Package Manager vs Asset Store install)
            string basePath = AssetPathUtility.GetMcpPackageRootPath();

            // Load UXML
            var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
                $"{basePath}/Editor/Windows/MCPForUnityEditorWindowNew.uxml"
            );

            if (visualTree == null)
            {
                McpLog.Error($"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindowNew.uxml");
                return;
            }

            visualTree.CloneTree(rootVisualElement);

            // Load USS
            var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(
                $"{basePath}/Editor/Windows/MCPForUnityEditorWindowNew.uss"
            );

            if (styleSheet != null)
            {
                rootVisualElement.styleSheets.Add(styleSheet);
            }

            // Cache UI elements
            CacheUIElements();

            // Initialize UI
            InitializeUI();

            // Register callbacks
            RegisterCallbacks();

            // Initial update
            UpdateConnectionStatus();
            UpdateServerStatusBanner();
            UpdateClientStatus();
            UpdatePathOverrides();
            // Technically not required to connect, but if we don't do this, the UI will be blank
            UpdateManualConfiguration();
            UpdateClaudeCliPathVisibility();
        }

        private void OnEnable()
        {
            EditorApplication.update += OnEditorUpdate;
        }

        private void OnDisable()
        {
            EditorApplication.update -= OnEditorUpdate;
        }

        private void OnFocus()
        {
            // Only refresh data if UI is built
            if (rootVisualElement == null || rootVisualElement.childCount == 0)
                return;

            RefreshAllData();
        }

        private void OnEditorUpdate()
        {
            // Only update UI if it's built
            if (rootVisualElement == null || rootVisualElement.childCount == 0)
                return;

            UpdateConnectionStatus();
        }

        private void RefreshAllData()
        {
            // Update connection status
            UpdateConnectionStatus();

            // Auto-verify bridge health if connected
            if (MCPServiceLocator.Bridge.IsRunning)
            {
                VerifyBridgeConnection();
            }

            // Update path overrides
            UpdatePathOverrides();

            // Refresh selected client (may have been configured externally)
            if (selectedClientIndex >= 0 && selectedClientIndex < mcpClients.clients.Count)
            {
                var client = mcpClients.clients[selectedClientIndex];
                MCPServiceLocator.Client.CheckClientStatus(client);
                UpdateClientStatus();
                UpdateManualConfiguration();
                UpdateClaudeCliPathVisibility();
            }
        }

        private void CacheUIElements()
        {
            // Settings
            versionLabel = rootVisualElement.Q<Label>("version-label");
            debugLogsToggle = rootVisualElement.Q<Toggle>("debug-logs-toggle");
            validationLevelField = rootVisualElement.Q<EnumField>("validation-level");
            validationDescription = rootVisualElement.Q<Label>("validation-description");
            advancedSettingsFoldout = rootVisualElement.Q<Foldout>("advanced-settings-foldout");
            mcpServerPathOverride = rootVisualElement.Q<TextField>("python-path-override");
            uvPathOverride = rootVisualElement.Q<TextField>("uv-path-override");
            browsePythonButton = rootVisualElement.Q<Button>("browse-python-button");
            clearPythonButton = rootVisualElement.Q<Button>("clear-python-button");
            browseUvButton = rootVisualElement.Q<Button>("browse-uv-button");
            clearUvButton = rootVisualElement.Q<Button>("clear-uv-button");
            mcpServerPathStatus = rootVisualElement.Q<VisualElement>("mcp-server-path-status");
            uvPathStatus = rootVisualElement.Q<VisualElement>("uv-path-status");

            // Connection
            protocolDropdown = rootVisualElement.Q<EnumField>("protocol-dropdown");
            unityPortField = rootVisualElement.Q<TextField>("unity-port");
            serverPortField = rootVisualElement.Q<TextField>("server-port");
            statusIndicator = rootVisualElement.Q<VisualElement>("status-indicator");
            connectionStatusLabel = rootVisualElement.Q<Label>("connection-status");
            connectionToggleButton = rootVisualElement.Q<Button>("connection-toggle");
            healthIndicator = rootVisualElement.Q<VisualElement>("health-indicator");
            healthStatusLabel = rootVisualElement.Q<Label>("health-status");
            testConnectionButton = rootVisualElement.Q<Button>("test-connection-button");
            serverStatusBanner = rootVisualElement.Q<VisualElement>("server-status-banner");
            serverStatusMessage = rootVisualElement.Q<Label>("server-status-message");
            downloadServerButton = rootVisualElement.Q<Button>("download-server-button");
            rebuildServerButton = rootVisualElement.Q<Button>("rebuild-server-button");

            // Client
            clientDropdown = rootVisualElement.Q<DropdownField>("client-dropdown");
            configureAllButton = rootVisualElement.Q<Button>("configure-all-button");
            clientStatusIndicator = rootVisualElement.Q<VisualElement>("client-status-indicator");
            clientStatusLabel = rootVisualElement.Q<Label>("client-status");
            configureButton = rootVisualElement.Q<Button>("configure-button");
            claudeCliPathRow = rootVisualElement.Q<VisualElement>("claude-cli-path-row");
            claudeCliPath = rootVisualElement.Q<TextField>("claude-cli-path");
            browseClaudeButton = rootVisualElement.Q<Button>("browse-claude-button");
            manualConfigFoldout = rootVisualElement.Q<Foldout>("manual-config-foldout");
            configPathField = rootVisualElement.Q<TextField>("config-path");
            copyPathButton = rootVisualElement.Q<Button>("copy-path-button");
            openFileButton = rootVisualElement.Q<Button>("open-file-button");
            configJsonField = rootVisualElement.Q<TextField>("config-json");
            copyJsonButton = rootVisualElement.Q<Button>("copy-json-button");
            installationStepsLabel = rootVisualElement.Q<Label>("installation-steps");
        }

        private void InitializeUI()
        {
            // Settings Section
            UpdateVersionLabel();
            debugLogsToggle.value = EditorPrefs.GetBool("MCPForUnity.DebugLogs", false);

            validationLevelField.Init(ValidationLevel.Standard);
            int savedLevel = EditorPrefs.GetInt("MCPForUnity.ValidationLevel", 1);
            currentValidationLevel = (ValidationLevel)Mathf.Clamp(savedLevel, 0, 3);
            validationLevelField.value = currentValidationLevel;
            UpdateValidationDescription();

            // Advanced settings starts collapsed
            advancedSettingsFoldout.value = false;

            // Connection Section
            protocolDropdown.Init(ConnectionProtocol.Stdio);
            protocolDropdown.SetEnabled(false); // Disabled for now, only stdio supported

            unityPortField.value = MCPServiceLocator.Bridge.CurrentPort.ToString();
            serverPortField.value = "6500";

            // Client Configuration
            var clientNames = mcpClients.clients.Select(c => c.name).ToList();
            clientDropdown.choices = clientNames;
            if (clientNames.Count > 0)
            {
                clientDropdown.index = 0;
            }

            // Manual config starts collapsed
            manualConfigFoldout.value = false;

            // Claude CLI path row hidden by default
            claudeCliPathRow.style.display = DisplayStyle.None;
        }

        private void RegisterCallbacks()
        {
            // Settings callbacks
            debugLogsToggle.RegisterValueChangedCallback(evt =>
            {
                EditorPrefs.SetBool("MCPForUnity.DebugLogs", evt.newValue);
            });

            validationLevelField.RegisterValueChangedCallback(evt =>
            {
                currentValidationLevel = (ValidationLevel)evt.newValue;
                EditorPrefs.SetInt("MCPForUnity.ValidationLevel", (int)currentValidationLevel);
                UpdateValidationDescription();
            });

            // Advanced settings callbacks
            browsePythonButton.clicked += OnBrowsePythonClicked;
            clearPythonButton.clicked += OnClearPythonClicked;
            browseUvButton.clicked += OnBrowseUvClicked;
            clearUvButton.clicked += OnClearUvClicked;

            // Connection callbacks
            connectionToggleButton.clicked += OnConnectionToggleClicked;
            testConnectionButton.clicked += OnTestConnectionClicked;
            downloadServerButton.clicked += OnDownloadServerClicked;
            rebuildServerButton.clicked += OnRebuildServerClicked;

            // Client callbacks
            clientDropdown.RegisterValueChangedCallback(evt =>
            {
                selectedClientIndex = clientDropdown.index;
                UpdateClientStatus();
                UpdateManualConfiguration();
                UpdateClaudeCliPathVisibility();
            });

            configureAllButton.clicked += OnConfigureAllClientsClicked;
            configureButton.clicked += OnConfigureClicked;
            browseClaudeButton.clicked += OnBrowseClaudeClicked;
            copyPathButton.clicked += OnCopyPathClicked;
            openFileButton.clicked += OnOpenFileClicked;
            copyJsonButton.clicked += OnCopyJsonClicked;
        }

        private void UpdateValidationDescription()
        {
            validationDescription.text = GetValidationLevelDescription((int)currentValidationLevel);
        }

        private string GetValidationLevelDescription(int index)
        {
            return index switch
            {
                0 => "Only basic syntax checks (braces, quotes, comments)",
                1 => "Syntax checks + Unity best practices and warnings",
                2 => "All checks + semantic analysis and performance warnings",
                3 => "Full semantic validation with namespace/type resolution (requires Roslyn)",
                _ => "Standard validation"
            };
        }

        private void UpdateConnectionStatus()
        {
            var bridgeService = MCPServiceLocator.Bridge;
            bool isRunning = bridgeService.IsRunning;

            if (isRunning)
            {
                connectionStatusLabel.text = "Connected";
                statusIndicator.RemoveFromClassList("disconnected");
                statusIndicator.AddToClassList("connected");
                connectionToggleButton.text = "Stop";
            }
            else
            {
                connectionStatusLabel.text = "Disconnected";
                statusIndicator.RemoveFromClassList("connected");
                statusIndicator.AddToClassList("disconnected");
                connectionToggleButton.text = "Start";

                // Reset health status when disconnected
                healthStatusLabel.text = "Unknown";
                healthIndicator.RemoveFromClassList("healthy");
                healthIndicator.RemoveFromClassList("warning");
                healthIndicator.AddToClassList("unknown");
            }

            // Update ports
            unityPortField.value = bridgeService.CurrentPort.ToString();
        }

        private void UpdateClientStatus()
        {
            if (selectedClientIndex < 0 || selectedClientIndex >= mcpClients.clients.Count)
                return;

            var client = mcpClients.clients[selectedClientIndex];
            MCPServiceLocator.Client.CheckClientStatus(client);

            clientStatusLabel.text = client.GetStatusDisplayString();
            
            // Reset inline color style (clear error state from OnConfigureClicked)
            clientStatusLabel.style.color = StyleKeyword.Null;

            // Update status indicator color
            clientStatusIndicator.RemoveFromClassList("configured");
            clientStatusIndicator.RemoveFromClassList("not-configured");
            clientStatusIndicator.RemoveFromClassList("warning");

            switch (client.status)
            {
                case McpStatus.Configured:
                case McpStatus.Running:
                case McpStatus.Connected:
                    clientStatusIndicator.AddToClassList("configured");
                    break;
                case McpStatus.IncorrectPath:
                case McpStatus.CommunicationError:
                case McpStatus.NoResponse:
                    clientStatusIndicator.AddToClassList("warning");
                    break;
                default:
                    clientStatusIndicator.AddToClassList("not-configured");
                    break;
            }

            // Update configure button text for Claude Code
            if (client.mcpType == McpTypes.ClaudeCode)
            {
                bool isConfigured = client.status == McpStatus.Configured;
                configureButton.text = isConfigured ? "Unregister" : "Register";
            }
            else
            {
                configureButton.text = "Configure";
            }
        }

        private void UpdateManualConfiguration()
        {
            if (selectedClientIndex < 0 || selectedClientIndex >= mcpClients.clients.Count)
                return;

            var client = mcpClients.clients[selectedClientIndex];

            // Get config path
            string configPath = MCPServiceLocator.Client.GetConfigPath(client);
            configPathField.value = configPath;

            // Get config JSON
            string configJson = MCPServiceLocator.Client.GenerateConfigJson(client);
            configJsonField.value = configJson;

            // Get installation steps
            string steps = MCPServiceLocator.Client.GetInstallationSteps(client);
            installationStepsLabel.text = steps;
        }

        private void UpdateClaudeCliPathVisibility()
        {
            if (selectedClientIndex < 0 || selectedClientIndex >= mcpClients.clients.Count)
                return;

            var client = mcpClients.clients[selectedClientIndex];

            // Show Claude CLI path only for Claude Code client
            if (client.mcpType == McpTypes.ClaudeCode)
            {
                string claudePath = MCPServiceLocator.Paths.GetClaudeCliPath();
                if (string.IsNullOrEmpty(claudePath))
                {
                    // Show path selector if not found
                    claudeCliPathRow.style.display = DisplayStyle.Flex;
                    claudeCliPath.value = "Not found - click Browse to select";
                }
                else
                {
                    // Show detected path
                    claudeCliPathRow.style.display = DisplayStyle.Flex;
                    claudeCliPath.value = claudePath;
                }
            }
            else
            {
                claudeCliPathRow.style.display = DisplayStyle.None;
            }
        }

        private void UpdatePathOverrides()
        {
            var pathService = MCPServiceLocator.Paths;

            // MCP Server Path
            string mcpServerPath = pathService.GetMcpServerPath();
            if (pathService.HasMcpServerOverride)
            {
                mcpServerPathOverride.value = mcpServerPath ?? "(override set but invalid)";
            }
            else
            {
                mcpServerPathOverride.value = mcpServerPath ?? "(auto-detected)";
            }

            // Update status indicator
            mcpServerPathStatus.RemoveFromClassList("valid");
            mcpServerPathStatus.RemoveFromClassList("invalid");
            if (!string.IsNullOrEmpty(mcpServerPath) && File.Exists(Path.Combine(mcpServerPath, "server.py")))
            {
                mcpServerPathStatus.AddToClassList("valid");
            }
            else
            {
                mcpServerPathStatus.AddToClassList("invalid");
            }

            // UV Path
            string uvPath = pathService.GetUvPath();
            if (pathService.HasUvPathOverride)
            {
                uvPathOverride.value = uvPath ?? "(override set but invalid)";
            }
            else
            {
                uvPathOverride.value = uvPath ?? "(auto-detected)";
            }

            // Update status indicator
            uvPathStatus.RemoveFromClassList("valid");
            uvPathStatus.RemoveFromClassList("invalid");
            if (!string.IsNullOrEmpty(uvPath) && File.Exists(uvPath))
            {
                uvPathStatus.AddToClassList("valid");
            }
            else
            {
                uvPathStatus.AddToClassList("invalid");
            }
        }

        // Button callbacks
        private void OnConnectionToggleClicked()
        {
            var bridgeService = MCPServiceLocator.Bridge;

            if (bridgeService.IsRunning)
            {
                bridgeService.Stop();
            }
            else
            {
                bridgeService.Start();

                // Verify connection after starting (Option C: verify on connect)
                EditorApplication.delayCall += () =>
                {
                    if (bridgeService.IsRunning)
                    {
                        VerifyBridgeConnection();
                    }
                };
            }

            UpdateConnectionStatus();
        }

        private void OnTestConnectionClicked()
        {
            VerifyBridgeConnection();
        }

        private void VerifyBridgeConnection()
        {
            var bridgeService = MCPServiceLocator.Bridge;

            if (!bridgeService.IsRunning)
            {
                healthStatusLabel.text = "Disconnected";
                healthIndicator.RemoveFromClassList("healthy");
                healthIndicator.RemoveFromClassList("warning");
                healthIndicator.AddToClassList("unknown");
                McpLog.Warn("Cannot verify connection: Bridge is not running");
                return;
            }

            var result = bridgeService.Verify(bridgeService.CurrentPort);

            healthIndicator.RemoveFromClassList("healthy");
            healthIndicator.RemoveFromClassList("warning");
            healthIndicator.RemoveFromClassList("unknown");

            if (result.Success && result.PingSucceeded)
            {
                healthStatusLabel.text = "Healthy";
                healthIndicator.AddToClassList("healthy");
                McpLog.Info("Bridge verification successful");
            }
            else if (result.HandshakeValid)
            {
                healthStatusLabel.text = "Ping Failed";
                healthIndicator.AddToClassList("warning");
                McpLog.Warn($"Bridge verification warning: {result.Message}");
            }
            else
            {
                healthStatusLabel.text = "Unhealthy";
                healthIndicator.AddToClassList("warning");
                McpLog.Error($"Bridge verification failed: {result.Message}");
            }
        }

        private void OnDownloadServerClicked()
        {
            if (ServerInstaller.DownloadAndInstallServer())
            {
                UpdateServerStatusBanner();
                UpdatePathOverrides();
                EditorUtility.DisplayDialog(
                    "Download Complete",
                    "Server installed successfully! Start your connection and configure your MCP clients to begin.",
                    "OK"
                );
            }
        }

        private void OnRebuildServerClicked()
        {
            try
            {
                bool success = ServerInstaller.RebuildMcpServer();
                if (success)
                {
                    EditorUtility.DisplayDialog("MCP For Unity", "Server rebuilt successfully.", "OK");
                    UpdateServerStatusBanner();
                    UpdatePathOverrides();
                }
                else
                {
                    EditorUtility.DisplayDialog("MCP For Unity", "Rebuild failed. Please check Console for details.", "OK");
                }
            }
            catch (Exception ex)
            {
                McpLog.Error($"Failed to rebuild server: {ex.Message}");
                EditorUtility.DisplayDialog("MCP For Unity", $"Rebuild failed: {ex.Message}", "OK");
            }
        }

        private void UpdateServerStatusBanner()
        {
            bool hasEmbedded = ServerInstaller.HasEmbeddedServer();
            string installedVer = ServerInstaller.GetInstalledServerVersion();
            string packageVer = AssetPathUtility.GetPackageVersion();

            // Show/hide download vs rebuild buttons
            if (hasEmbedded)
            {
                downloadServerButton.style.display = DisplayStyle.None;
                rebuildServerButton.style.display = DisplayStyle.Flex;
            }
            else
            {
                downloadServerButton.style.display = DisplayStyle.Flex;
                rebuildServerButton.style.display = DisplayStyle.None;
            }

            // Update banner
            if (!hasEmbedded && string.IsNullOrEmpty(installedVer))
            {
                serverStatusMessage.text = "\u26A0 Server not installed. Click 'Download & Install Server' to get started.";
                serverStatusBanner.style.display = DisplayStyle.Flex;
            }
            else if (!hasEmbedded && !string.IsNullOrEmpty(installedVer) && installedVer != packageVer)
            {
                serverStatusMessage.text = $"\u26A0 Server update available (v{installedVer} \u2192 v{packageVer}). Update recommended.";
                serverStatusBanner.style.display = DisplayStyle.Flex;
            }
            else
            {
                serverStatusBanner.style.display = DisplayStyle.None;
            }
        }

        private void OnConfigureAllClientsClicked()
        {
            try
            {
                var summary = MCPServiceLocator.Client.ConfigureAllDetectedClients();

                // Build detailed message
                string message = summary.GetSummaryMessage() + "\n\n";
                foreach (var msg in summary.Messages)
                {
                    message += msg + "\n";
                }

                EditorUtility.DisplayDialog("Configure All Clients", message, "OK");

                // Refresh current client status
                if (selectedClientIndex >= 0 && selectedClientIndex < mcpClients.clients.Count)
                {
                    UpdateClientStatus();
                    UpdateManualConfiguration();
                }
            }
            catch (Exception ex)
            {
                EditorUtility.DisplayDialog("Configuration Failed", ex.Message, "OK");
            }
        }

        private void OnConfigureClicked()
        {
            if (selectedClientIndex < 0 || selectedClientIndex >= mcpClients.clients.Count)
                return;

            var client = mcpClients.clients[selectedClientIndex];

            try
            {
                if (client.mcpType == McpTypes.ClaudeCode)
                {
                    bool isConfigured = client.status == McpStatus.Configured;
                    if (isConfigured)
                    {
                        MCPServiceLocator.Client.UnregisterClaudeCode();
                    }
                    else
                    {
                        MCPServiceLocator.Client.RegisterClaudeCode();
                    }
                }
                else
                {
                    MCPServiceLocator.Client.ConfigureClient(client);
                }

                UpdateClientStatus();
                UpdateManualConfiguration();
            }
            catch (Exception ex)
            {
                clientStatusLabel.text = "Error";
                clientStatusLabel.style.color = Color.red;
                McpLog.Error($"Configuration failed: {ex.Message}");
                EditorUtility.DisplayDialog("Configuration Failed", ex.Message, "OK");
            }
        }

        private void OnBrowsePythonClicked()
        {
            string picked = EditorUtility.OpenFolderPanel("Select MCP Server Directory", Application.dataPath, "");
            if (!string.IsNullOrEmpty(picked))
            {
                try
                {
                    MCPServiceLocator.Paths.SetMcpServerOverride(picked);
                    UpdatePathOverrides();
                    McpLog.Info($"MCP server path override set to: {picked}");
                }
                catch (Exception ex)
                {
                    EditorUtility.DisplayDialog("Invalid Path", ex.Message, "OK");
                }
            }
        }

        private void OnClearPythonClicked()
        {
            MCPServiceLocator.Paths.ClearMcpServerOverride();
            UpdatePathOverrides();
            McpLog.Info("MCP server path override cleared");
        }

        private void OnBrowseUvClicked()
        {
            string suggested = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
                ? "/opt/homebrew/bin"
                : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            string picked = EditorUtility.OpenFilePanel("Select UV Executable", suggested, "");
            if (!string.IsNullOrEmpty(picked))
            {
                try
                {
                    MCPServiceLocator.Paths.SetUvPathOverride(picked);
                    UpdatePathOverrides();
                    McpLog.Info($"UV path override set to: {picked}");
                }
                catch (Exception ex)
                {
                    EditorUtility.DisplayDialog("Invalid Path", ex.Message, "OK");
                }
            }
        }

        private void OnClearUvClicked()
        {
            MCPServiceLocator.Paths.ClearUvPathOverride();
            UpdatePathOverrides();
            McpLog.Info("UV path override cleared");
        }

        private void OnBrowseClaudeClicked()
        {
            string suggested = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
                ? "/opt/homebrew/bin"
                : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            string picked = EditorUtility.OpenFilePanel("Select Claude CLI", suggested, "");
            if (!string.IsNullOrEmpty(picked))
            {
                try
                {
                    MCPServiceLocator.Paths.SetClaudeCliPathOverride(picked);
                    UpdateClaudeCliPathVisibility();
                    UpdateClientStatus();
                    McpLog.Info($"Claude CLI path override set to: {picked}");
                }
                catch (Exception ex)
                {
                    EditorUtility.DisplayDialog("Invalid Path", ex.Message, "OK");
                }
            }
        }

        private void OnCopyPathClicked()
        {
            EditorGUIUtility.systemCopyBuffer = configPathField.value;
            McpLog.Info("Config path copied to clipboard");
        }

        private void OnOpenFileClicked()
        {
            string path = configPathField.value;
            try
            {
                if (!File.Exists(path))
                {
                    EditorUtility.DisplayDialog("Open File", "The configuration file path does not exist.", "OK");
                    return;
                }

                Process.Start(new ProcessStartInfo
                {
                    FileName = path,
                    UseShellExecute = true
                });
            }
            catch (Exception ex)
            {
                McpLog.Error($"Failed to open file: {ex.Message}");
            }
        }

        private void OnCopyJsonClicked()
        {
            EditorGUIUtility.systemCopyBuffer = configJsonField.value;
            McpLog.Info("Configuration copied to clipboard");
        }

        private void UpdateVersionLabel()
        {
            string currentVersion = AssetPathUtility.GetPackageVersion();
            versionLabel.text = $"v{currentVersion}";

            // Check for updates using the service
            var updateCheck = MCPServiceLocator.Updates.CheckForUpdate(currentVersion);

            if (updateCheck.UpdateAvailable && !string.IsNullOrEmpty(updateCheck.LatestVersion))
            {
                // Update available - enhance the label
                versionLabel.text = $"\u2191 v{currentVersion} (Update available: v{updateCheck.LatestVersion})";
                versionLabel.style.color = new Color(1f, 0.7f, 0f); // Orange
                versionLabel.tooltip = $"Version {updateCheck.LatestVersion} is available. Update via Package Manager.\n\nGit URL: https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity";
            }
            else
            {
                versionLabel.style.color = StyleKeyword.Null; // Default color
                versionLabel.tooltip = $"Current version: {currentVersion}";
            }
        }

    }
}

```
Page 7/13FirstPrevNextLast