IvanMurzak / IvanMurzak/Unity-MCP

unity-mcp-cli derives the local port with ProjectIdentity v1 while the plugin uses v2 — status/wait-for-ready probe the wrong port on Windows

Open Beginner friendly
#970 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
4.3k
Forks
379
Avg merge
6h 52m
Merged PRs (30d)
17

Description

Summary

unity-mcp-cli derives the deterministic local port with the v1 ProjectIdentity
algorithm, while the Unity plugin and setup-mcp use v2. On Windows the two disagree,
because v1 does not normalise \ to /. Five CLI code paths therefore probe a port nothing
is listening on.

The runtime path (agent ↔ broker ↔ Editor) is unaffected — only the CLI's own diagnostics
and wait-for-ready are, which is probably why this has gone unnoticed.

Environment

unity-mcp-cli 0.90.0
com.ivanmurzak.unity.mcp 0.90.0
gamedev-mcp-server 9.2.5
Unity 6000.5.1f1
OS Windows 11 (10.0.26200)
Node v24.16.0

Reproduction

With a Unity project at C:\Users\admin\Documents\GitHub\LumberJack, the Editor open, and the
broker healthy on port 27244:

> unity-mcp-cli status .

Unity Editor Process
SUCCESS: Unity is running (PID: 61456)

Local MCP Server
  URL: http://localhost:28268
Probing http://localhost:28268...
ERROR: Not available (connection refused)

Config Server
  URL: http://localhost:27244
Probing http://localhost:27244...
SUCCESS: Connected

28268 is the v1 port; 27244 is the v2 port that the plugin and setup-mcp actually use.
Passing a forward-slash path does not help — resolveProjectPath runs path.resolve() and
converts the separators back.

wait-for-ready is the worse symptom: it polls the v1 port and times out while the Editor and
broker are up and healthy.

> unity-mcp-cli wait-for-ready . --timeout 540000
Waiting for Unity Editor and MCP server...
ERROR: Timed out after 540.0s waiting for MCP server

Root cause

dist/utils/port.js re-exports the v1 functions under the names the rest of the CLI
imports:

export { derivePin as deriveProjectPin, derivePort as generatePortFromDirectory, normalize as normalizeProjectRoot, } from '@baizor/gamedev-cli-core';

Five consumers take the v1 port from it:

  • dist/commands/status.js:18
  • dist/commands/wait-for-ready.js:18
  • dist/lib/run-tool.js:182 (fallback URL)
  • dist/utils/config.js:12
  • dist/utils/connection.js:62

Meanwhile @baizor/gamedev-cli-core/dist/setup-mcp.js:127 uses derivePortV2, and the Unity
plugin's UnityMcpPlugin.GeneratePortFromDirectory uses ProjectIdentity.DerivePortV2.

status.js compares its derived localUrl against the config URL and hides the second
section when they match — so the mismatch also makes that consistency check permanently
report a false discrepancy on Windows.

Note that status.js calls generatePortFromDirectory(projectPath) directly rather than
deriveProjectIdentity(projectRoot, portOverride), so a .ai-game-dev/project.json port
override cannot work around it either.

Why v2 is the intended side

This looks like an incomplete migration rather than a deliberate split:

  • #882 (2026-07-14, CLI) aligned generatePortFromDirectory with ProjectIdentity
    because it "could derive a different port than the plugin's canonical ProjectIdentity".
    At that point the canonical algorithm was v1.
  • #904 / #905 (2026-07-18, plugin) landed defect B10, moving the plugin to the v2
    normalisation "so the port stays in lock-step with the routing pin".

The CLI side was never brought forward the four days to match.

The plugin's own Tests/Editor/Auth/PortDerivationV2Tests.cs commits the golden vectors:

path expected port
C:\Users\user\my-game 24298
C:\Users\user\my-game\ 24298
C:/Users/user/my-game 24298
/home/user/my-game 23940

An independent implementation of the documented algorithm reproduces all of them, and
reproduces 28268 for the v1 path of the project above — so the divergence is exactly the
v1/v2 seam and nothing else.

Suggested fix

Point the historical names at v2 in utils/port.js, which fixes all five consumers at once:

export { derivePinV2 as deriveProjectPin, derivePortV2 as generatePortFromDirectory, normalizeV2 as normalizeProjectRoot, } from '@baizor/gamedev-cli-core';

v1 and v2 are identical for paths without backslashes, so this is a no-op on macOS/Linux.

If v1 must stay reachable for the golden-vector parity tests, importing derivePortV2
directly at the five call sites works equally well.

A CI check that asserts the CLI and the plugin agree for a Windows-style path would stop this
seam from reopening.

Workaround

For anyone hitting this before a release: patching that single line locally restores
status, wait-for-ready, and run-tool. I put the patch script, the golden-vector tests,
and setup notes in https://github.com/duckxy166/unity-mcp-connect — happy to open a PR here
instead if you'd prefer the fix upstream.

Thanks for the project — the broker-as-separate-process design surviving domain reloads is
genuinely the right call.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with dist/utils/port.js and compare its exported functions with the v2 exports used by @baizor/gamedev-cli-core/dist/setup-mcp.js. Check the five listed CLI consumers, then run or add coverage using the Windows-style vectors from Tests/Editor/Auth/PortDerivationV2Tests.cs. Done means status, wait-for-ready, run-tool, config, and connection derive the same port as the Unity plugin on Windows.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, javascript, node.js, unity
Domain
cli, game-dev, testing-qa
Issue type
Bug
Difficulty
2/5
Estimated time
Half a day
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.