Skip to content

Conversation

@msanatan
Copy link
Contributor

@msanatan msanatan commented Nov 27, 2025

We fix the auto-reconnect logic for stdio. That is, if you're connected via stdio, and you reload the domain, then you'll still be connected via stdio. Similar to our websocket connection

Summary by CodeRabbit

  • Bug Fixes

    • More reliable resume behavior across editor reloads; active connections are preserved and validated per-transport (HTTP vs stdio).
  • Refactor

    • Transport management reworked to track and operate on each transport mode independently, improving start/stop, verification, and state accuracy.
  • New Features

    • Added resume-after-reload support for legacy stdio so it can be restarted automatically when appropriate.

✏️ Tip: You can customize this high-level summary in your review settings.

@msanatan msanatan self-assigned this Nov 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Walkthrough

Refactors transport management to per-transport (HTTP and Stdio) state and mode-aware APIs, adds a persistent ResumeStdioAfterReload preference, introduces a StdioBridgeReloadHandler to manage stdio across assembly reloads, and updates callers to use TransportManager with explicit TransportMode.

Changes

Cohort / File(s) Summary
EditorPrefKeys
MCPForUnity/Editor/Constants/EditorPrefKeys.cs
Added internal const string ResumeStdioAfterReload = "MCPForUnity.ResumeStdioAfterReload";.
TransportManager infrastructure
MCPForUnity/Editor/Services/Transport/TransportManager.cs
Reworked to per-transport clients and states (_httpClient, _stdioClient, _httpState, _stdioState); added mode-aware APIs (StartAsync(TransportMode), StopAsync(TransportMode?), VerifyAsync(TransportMode), GetState(TransportMode), IsRunning(TransportMode)); deprecated single-transport accessors return null.
Service layer updates
MCPForUnity/Editor/Services/BridgeControlService.cs, MCPForUnity/Editor/Services/HttpBridgeReloadHandler.cs
Replaced Bridge usage with TransportManager mode-aware calls; resolve preferred mode before transport operations; updated start/stop/verify flows to pass explicit TransportMode.
Stdio transport reload handler
MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs, MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta
New static editor-on-load handler that subscribes to assembly reload events, persists ResumeStdioAfterReload in EditorPrefs, stops only stdio before reload (when appropriate), and restarts/verifies stdio after reload. Added Unity .meta for the new file.
Transport implementation cleanup
MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
Removed assembly-reload event hookups, shouldRestartAfterReload flag and associated handlers; reload-resume logic moved to new StdioBridgeReloadHandler.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Editor as Unity Editor
    participant Before as BeforeReload (AssemblyReloadEvents.before)
    participant StdioHandler as StdioBridgeReloadHandler
    participant EditorPrefs as EditorPrefs
    participant TransportMgr as TransportManager
    participant Stdio as Stdio Bridge
    participant After as AfterReload (AssemblyReloadEvents.after)
    participant Window as MCPForUnityEditorWindow

    Editor->>Before: beforeAssemblyReload
    Before->>StdioHandler: onBeforeAssemblyReload()
    StdioHandler->>TransportMgr: Query IsRunning(Stdio) & IsHttpInUse()
    alt stdio running && http not in use
        StdioHandler->>EditorPrefs: Set ResumeStdioAfterReload = true
        StdioHandler->>TransportMgr: StopAsync(Stdio)
        TransportMgr->>Stdio: Stop transport client
    else
        StdioHandler->>EditorPrefs: Clear ResumeStdioAfterReload
    end

    Editor->>After: afterAssemblyReload
    After->>StdioHandler: onAfterAssemblyReload()
    StdioHandler->>EditorPrefs: Read ResumeStdioAfterReload
    StdioHandler->>TransportMgr: Query IsHttpInUse()
    alt resume conditions met
        StdioHandler->>EditorPrefs: Clear ResumeStdioAfterReload
        StdioHandler->>TransportMgr: StartAsync(Stdio)
        TransportMgr->>Stdio: Start transport client
        StdioHandler->>Window: Request health verification
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on: per-mode state transitions and their atomicity in TransportManager.
  • Verify all callers were updated to mode-aware APIs (e.g., BridgeControlService, reload handlers).
  • Confirm EditorPrefs flag correctness and race conditions across assembly reloads.
  • Check StdioBridgeHost removal of reload logic doesn't leave gaps in lifecycle handling.

