Skip to content

Remove the stdio transport and the legacy TCP bridge - #38

Merged
vbucc merged 2 commits into
mainfrom
remove-stdio-transport
Jul 30, 2026
Merged

vbucc merged 2 commits into
mainfrom
remove-stdio-transport

Conversation

@vbucc

@vbucc vbucc commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Removes the stdio transport and the legacy framed TCP bridge it used to reach Unity. This fork only uses HTTP, and stdio was still the Python default — Server/Dockerfile and manifest.json both omitted --transport and inherited it, while Unity already defaulted UseHttpTransport = true. Net −9,000 lines across 29 deleted files.

Python

  • Delete Server/src/transport/legacy/ (unity_connection, port_discovery, stdio_port_registry). _extract_response_reason / _is_reloading_response are rescued into models/unity_response.py — the HTTP path still uses them.
  • Drop the send_fn escape hatch from send_with_unity_instance; it is now a single HTTP path. 60 files / 72 call sites.
  • Convert the four sites that bypassed the shim entirely (sync_tool_visibility_from_unity, script_apply_edits get_sha/read, the manage_script reload sentinel) rather than only dropping their imports — deleting those would have silently broken them.
  • --transport is retained, accepting only http, so client configs written by older packages keep working on upgrade.

Unity

  • Delete StdioBridgeHost (1134 lines), StdioTransportClient, StdioBridgeReloadHandler, PortManager. TransportManager collapses to one client; TransportMode goes.
  • Remove UseHttpTransport. With stdio gone, a stale false from a prior install would have silently disabled auto-start and reload-resume.
  • Remove ConfiguredTransport.Stdio. A leftover stdio config now reports MissingConfig so the UI prompts re-Configure, and StdIoVersionMigration → LegacyClientConfigMigration rewrites it on the next version bump. (Kept, not deleted — it is the only thing that migrates upgrading users off stdio.)

Test harness

tools/local_harness.py drove Unity entirely over the TCP bridge, so it is ported to HTTP: it starts its own MCP server, boots Unity against it via McpCiBoot.StartHttpForCi, discovers the instance through /api/instances, and sends through /api/command.

Port isolation — 8080 is the everyday local server port, and Unity's StartLocalHttpServer terminates whatever process owns the port it is about to bind. The harness therefore:

  • never binds 8080 or $UNITY_MCP_HTTP_PORT (--http-port 8080 is a hard exit 2);
  • points its Editor at its own server with the UNITY_MCP_HTTP_URL env override rather than EditorPrefs, which are shared machine-wide per Unity version;
  • no longer sets UNITY_MCP_ALLOW_BATCH, the flag that lets a batch Editor reach StopLocalHttpServerInternal at all;
  • starts and stops only the server process it spawned.

Verified across seven runs against a live 8080 server — including one killed mid-flight and one where another Unity project connected to 8080 concurrently. The listener PID never changed and /health stayed 200.

Four bugs in the port were found only by running it end-to-end: /api/instances field names, a blocked main thread in McpCiBoot (Unity registered but could not execute), the /api/command envelope colliding with the UTF job status in _poll_utf, and missing reload retry (/api/command routes to PluginHub.send_command, which has no retry wrapper, while the UTF legs trigger domain reloads).

Also

  • Delete e2e-bridge.yml and claude-nl-suite.yml — both pinned to a 2021.3 container that cannot open this 6.5 project, so both were already unrunnable. claude-nl-suite.yml was workflow_dispatch-only and gated nothing.
  • Delete tools/stress_*.py — they implement the deleted framed socket protocol directly.
  • Docs: CLAUDE.md, Server/README.md, the transports page, install/clients/guides, zh translations, the homepage cards, the bug-report template.
  • Regenerate website/docs/reference/ — this drift is pre-existing on main (verified in a clean worktree); CI's docs-generate check runs because this PR touches Server/src/services/**, so it had to be fixed here.

