fix(server): play-mode busy-state, auth-token rotation 401, dropped rapid clicks, and background responsiveness#171
Merged
Daliys merged 10 commits intoJul 24, 2026
Conversation
…t for local test suites
IsPlayModeTransitionCached used EditorApplication.isPlayingOrWillChange- Playmode, which stays true for the entire play session rather than just the transition. As a result get_server_status reported busyReason= play_mode_transition for the whole session, acceptsWriteCommands stayed false, and initialize() threw "editor is busy" the entire time the game ran — write commands and readiness checks were unusable in play mode. A transition is in progress only while isPlayingOrWillChangePlaymode and isPlaying disagree (entering: will-change but not yet playing; exiting: still playing but no longer will-change). Compare the two flags instead. Verified in play mode: busyReason=idle, acceptsWriteCommands=true, initialize() succeeds. Play-mode entry detection dropped 90s -> ~4.5s. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
simulate_mouse / click_object_in_game defer the button release ~100ms so the press is observably held for at least one frame. A second click issued inside that window queued its press while the button was still down, so it produced no press edge and was silently lost — no error, nothing in logs. Track the pending release and flush it before starting a new click, so back-to-back clicks each register as a distinct press. Reproduced: at 0ms gap the second click vanished; at >=150ms both landed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_transport resolved AUTH_TOKEN once at import. Unity rewrites Library/NexusUnityAuthToken.txt on every domain reload, so the cached token goes stale the moment a script compiles and every authenticated method returns HTTP 401 for the rest of the session — while get_server_status keeps returning 200 (it is auth-exempt), which reads to a caller as "the editor never came back". The 401 was also reported as "Unity Server unreachable", sending debugging the wrong way. Re-read the token file and retry once on 401 (the first attempt keeps the import-time token), and report a 401 as an auth failure rather than as unreachable. Multi-file apply_code_change went from a 90s timeout to ~8.6s. Adds test_transport coverage for the 401 retry and the auth-failure message. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nction) No behavior change — verified by the full integration suite (355 checks) and the package unit tests (38). - MCPServer.cs (386L): split identity/version + auth-token methods into MCPServer.Identity.cs, and the server lifecycle (Start/Stop/Cleanup) into MCPServer.Networking.cs. Init and Start broken into focused helpers. - MCPServer.Networking.cs (312L, one function miscounted at 296): split HTTP/ WebSocket handling into MCPServer.Http.cs; broke IsAnotherMcpInstanceRunning and HandleHttpRequest into helpers. Moved the loopback URL to its own line (LoopbackUrl) so no brace ever shares a line with a "http://" literal — the gate strips comments before strings and mistook the "//" in the URL for a line comment, dropping trailing braces and inflating the function's length. - MCPServerMethods.Snapshot.cs: extracted helpers from SerializeSceneNode and GetSceneDependencies. - nexus_unity_bridge.py: extracted _handle_rpc_request / _handle_tool_call / _run_cli_mode from main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Started as an auth-token / domain-reload / app-nap fix. While hardening the
real-time integration test suite that exercises this server, the suite surfaced
three additional server bugs that this PR now also fixes. All three are
verified against a live editor (Unity 6000.4.3f1) and covered by tests.
Fixes in this PR
1. Auth token resolution & background responsiveness (original scope)
Library/NexusUnityAuthToken.txtwith a sanefallback, and enable
Application.runInBackground+AppNapBypassinInit()so the server stays responsive when Unity is backgrounded.2.
isPlayModeTransitionnever cleared during play modeIsPlayModeTransitionCachedusedEditorApplication.isPlayingOrWillChange- Playmode, which staystruefor the entire play session, not just thetransition. Consequences while the game was running:
get_server_statusreportedbusyReason: play_mode_transitionthe whole timeacceptsWriteCommandswas false for all of play modeinitialize()threw "editor is busy" until you left play modeFixed by treating a transition as "in progress" only while
isPlayingOrWillChangePlaymode != isPlaying. Verified in play mode:busyReason: idle, writes accepted,initialize()succeeds. Play-mode entrydetection dropped ~90s → ~4.5s.
3. Auth token rotates on domain reload → permanent HTTP 401
The Python bridge (
nexus_bridge/_transport.py) resolved the token once atimport. Unity rewrites the token file on every domain reload, so after the
first script compile every authenticated method returned 401 for the rest of
the session — while
get_server_statuskept returning 200 (it isauth-exempt), which reads to a client as "the editor never came back". The
401 was even reported as "Unity Server unreachable", misdirecting debugging.
Fixed: re-read the token file and retry once on 401 (first attempt keeps the
import-time token), and report a 401 as an auth failure, not as unreachable.
apply_code_changeon multiple files went from a 90s timeout → ~8.6s.New
test_transportcases pin the retry and the error message.4. Rapid clicks silently dropped
simulate_mouse/click_object_in_gamedefer the button release ~100ms sothe press is held for a frame. A second click issued inside that window queued
its press while the button was still down — no press edge, so it was silently
lost with no error. Fixed by flushing any pending release before starting a
new click. Reproduced: at 0ms gap the second click vanished; at ≥150ms both
landed.
Testing
Editor/tests/) pass, including the new 401-retry cases.(11 suites / 345 named checks) that lives in the consuming project repo. That
suite is not part of this package PR; it is tracked separately. Highlights
of what it exposed and now guards against are the three server bugs above.
Closes #71