Suggested reviewers

  • Scriptwonder

Poem

🐰
I hopped through reloads, tiny and spry,
Saved a stdio flag so connections won't die.
HTTP and Stdio now mind their own lanes,
Restarted with care after domain rains.
Hooray — the rabbit cheers for stable trains! 🚆

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix stdio reloads' directly addresses the main objective of fixing auto-reconnect logic for stdio connections after domain reloads, which is the primary change across the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcae2c6 and caf89ee.

📒 Files selected for processing (3)
  • MCPForUnity/Editor/Services/BridgeControlService.cs (4 hunks)
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (1 hunks)
  • MCPForUnity/Editor/Services/Transport/TransportManager.cs (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-13T13:27:23.040Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
📚 Learning: 2025-09-03T16:00:55.839Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 0
File: :0-0
Timestamp: 2025-09-03T16:00:55.839Z
Learning: ComponentResolver in UnityMcpBridge/Editor/Tools/ManageGameObject.cs is a nested static class within ManageGameObject, not a sibling type. The `using static MCPForUnity.Editor.Tools.ManageGameObject;` import is required to access ComponentResolver methods directly without the outer class qualifier.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
🧬 Code graph analysis (2)
MCPForUnity/Editor/Services/BridgeControlService.cs (2)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (1)
  • IsRunning (132-132)
MCPForUnity/Editor/Services/IBridgeControlService.cs (2)
  • BridgeVerificationResult (47-47)
  • BridgeVerificationResult (60-81)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (1)
MCPForUnity/Editor/Services/BridgeControlService.cs (4)
  • TransportMode (25-30)
  • Task (80-97)
  • Task (99-110)
  • Task (112-118)
🔇 Additional comments (18)
MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (4)

16-20: LGTM!

The static constructor correctly subscribes to assembly reload events using the [InitializeOnLoad] attribute pattern.


56-81: LGTM!

The resume logic correctly validates the flag against current HTTP usage, includes appropriate error handling, and uses an early return pattern for clarity.


83-102: LGTM!

The restart logic appropriately uses fire-and-forget async (allowing the reload to complete first), includes comprehensive error handling for both faulted tasks and startup failures, and triggers health verification on success.


36-43: Potential race condition with fire-and-forget StopAsync.

The async StopAsync call is not awaited because Unity's beforeAssemblyReload is synchronous. However, this means the assembly reload may proceed before the stdio bridge has fully stopped, potentially leaving the transport in an inconsistent state or causing resource cleanup issues.

Consider whether this is acceptable given Unity's reload constraints. If similar patterns exist in HttpBridgeReloadHandler, this may be an architectural limitation rather than a bug. Verify that this fire-and-forget approach doesn't cause issues in practice and that proper cleanup happens when the reload completes.

MCPForUnity/Editor/Services/BridgeControlService.cs (6)

52-59: LGTM!

The property correctly resolves the preferred mode and delegates to the mode-aware TransportManager.IsRunning(mode) API.


61-75: LGTM!

The property correctly migrates to mode-aware state retrieval while preserving a legacy fallback for backward compatibility.


78-78: LGTM!

The property correctly adapts to the deprecated TransportManager.ActiveMode by resolving the preferred mode locally.


80-97: LGTM!

The method correctly passes the resolved mode to TransportManager.StartAsync(mode) while preserving existing error handling.


99-110: LGTM!

The method correctly passes the resolved mode to TransportManager.StopAsync(mode) while preserving error handling.


112-136: LGTM!

Both VerifyAsync and Verify correctly adopt mode-aware APIs while preserving the special stdio port validation logic.

MCPForUnity/Editor/Services/Transport/TransportManager.cs (8)

13-16: LGTM!

The refactoring to per-mode state with separate HTTP and Stdio clients enables proper concurrent transport operation and is initialized correctly.


38-56: LGTM!

The helper methods cleanly separate client creation (GetOrCreateClient) from retrieval (GetClient), use appropriate switch expressions, and include proper exception handling for unsupported modes.


108-120: LGTM!

The method correctly handles null clients and updates per-mode state after verification. The required TransportMode parameter is a breaking change, but all observed callers have been updated.


122-132: LGTM!

Both GetState and IsRunning correctly implement per-mode state retrieval using clean switch expressions.


134-147: LGTM!

The private UpdateState helper centralizes per-mode state updates with appropriate validation and exception handling.


27-28: I'm unable to verify the review comment at this time due to a repository access issue. The repository clone operation failed, preventing me from executing shell scripts to search for usages of the ActiveTransport and ActiveMode properties.

Cannot verify breaking change claims without codebase access.

The review comment asserts that:

  1. ActiveTransport and ActiveMode return null
  2. All callers (e.g., BridgeControlService) have been updated
  3. No other code in the codebase relies on these deprecated properties

However, I cannot confirm these claims through codebase analysis. The shell script that would search for remaining usages of these properties could not execute due to repository access failure.


81-106: Unable to verify the behavioral change claim—repository access failed.

The review comment flags that StopAsync(null) now stops both transports instead of just the active one. However, I cannot verify this claim because the repository failed to clone, preventing me from:

  • Locating all callers of StopAsync() without arguments
  • Checking whether existing call sites expect single or dual transport stops
  • Confirming this is actually a breaking behavioral change

The concern in the review is valid and warrants verification by examining the codebase directly, but I cannot complete this verification at this time.


58-79: Unable to verify breaking change claim due to repository access issue.

The repository could not be cloned to verify the breaking change. Without access to the codebase, I cannot confirm whether all callers of StartAsync have been updated to pass the new mode parameter. The review comment's claim that "all observed callers have been updated" requires confirmation against actual call sites throughout the codebase.

The logic in the method itself appears sound (proper failure handling, state updates, cleanup), but the breaking change verification cannot be completed.


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (3)

29-42: Consolidate duplicate condition check.

The condition !useHttp && isRunning is evaluated twice (lines 29 and 38). Consider consolidating into a single block.

-                if (!useHttp && isRunning)
-                {
-                    EditorPrefs.SetBool(EditorPrefKeys.ResumeStdioAfterReload, true);
-                }
-                else
-                {
-                    EditorPrefs.DeleteKey(EditorPrefKeys.ResumeStdioAfterReload);
-                }
-
-                if (!useHttp && isRunning)
-                {
-                    // Stop only the stdio bridge; leave HTTP untouched if it is running concurrently.
-                    MCPServiceLocator.TransportManager.StopAsync(TransportMode.Stdio);
-                }
+                bool shouldResume = !useHttp && isRunning;
+                if (shouldResume)
+                {
+                    EditorPrefs.SetBool(EditorPrefKeys.ResumeStdioAfterReload, true);
+                    // Stop only the stdio bridge; leave HTTP untouched if it is running concurrently.
+                    MCPServiceLocator.TransportManager.StopAsync(TransportMode.Stdio);
+                }
+                else
+                {
+                    EditorPrefs.DeleteKey(EditorPrefKeys.ResumeStdioAfterReload);
+                }

38-42: Consider adding error handling for the async stop operation.

StopAsync is called fire-and-forget, so exceptions won't be caught by the surrounding try-catch. For consistency with HttpBridgeReloadHandler (lines 41-48), consider using ContinueWith to log errors.

                 if (!useHttp && isRunning)
                 {
                     // Stop only the stdio bridge; leave HTTP untouched if it is running concurrently.
-                    MCPServiceLocator.TransportManager.StopAsync(TransportMode.Stdio);
+                    var stopTask = MCPServiceLocator.TransportManager.StopAsync(TransportMode.Stdio);
+                    stopTask.ContinueWith(t =>
+                    {
+                        if (t.IsFaulted && t.Exception != null)
+                        {
+                            McpLog.Warn($"Error stopping stdio bridge before reload: {t.Exception.GetBaseException().Message}");
+                        }
+                    }, System.Threading.Tasks.TaskScheduler.Default);
                 }

77-88: Async start exceptions may be silently swallowed.

StartAsync is called fire-and-forget, so the catch block won't capture async failures. For consistency with HttpBridgeReloadHandler (lines 95-113), consider using ContinueWith to handle the result and log failures.

         private static void TryStartBridgeImmediate()
         {
-            try
-            {
-                MCPServiceLocator.TransportManager.StartAsync(TransportMode.Stdio);
-                MCPForUnity.Editor.Windows.MCPForUnityEditorWindow.RequestHealthVerification();
-            }
-            catch (Exception ex)
-            {
-                McpLog.Warn($"Failed to resume stdio bridge after reload: {ex.Message}");
-            }
+            var startTask = MCPServiceLocator.TransportManager.StartAsync(TransportMode.Stdio);
+            startTask.ContinueWith(t =>
+            {
+                if (t.IsFaulted)
+                {
+                    var baseEx = t.Exception?.GetBaseException();
+                    McpLog.Warn($"Failed to resume stdio bridge after reload: {baseEx?.Message}");
+                    return;
+                }
+                if (!t.Result)
+                {
+                    McpLog.Warn("Failed to resume stdio bridge after domain reload");
+                }
+                else
+                {
+                    MCPForUnity.Editor.Windows.MCPForUnityEditorWindow.RequestHealthVerification();
+                }
+            }, System.Threading.Tasks.TaskScheduler.Default);
         }
MCPForUnity/Editor/Services/BridgeControlService.cs (1)

77-78: Consider ensuring ActiveMode reflects current preference.

ActiveMode returns _preferredMode which is only updated when ResolvePreferredMode() is called. If accessed before other methods, it may return the stale default (Http). Consider calling ResolvePreferredMode() in the getter for consistency.

-        public TransportMode? ActiveMode => _preferredMode;
+        public TransportMode? ActiveMode => ResolvePreferredMode();
MCPForUnity/Editor/Services/Transport/TransportManager.cs (3)

38-46: Mode-aware client creation and StartAsync flow are sound; minor robustness tweaks possible

The GetOrCreateClient(mode) switch and StartAsync(TransportMode mode) logic look correct and align with the new per-mode model:

  • Correct factory is used per mode.
  • On failure (started == false) you clean up via client.StopAsync() and mark the mode as disconnected.
  • On success you prefer client.State but fall back to a sensible Connected default.

Two optional robustness nits:

  • In the failure path, await client.StopAsync(); can still throw and bypass your UpdateState(...) call. Mirroring the try/catch you use in StopAsync’s StopClient helper (log & still update state) would make this more resilient.
  • For the failure state, you currently use mode.ToString().ToLowerInvariant() as the transport name, whereas success uses client.TransportName. Using client.TransportName in both paths would keep naming consistent and avoid subtle discrepancies if the enum name and transport name ever diverge.

These are not blockers, just cleanups to consider.

Also applies to: 48-62


64-88: StopAsync semantics and implementation look reasonable; ensure “stop all” default is intended

The refactored StopAsync(TransportMode? mode = null) looks solid:

  • Local StopClient defensively handles null clients, catches/logs exceptions, and always updates the per-mode state.
  • mode == null stopping both transports is a sensible generalization now that you support multiple modes.
  • Mode-specific paths delegate correctly to HTTP vs stdio.

One thing to double‑check is API semantics: if any existing callers relied on previous “stop current active transport only” behavior, StopAsync() now stopping both could be a behavior change. If that’s not desired, you may want an explicit StopAllAsync() helper and keep StopAsync() delegating to “preferred”/“active” mode instead.

If the new “stop all” default is intentional, the current implementation is fine as-is.


91-103: Prefer explicit switch on TransportMode instead of mode == Http ? ... : ... for future-proofing

In VerifyAsync, GetState, IsRunning, and UpdateState you use patterns like:

  • mode == TransportMode.Http ? _httpClient : _stdioClient
  • mode == TransportMode.Http ? _httpState : _stdioState
  • if (mode == TransportMode.Http) { ... } else { ... }

With the current enum (Http, Stdio), this works, but it silently treats any future TransportMode value as Stdio. That’s inconsistent with GetOrCreateClient, which throws for unknown modes, and could cause subtle bugs if new modes are added later.

Consider refactoring these to explicit switches, mirroring GetOrCreateClient:

private IMcpTransportClient GetClient(TransportMode mode) =>
    mode switch
    {
        TransportMode.Http => _httpClient,
        TransportMode.Stdio => _stdioClient,
        _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Unsupported transport mode"),
    };

public TransportState GetState(TransportMode mode) =>
    mode switch
    {
        TransportMode.Http => _httpState,
        TransportMode.Stdio => _stdioState,
        _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Unsupported transport mode"),
    };

…and similarly in VerifyAsync, IsRunning, and UpdateState. This keeps behavior well-defined and consistent if/when additional modes are introduced.

Also applies to: 105-108, 110-110, 112-122

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f94cb24 and bcae2c6.

📒 Files selected for processing (7)
  • MCPForUnity/Editor/Constants/EditorPrefKeys.cs (1 hunks)
  • MCPForUnity/Editor/Services/BridgeControlService.cs (4 hunks)
  • MCPForUnity/Editor/Services/HttpBridgeReloadHandler.cs (5 hunks)
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (1 hunks)
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta (1 hunks)
  • MCPForUnity/Editor/Services/Transport/TransportManager.cs (3 hunks)
  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs (0 hunks)
💤 Files with no reviewable changes (1)
  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-13T13:27:23.040Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.

Applied to files:

  • MCPForUnity/Editor/Constants/EditorPrefKeys.cs
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta
  • MCPForUnity/Editor/Services/HttpBridgeReloadHandler.cs
📚 Learning: 2025-09-03T16:00:55.839Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 0
File: :0-0
Timestamp: 2025-09-03T16:00:55.839Z
Learning: ComponentResolver in UnityMcpBridge/Editor/Tools/ManageGameObject.cs is a nested static class within ManageGameObject, not a sibling type. The `using static MCPForUnity.Editor.Tools.ManageGameObject;` import is required to access ComponentResolver methods directly without the outer class qualifier.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta
📚 Learning: 2025-09-04T01:01:11.927Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 260
File: UnityMcpBridge/UnityMcpServer~/src/server_version.txt:1-1
Timestamp: 2025-09-04T01:01:11.927Z
Learning: The UnityMcpBridge project is not maintaining changelogs yet, so don't suggest adding changelog entries for version bumps.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta
🧬 Code graph analysis (4)
MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (4)
MCPForUnity/Editor/Constants/EditorPrefKeys.cs (1)
  • EditorPrefKeys (7-40)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (3)
  • TransportManager (11-123)
  • TransportManager (20-25)
  • IsRunning (110-110)
MCPForUnity/Editor/Services/BridgeControlService.cs (1)
  • TransportMode (25-30)
MCPForUnity/Editor/Helpers/McpLog.cs (2)
  • McpLog (7-52)
  • Warn (43-46)
MCPForUnity/Editor/Services/BridgeControlService.cs (2)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (1)
  • IsRunning (110-110)
MCPForUnity/Editor/Services/IBridgeControlService.cs (2)
  • BridgeVerificationResult (47-47)
  • BridgeVerificationResult (60-81)
MCPForUnity/Editor/Services/HttpBridgeReloadHandler.cs (4)
MCPForUnity/Editor/Services/MCPServiceLocator.cs (1)
  • MCPServiceLocator (11-85)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (3)
  • TransportManager (11-123)
  • TransportManager (20-25)
  • IsRunning (110-110)
MCPForUnity/Editor/Services/BridgeControlService.cs (1)
  • TransportMode (25-30)
MCPForUnity/Editor/Constants/EditorPrefKeys.cs (1)
  • EditorPrefKeys (7-40)
MCPForUnity/Editor/Services/Transport/TransportManager.cs (1)
MCPForUnity/Editor/Services/BridgeControlService.cs (4)
  • TransportMode (25-30)
  • Task (80-97)
  • Task (99-110)
  • Task (112-118)
🔇 Additional comments (12)
MCPForUnity/Editor/Constants/EditorPrefKeys.cs (1)

13-14: LGTM!

The new ResumeStdioAfterReload constant follows the established naming convention and is logically grouped with the related ResumeHttpAfterReload key.

MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs.meta (1)

1-11: LGTM!

Standard Unity metadata file with a unique GUID for the new StdioBridgeReloadHandler.cs script.

MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (1)

10-20: Good implementation of the stdio reload handler.

The structure correctly mirrors HttpBridgeReloadHandler by subscribing to AssemblyReloadEvents and managing the resume flag via EditorPrefs. This aligns well with the PR objective of bringing stdio behavior in line with websocket connection behavior.

MCPForUnity/Editor/Services/BridgeControlService.cs (3)

52-59: LGTM!

The IsRunning property now correctly resolves the preferred mode and queries the transport manager for mode-specific state. This aligns with the per-mode transport management approach.


99-110: LGTM!

StopAsync correctly resolves the preferred mode and stops only that specific transport, preserving the existing error handling pattern.


120-136: LGTM with note on blocking call.

The Verify(int port) method uses GetAwaiter().GetResult() to meet the synchronous interface contract. This is acceptable in the Unity Editor context, though be mindful that it blocks the calling thread.

MCPForUnity/Editor/Services/HttpBridgeReloadHandler.cs (4)

27-28: LGTM!

The update correctly uses TransportManager.IsRunning(TransportMode.Http) for explicit mode-aware state checking.


62-64: Good defensive check.

The addition of useHttp verification ensures HTTP transport only resumes if it remains the preferred transport, preventing incorrect behavior if the user switched preferences during reload.


39-49: LGTM!

The stop operation correctly targets TransportMode.Http and maintains proper error handling via ContinueWith.


95-113: LGTM!

The start operation correctly uses TransportMode.Http with proper error handling and health verification on success.

MCPForUnity/Editor/Services/Transport/TransportManager.cs (2)

13-16: Per-transport clients and state look consistent with multi-mode design

Splitting _httpClient/_stdioClient and _httpState/_stdioState cleanly supports concurrent tracking of both transports and aligns with the PR objective (HTTP/websocket vs stdio). No correctness issues spotted here.


27-28: Mark deprecated ActiveTransport and ActiveMode properties with [Obsolete] attribute and provide clear migration path

Both properties now always return null, creating risk of silent behavioral regressions for existing callers. To improve discoverability and safety:

  • Add [Obsolete("Use per-mode APIs (StartAsync(mode), GetState(mode), IsRunning(mode), etc.) instead.", error: false)] to both properties
  • Add XML doc comments indicating they will always return null and will be removed in a future version

… mode

The ActiveMode property now calls ResolvePreferredMode() to return the actual active transport mode rather than just the preferred mode setting.
- Consolidated the !useHttp && isRunning checks into a single shouldResume flag.
- Wrapped the fire-and-forget StopAsync in a continuation that logs faults (matching the HTTP handler pattern).
- Wrapped StartAsync in a continuation that logs failures and only triggers the health check on success.
… handling

- Replace if-else chains with switch expressions for better readability and exhaustiveness checking
- Add GetClient() helper method to centralize client retrieval logic
- Wrap StopAsync in try-catch to log failures when stopping a failed transport
- Use client.TransportName instead of mode.ToString() for consistent naming in error messages
@msanatan msanatan merged commit 17cd543 into CoplayDev:main Nov 27, 2025
1 check passed
@msanatan msanatan deleted the fix-stdio-reloads branch November 27, 2025 23:33
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