* fix: reduce per-frame GC allocations causing editor hitches (issue #577) Eliminate memory allocations that occurred every frame, which triggered garbage collection spikes (~28ms) approximately every second. Changes: - EditorStateCache: Skip BuildSnapshot() entirely when state unchanged (check BEFORE building). Increased poll interval from 0.25s to 1.0s. Cache DeepClone() results to avoid allocations on GetSnapshot(). - TransportCommandDispatcher: Early exit before lock/list allocation when Pending.Count == 0, eliminating per-frame allocations when idle. - StdioBridgeHost: Same early exit pattern for commandQueue. - MCPForUnityEditorWindow: Throttle OnEditorUpdate to 2-second intervals instead of every frame, preventing expensive socket checks 60+/sec. Fixes GitHub issue #577: High performance impact even when MCP server is off * fix: prevent multiple domain reloads when calling refresh_unity (issue #577) Root Cause: - send_command() had a hardcoded retry loop (min 6 attempts) on connection errors - Each retry resent the refresh_unity command, causing Unity to reload 6 times - retry_on_reload=False only controlled reload-state retries, not connection retries The Fix: 1. Unity C# (MCPForUnity/Editor): - Added --reinstall flag to uvx commands in dev mode - Ensures local development changes are picked up by uvx/Claude Code - Applies to all client configurators (Claude Code, Codex, etc.) 2. Python Server (Server/src): - Added max_attempts parameter to send_command() - Pass max_attempts=0 when retry_on_reload=False - Fixed type handling in refresh_unity.py (handle MCPResponse objects) - Added timeout to connection error recovery conditions - Recovery logic now returns success instead of error to prevent client retries Changes: - MCPForUnity/Editor: Added --reinstall to dev mode uvx commands - Server/refresh_unity.py: Fixed type handling, improved error recovery - Server/unity_connection.py: Added max_attempts param, disable retries when retry_on_reload=False Result: refresh_unity with compile=request now triggers only 1 domain reload instead of 6 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: UI and server stability improvements Unity Editor (C#): - Fix "Resuming..." stuck state when manually clicking End Session Clear ResumeStdioAfterReload and ResumeHttpAfterReload flags in OnConnectionToggleClicked and EndOrphanedSessionAsync to prevent UI from getting stuck showing "Resuming..." with disabled button - Remove unsupported --reinstall flag from all uvx command builders uvx does not support --reinstall and shows warning when used Use --no-cache --refresh instead for dev mode cache busting Python Server: - Add "aborted" to connection error patterns in refresh_unity Handle WinError 10053 (connection aborted) gracefully during Unity domain reload, treating it as expected behavior - Add WindowsSafeRotatingFileHandler to suppress log rotation errors Windows file locking prevents log rotation when file is open by another process; catch PermissionError to avoid noisy stack traces - Fix packaging: add py-modules = ["main"] to pyproject.toml setuptools.packages.find only discovers packages (directories with __init__.py), must explicitly list standalone module files Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * docs: improve refresh_unity connection loss handling documentation Add detailed comments and logging to clarify why connection loss during compile is treated as success (expected domain reload behavior, not failure). This addresses PR feedback about potentially masking real connection errors. The logic is intentional and correct: - Connection loss only treated as success when compile='request' - Domain reload causing disconnect is expected Unity behavior - Subsequent wait_for_ready loop validates Unity becomes ready - Prevents multiple domain reload loops (issue #577) Added logging for observability: - Info log when expected disconnect detected - Warning log for non-recoverable errors Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: add missing logger import in refresh_unity Missing logger import causes NameError at runtime when connection loss handling paths are triggered (lines 82 and 91). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: address code review feedback on thread safety and semantics Addresses four issues raised in code review: 1. EditorStateCache.GetSnapshot() - Remove shared cached clone - Revert to always returning fresh DeepClone() to prevent mutation bugs - Main GC optimization remains: state-change detection prevents unnecessary _cached rebuilds (the expensive operation) - Removed _cachedClone and _cachedCloneSequence fields 2. refresh_unity.py - Fix blocking reason terminology mismatch - Changed "asset_refresh" to "asset_import" to match activityPhase values from EditorStateCache.cs - Ensures asset import is correctly detected as blocking state 3. TransportCommandDispatcher - Fix unsynchronized Count access - Moved Pending.Count check inside PendingLock - Prevents data races and InvalidOperationException from concurrent dictionary access 4. StdioBridgeHost - Fix unsynchronized Count access - Moved commandQueue.Count check inside lockObj - Ensures all collection access is properly serialized All changes maintain the GC allocation optimizations while fixing thread safety violations and semantic contract changes. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: address code review feedback on thread safety and timeout handling - refresh_unity.py: Track readiness explicitly and return failure on timeout instead of silently returning success when wait loop exits without confirming ready_for_tools=true - McpClientConfiguratorBase.cs: Add thread safety guard for Configure() call in CheckStatusWithProjectDir(). Changed default attemptAutoRewrite to false and added runtime check to prevent calling Configure() from background threads. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Editor | ||
| Runtime | ||
| Editor.meta | ||
| README.md | ||
| README.md.meta | ||
| Runtime.meta | ||
| package.json | ||
| package.json.meta | ||
README.md
MCP for Unity — Editor Plugin Guide
Use this guide to configure and run MCP for Unity inside the Unity Editor. Installation is covered elsewhere; this document focuses on the Editor window, client configuration, and troubleshooting.
Open the window
- Unity menu: Window > MCP for Unity
The window has four areas: Server Status, Unity Bridge, MCP Client Configuration, and Script Validation.
Quick start
- Open Window > MCP for Unity.
- Click “Auto-Setup”.
- If prompted:
- Select the packaged server folder (
Server) if you want to run the bundled implementation. - Install Python and/or uv/uvx if missing so the server can be managed locally.
- For Claude Code, ensure the
claudeCLI is installed.
- Select the packaged server folder (
- Click “Start Bridge” if the Unity Bridge shows “Stopped”.
- Use your MCP client (Cursor, VS Code, Windsurf, Claude Code) to connect.
Server Status
- Status dot and label:
- Installed / Installed (Embedded) / Not Installed.
- Mode and ports:
- Mode: Auto or Standard.
- Ports: Unity (varies; shown in UI), MCP 6500.
- Actions:
- Auto-Setup: Registers/updates your selected MCP client(s), ensures bridge connectivity. Shows “Connected ✓” after success.
- Rebuild MCP Server: Rebuilds the Python based MCP server
- Select server folder…: Choose the folder containing
server.py. - Verify again: Re-checks server presence.
- If Python isn’t detected, use “Open Install Instructions”.
- HTTP Server Command foldout:
- Expands to display the exact
uvxcommand Unity will run. - Includes a copy button and the “Start Local HTTP Server” action so you can launch or reuse the command elsewhere.
- Expands to display the exact
Unity Bridge
- Shows Running or Stopped with a status dot.
- Start/Stop Bridge button toggles the Unity bridge process used by MCP clients to talk to Unity.
- Tip: After Auto-Setup, the bridge may auto-start in Auto mode.
MCP Client Configuration
- Select Client: Choose your target MCP client (e.g., Cursor, VS Code, Windsurf, Claude Code).
- Per-client actions:
- Cursor / VS Code / Windsurf:
- Auto Configure: Writes/updates your config to launch the server via
uvxwith the current package version:- Command: uvx (or your overridden path)
- Args: --from mcp-for-unity
- Manual Setup: Opens a window with a pre-filled JSON snippet to copy/paste into your client config.
- Choose UV Install Location: If uv/uvx isn’t on PATH, select the executable.
- A compact “Config:” line shows the resolved config file name once uv/server are detected.
- Auto Configure: Writes/updates your config to launch the server via
- Claude Code:
- Register with Claude Code / Unregister MCP for Unity with Claude Code.
- If the CLI isn’t found, click “Choose Claude Install Location”.
- The window displays the resolved Claude CLI path when detected.
- Cursor / VS Code / Windsurf:
Notes:
- The UI shows a status dot and a short status text (e.g., “Configured”, “uv Not Found”, “Claude Not Found”).
- Use “Auto Configure” for one-click setup; use “Manual Setup” when you prefer to review/copy config.
Script Validation
- Validation Level options:
- Basic — Only syntax checks
- Standard — Syntax + Unity practices
- Comprehensive — All checks + semantic analysis
- Strict — Full semantic validation (requires Roslyn)
- Pick a level based on your project’s needs. A description is shown under the dropdown.
Troubleshooting
- Python or
uvnot found: - Claude CLI not found:
Tips
- Use Cmd+Shift+M (macOS) / Ctrl+Shift+M (Windows, Linux) to toggle the MCP for Unity window.
- Enable “Show Debug Logs” in the header for more details in the Console when diagnosing issues.