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 more than one Unity Editor is connected, the server's auto-select gives up - it only auto-selects when exactly one editor is connected - and forces the caller to pass unity_instance on every call. There is no signal tying a client session to the editor it belongs to, which is painful for setups with several projects open at once, or multiple git worktrees of one project (identical project names, only the path differs).

This adds client-agnostic launch-directory routing: when several editors are connected, the server picks the one whose Unity project shares a path lineage with 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

  • unity_instance_middleware.py: when more than one instance is connected, resolve the launch directory and select the single instance whose project root shares a path lineage with it (contains / equals / is contained by). Only the existing ">1 instance, give up" branch changes; single-instance and explicit unity_instance selection are untouched, and no/ambiguous match keeps the current "ask the user" behavior.
  • Launch directory is resolved client-agnostically: the UNITY_MCP_PROJECT_DIR override, then the file:// MCP roots the client advertises (all of them), cached per session so a client is probed at most once.
  • file:// URI parsing (UNC hosts, percent-encoding, drive-aware) and project-root normalization (stdio reports .../Assets, HTTP the project root).
  • SessionDetails gains an optional project_path, populated by PluginHub.get_sessions, so the HTTP/plugin-hub path can match too. Backward compatible (defaults to None).
  • Tests: Server/tests/integration/test_instance_autoselect_by_launch_dir.py.

Compatibility / Package Source

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

Testing/Screenshots/Recordings

  • Python tests (cd Server && uv run pytest tests/ -v) - full suite 1249 passed, including the 22 cases in 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 were added or changed, so the generated tool reference is unaffected.

Related Issues

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

Additional Notes

  • The Unity EditMode/PlayMode/package-import items are not applicable: the change lives entirely in the Python server (transport middleware + models); no C#/Unity-side code is touched.
  • Manual end-to-end check: ran the patched selection path against real stdio discovery of two live editors (real on-disk project paths) and confirmed both roots- and UNITY_MCP_PROJECT_DIR-based routing select the correct instance, with ambiguity yielding no auto-selection.
  • Interaction note (pre-existing, not introduced here): on Linux/stdio, instance discovery is keyed by port, so two editors that bind the same port (SO_REUSEADDR) collapse to one. This routing relies on editors having distinct ports; the HTTP/plugin-hub path (keyed by hash) is unaffected.

Summary by CodeRabbit

  • New Features

    • Sessions now include an optional project-path field for clearer session context.
    • Improved automatic selection of active Unity instances by matching client launch directories, reducing ambiguous instance prompts.
  • Tests

    • Added integration and unit tests covering launch-directory parsing, instance auto-selection behavior, caching, environment override, and the new session project-path handling.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4b2f96d-a45b-4a58-963a-15051f6c7432

📥 Commits

Reviewing files that changed from the base of the PR and between c0908b8 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

📝 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
Title check ✅ Passed The title accurately summarizes the main feature: auto-selecting Unity instances based on launch directory to resolve multi-instance routing.
Description check ✅ Passed The description covers all required template sections: problem statement, type of change (new feature), detailed changes, compatibility notes, testing results, and additional context.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@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
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