Gate

  • Python: 1502 passed, 3 skipped.

  • Harness unit tests: 139 passed (including 18 for port isolation, 7 for reload retry, 6 for envelope handling).

  • Unity compile (6000.5.5f1): pass.

  • Unity EditMode, native -runTests: pass.

  • Harness smoke leg: 7/7, exit 0.

  • Harness EditMode leg: 3 failures, all pre-existing —

    EditorStateCache_IsChanging_TracksTransitionWindowNotWholeSession
    ReadConsoleTests.HandleCommand_Get_PreservesMultilineMessageBody
    ReadConsoleTests.HandleCommand_Get_Works
    

    Proven two independent ways: Unity's native runner (no MCP transport at all) passes all three, and running unmodified origin/main with its original stdio harness in a separate worktree produces a character-identical failure set. They are artifacts of driving tests through an MCP run_tests job — the activity phase reads running_tests, and the console carries session traffic — and they predate this change. Not fixed here; they are unrelated to stdio and would block any Unity-touching PR.

🤖 Generated with Claude Code

vbucc and others added 2 commits July 30, 2026 18:59
This fork only uses HTTP. Deletes the second, parallel transport stack:
stdio on the Python side and the framed TCP bridge it used to reach Unity.

Python:
- Delete Server/src/transport/legacy/ (unity_connection, port_discovery,
  stdio_port_registry). Rescue _extract_response_reason / _is_reloading_response
  into models/unity_response.py, which the HTTP path still needs.
- Drop the send_fn escape hatch from send_with_unity_instance; it is now a
  single HTTP path. Sweeps 60 files / 72 call sites.
- Convert the four sites that bypassed the shim entirely
  (sync_tool_visibility_from_unity, script_apply_edits get_sha/read, the
  manage_script reload sentinel) rather than only dropping their imports.
- Keep --transport, accepting only "http", so client configs written by older
  packages keep working on upgrade.

Unity:
- Delete StdioBridgeHost, StdioTransportClient, StdioBridgeReloadHandler,
  PortManager. Collapse TransportManager to one client and drop TransportMode.
- Remove UseHttpTransport: with stdio gone a stale `false` from a prior install
  would have silently disabled auto-start and reload-resume.
- Remove ConfiguredTransport.Stdio. A leftover stdio config now reports
  MissingConfig so the UI prompts re-Configure, and StdIoVersionMigration ->
  LegacyClientConfigMigration rewrites it on the next version bump.

Test harness (tools/local_harness.py):
- Port from the TCP bridge to HTTP: the harness starts its own MCP server,
  boots Unity against it via McpCiBoot.StartHttpForCi, discovers the instance
  through /api/instances and sends through /api/command.
- Port isolation: never binds 8080 or $UNITY_MCP_HTTP_PORT, points its Editor
  at its own server with the UNITY_MCP_HTTP_URL env override (EditorPrefs are
  machine-wide, so writing them would repoint the developer's Editor), and no
  longer sets UNITY_MCP_ALLOW_BATCH — the flag that lets a batch Editor reach
  StopLocalHttpServerInternal, which terminates whatever owns the target port.
- Scope UNITY_MCP_HTTP_URL to GetBaseUrl (the connection path), never
  GetLocalBaseUrl, so it cannot steer local-server management decisions.
- Unwrap the /api/command envelope: its outer "status" collided with the UTF
  job status and made _poll_utf poll forever.
- Own reload retries: /api/command routes to PluginHub.send_command, which has
  no retry wrapper, and the UTF legs trigger domain reloads.

Also: delete e2e-bridge.yml and claude-nl-suite.yml (both pinned to a 2021.3
container that cannot open this 6.5 project) and tools/stress_*.py (they
implement the deleted framed protocol directly); update docs; regenerate the
reference pages, which were already stale on origin/main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vbucc
vbucc merged commit ea42663 into main Jul 30, 2026
1 check passed
@vbucc
vbucc deleted the remove-stdio-transport branch July 30, 2026 23:04
@vbucc

vbucc commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

Correction: the gate note above is wrong where it says Unity's native runner passes all three pre-existing failures. It passes only EditorStateCache_IsChanging.

The two ReadConsoleTests failures were never MCP-specific — they reproduce under the plain -batchmode -nographics -runTests runner with no MCP involvement at all (native full suite at that commit: 1039 tests, 972 passed, 2 failed, exactly those two). Unity does not record a log emitted inside a Test Framework test into the console's LogEntries buffer when headless, so those tests only ever passed in a GUI editor. HandleCommand_Clear_Works was passing only by luck, on log entries left by unrelated tests; it failed as soon as the class was run alone.

All three are fixed in #41 (b3ece1b0). The native suite is now 0 failures and the harness gate is green with no documented exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant