Skip to content

feat: auto-select Unity instance by launch directory#1194

Open
imurashka wants to merge 1 commit into
CoplayDev:betafrom
imurashka:feat/autoselect-instance-by-launch-dir
Open

feat: auto-select Unity instance by launch directory#1194
imurashka wants to merge 1 commit into
CoplayDev:betafrom
imurashka:feat/autoselect-instance-by-launch-dir

Conversation

@imurashka

@imurashka imurashka commented Jun 8, 2026

Copy link
Copy Markdown

Description

When several Unity editors are connected the server only auto-selects one if exactly one is open. With more than one it gives up and you have to pass unity_instance on every call. This happens often when the Unity project is not at the repo root, or when you run several projects at once, or git worktrees of one project. Worktrees share the same project name and differ only by path, so name alone cannot tell them apart.

This PR picks the editor that matches the directory the client is working in.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Test update

Changes Made

The whole change lives in the selection middleware. The old code gave up in the "more than one instance" branch of _maybe_autoselect_instance. That branch now tries to resolve a single editor before giving up.

  • unity_instance_middleware.py: in the "more than one instance" branch, select the editor whose project path shares a path lineage with the client launch directory. The single instance path and the explicit unity_instance path are untouched. No match or an ambiguous match keeps the current "ask the user" behavior.
  • The launch directory is resolved client-agnostically. UNITY_MCP_PROJECT_DIR wins if set, otherwise the file:// MCP roots the client advertises. The result is cached per session so the client is queried at most once.
  • Added file:// URI parsing (UNC hosts, percent-encoding, Windows drive letters) and project-root normalization. Over stdio Unity reports the Assets folder, over HTTP the project root.
  • models.py and plugin_hub.py: SessionDetails gets an optional project_path so the HTTP path can match too. It defaults to None, so this is backward compatible.
  • Added Server/tests/integration/test_instance_autoselect_by_launch_dir.py.

Compatibility / Package Source

  • Unity version(s) tested: not applicable, no C#/Unity code changed. Verified against running Unity 6000.4 editors over stdio.
  • Package source used (#beta, #main, tag, branch, or file:): not applicable, no Unity package change. Branch is off beta.
  • Resolved commit hash from Packages/packages-lock.json: not applicable.

Testing/Screenshots/Recordings

  • Python tests (cd Server && uv run pytest tests/ -v), full suite passes including the new file.
  • Unity EditMode tests
  • Unity PlayMode tests
  • Package import/compile check
  • Not applicable (explain why in Additional Notes)

Documentation Updates

  • I have added/removed/modified tools or resources

No tools or resources changed, so the generated tool reference is not affected.

Related Issues

Relates to the multi-instance routing item under "Areas That Need Help" in CONTRIBUTING. Independent of #1121, which hardens discovery and auto-start. This PR only changes the selection middleware.

Additional Notes

  • Manual check: ran the selection path against two live editors over stdio. Both the roots-based and the UNITY_MCP_PROJECT_DIR-based routing pick the right editor, and an ambiguous case picks nothing.
  • Pre-existing note, not introduced here: on Linux over stdio, discovery is keyed by port, so two editors that bind the same port collapse to one. This routing needs editors on distinct ports. The HTTP path is keyed by hash and is not affected.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds launch-directory-aware Unity instance auto-selection: SessionDetails.project_path, file:// URI parsing and Unity root normalization, per-session launch-dir caching, and selection integration for PluginHub and stdio discovery, with comprehensive unit and integration tests.

Changes

Unity Instance Auto-selection via Launch Directory Matching

Layer / File(s) Summary
SessionDetails contract and integration
Server/src/transport/models.py, Server/src/transport/plugin_hub.py, Server/tests/integration/test_instance_autoselect_by_launch_dir.py
SessionDetails gains an optional project_path field; PluginHub populates it from session metadata when building the response; tests confirm default None and backward compatibility.
Path handling utilities and per-session caching
Server/src/transport/unity_instance_middleware.py, Server/tests/integration/test_instance_autoselect_by_launch_dir.py
Adds imports for URI parsing; helpers convert file:// URIs to filesystem paths (POSIX, UNC, drive-aware, percent-decoding) and normalize Unity project roots by stripping trailing /Assets; adds per-session cache for resolved launch directories and unit tests for parsing and helpers.
Core instance selection and launch directory resolution
Server/src/transport/unity_instance_middleware.py, Server/tests/integration/test_instance_autoselect_by_launch_dir.py
New methods resolve launch directories via UNITY_MCP_PROJECT_DIR or MCP roots, select a single instance by path-lineage matching, cache probes per session, and include unit/integration tests for matching, ambiguity, multi-root, and caching behaviors.
PluginHub transport: candidate construction and auto-selection
Server/src/transport/unity_instance_middleware.py
PluginHub discovery now includes reported project_path in candidates; when multiple instances exist, middleware attempts launch-directory-based disambiguation (and persists the choice) prior to the previous multiple-instance flow; covered by end-to-end tests.
Stdio transport: candidate construction and auto-selection
Server/src/transport/unity_instance_middleware.py
Stdio discovery builds (id, path) candidate pairs and applies the same launch-directory disambiguation and persistence before falling back to the existing user-choice flow.
End-to-end integration tests
Server/tests/integration/test_instance_autoselect_by_launch_dir.py
End-to-end tests cover env var precedence (UNITY_MCP_PROJECT_DIR), use of MCP roots when env is absent, caching semantics, project-path normalization across transport modes, and PluginHub integration.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble paths and strip the trailing bits,
Decode file:// hops and follow Unity's wits,
When multiple instances jumble the lane,
Launch-dir lineage shows which to claim—
I cache the choice and hop away, triumphant, not vain.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 97.73% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately reflects the main change: auto-selecting a Unity instance by launch directory.
Description check ✅ Passed The description follows the template and includes the required sections with substantive details on changes, compatibility, testing, and notes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@imurashka imurashka force-pushed the feat/autoselect-instance-by-launch-dir branch 4 times, most recently from 87aa320 to 4e009c7 Compare June 8, 2026 14:00
@imurashka

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@imurashka

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@imurashka

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@imurashka imurashka force-pushed the feat/autoselect-instance-by-launch-dir branch from 4e009c7 to 3617b75 Compare June 8, 2026 14:51
@imurashka

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Server/src/transport/unity_instance_middleware.py`:
- Around line 272-280: The current _client_root_dirs logic double-fetches under
concurrency; modify it to memoize the in-flight fetch per key instead of only
storing the final dirs after await: inside _client_root_dirs (use
get_session_key, _root_dirs_by_key, _lock and _fetch_client_root_dirs) acquire
the lock, check for an existing entry and return if present, and if missing
create and store a placeholder future/task for that key before releasing the
lock; then await the actual _fetch_client_root_dirs, resolve the placeholder
with the result and replace it with the real dirs; ensure exceptions clear the
placeholder so subsequent calls can retry.
- Around line 327-345: The selector currently skips candidates with missing
project_path and may still auto-select a single match; change the logic so that
if there is more than one candidate and any candidate has a missing or falsy
project_path, the function treats the set as ambiguous and returns None instead
of auto-selecting. Concretely, before the matching loop or before returning a
single match, check the candidates list for more than one entry and for any
inst_id whose project_path is falsy; if found, return None; otherwise proceed
with the existing _strip_assets/project_real/commonpath matching that populates
matches and the existing matches==1 return behavior. Ensure this uses the
existing variables candidates, project_path, matches, _strip_assets, and
launch_reals so the change is local and minimal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da8dd5e3-4aab-4020-95bf-ad14f04bf876

📥 Commits

Reviewing files that changed from the base of the PR and between 4e009c7 and 3617b75.

📒 Files selected for processing (4)
  • Server/src/transport/models.py
  • Server/src/transport/plugin_hub.py
  • Server/src/transport/unity_instance_middleware.py
  • Server/tests/integration/test_instance_autoselect_by_launch_dir.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • Server/src/transport/models.py
  • Server/src/transport/plugin_hub.py
  • Server/tests/integration/test_instance_autoselect_by_launch_dir.py

Comment thread Server/src/transport/unity_instance_middleware.py
Comment thread Server/src/transport/unity_instance_middleware.py
@imurashka

Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

When several Unity editors are connected, auto-select gave up at ">1 instance"
and forced the caller to pass unity_instance on every call. Worktrees made it
worse: identical project names, only the path differs.

Resolve the directories the client is working in - client-agnostic, via the
package's own UNITY_MCP_PROJECT_DIR or the file:// MCP roots the client
advertises (all of them) - and pick the single connected editor whose project
shares a path lineage with one of them. Candidate paths are normalized to the
project root (stdio reports .../Assets, HTTP the root) before matching, and the
roots lookup is cached per session to keep the no-match path off the wire.
Surface project_path on SessionDetails so the PluginHub path can match too.

Purely additive: only the existing ">1 instance, give up" branch changes;
single-instance and explicit selection are untouched, and no/ambiguous match
keeps the "ask the user" behavior.
@imurashka imurashka force-pushed the feat/autoselect-instance-by-launch-dir branch from 3617b75 to 3e38a06 Compare June 8, 2026 18:07
@imurashka

Copy link
Copy Markdown
Author

@coderabbitai full review

@imurashka imurashka marked this pull request as ready for review June 8, 2026 18:19

@jordandunmire97-ai jordandunmire97-ai left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow I love this .13 days from now I won't be here physically in this realm. Hopefully when I am back I am a bird . With that . Also why I am approving it myself. And no im not sad. Its very hard to explain
. Don't worry. Never one has . Thank you so much for what you have done .

@imurashka

Copy link
Copy Markdown
Author

Hi @Scriptwonder, when you have a moment, would you be able to take a look at this PR? Happy to adjust anything if needed. Thanks!

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.

2 participants