From dd9fef5aa7dfd5534a1726c54dd2383f6da5ed29 Mon Sep 17 00:00:00 2001
From: Ramlock <22538054+Ramlock@users.noreply.github.com>
Date: Tue, 16 Jun 2026 22:05:45 -0300
Subject: [PATCH] fix(editor): qualify server PID EditorPrefs key by port
McpServerManager stored the running server's PID under a fixed EditorPrefs
key ("McpServerManager_ProcessId"). EditorPrefs are machine-global - shared
across every project of the same Editor version - and the key was not
qualified by project or port, so two Editors open at once (different
projects, different ports) clobbered a single slot.
The result was mutual exclusion despite distinct ports: after Editor B
started its server and overwrote the slot with B's PID, Editor A's
CheckExistingProcess (run on domain reload) read B's PID, adopted B's
server as its own _serverProcess, and terminated it on the next stop/quit -
dropping B's connection. Symmetric, so whichever Editor was touched second
killed the other's server.
Qualify the key by the server port via the pure, unit-tested
ProcessIdKeyForPort(int) helper so each project tracks its own server
independently. The per-project binary folder and the orphaned-process kill
were already port-scoped; this closes the last shared-state gap.
Adds EditMode tests for the helper.
---
.../Editor/Scripts/McpServerManager.cs | 16 +++++-
.../McpServerManagerProcessIdKeyTests.cs | 53 +++++++++++++++++++
.../McpServerManagerProcessIdKeyTests.cs.meta | 11 ++++
3 files changed, 79 insertions(+), 1 deletion(-)
create mode 100644 Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs
create mode 100644 Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs.meta
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Editor/Scripts/McpServerManager.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Editor/Scripts/McpServerManager.cs
index 057cf99b0..3111af728 100644
--- a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Editor/Scripts/McpServerManager.cs
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Editor/Scripts/McpServerManager.cs
@@ -51,9 +51,23 @@ public enum McpServerStatus
[InitializeOnLoad]
public static class McpServerManager
{
- const string ProcessIdKey = "McpServerManager_ProcessId";
+ // Qualified by the server port so two Editors (different projects, different ports) on
+ // the same machine never share this slot. EditorPrefs are machine-global - shared across
+ // every project of the same Editor version - so an UNqualified key let one project's
+ // CheckExistingProcess adopt the OTHER project's server PID and then tear it down on stop,
+ // making the two Editors mutually exclusive even though their ports differ. See ProcessIdKeyForPort.
+ static string ProcessIdKey => ProcessIdKeyForPort(UnityMcpPluginEditor.Port);
const string McpServerProcessName = "gamedev-mcp-server";
+ ///
+ /// The EditorPrefs key under which this project's running server PID is stored, qualified by
+ /// the server . EditorPrefs are shared across every project of the same
+ /// Editor version on the machine, so this key MUST be port-qualified: otherwise two Editors
+ /// clobber a single global slot and adopt/terminate each other's server processes. Pure (no
+ /// Unity API access) so it can be unit-tested in EditMode.
+ ///
+ internal static string ProcessIdKeyForPort(int port) => $"McpServerManager_ProcessId_{port}";
+
static readonly ILogger _logger = UnityLoggerFactory.LoggerFactory.CreateLogger(typeof(McpServerManager));
static readonly ReactiveProperty _serverStatus = new(McpServerStatus.Stopped);
static readonly object _processMutex = new();
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs
new file mode 100644
index 000000000..5efa374f0
--- /dev/null
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs
@@ -0,0 +1,53 @@
+/*
+┌──────────────────────────────────────────────────────────────────┐
+│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
+│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
+│ Copyright (c) 2025 Ivan Murzak │
+│ Licensed under the Apache License, Version 2.0. │
+│ See the LICENSE file in the project root for more information. │
+└──────────────────────────────────────────────────────────────────┘
+*/
+
+#nullable enable
+using NUnit.Framework;
+
+namespace com.IvanMurzak.Unity.MCP.Editor.Tests
+{
+ ///
+ /// Regression tests: the EditorPrefs key that stores the running server PID must be qualified by
+ /// the server port. EditorPrefs are shared across every project of the same Editor version on a
+ /// machine, so an unqualified key let two Editors (different projects, different ports) clobber a
+ /// single global slot — one project's CheckExistingProcess would adopt the other's server
+ /// PID and terminate it on stop, making the two Editors mutually exclusive despite distinct ports.
+ ///
+ /// is the pure helper behind the key.
+ ///
+ public class McpServerManagerProcessIdKeyTests
+ {
+ [Test]
+ public void ProcessIdKeyForPort_DifferentPorts_ProduceDifferentKeys()
+ {
+ Assert.AreNotEqual(
+ McpServerManager.ProcessIdKeyForPort(26645),
+ McpServerManager.ProcessIdKeyForPort(26646),
+ "Two projects on different ports must not share the same PID key, " +
+ "or they tear down each other's servers.");
+ }
+
+ [Test]
+ public void ProcessIdKeyForPort_SamePort_IsStable()
+ {
+ Assert.AreEqual(
+ McpServerManager.ProcessIdKeyForPort(26646),
+ McpServerManager.ProcessIdKeyForPort(26646),
+ "The key for a given port must be deterministic across calls so the stored PID " +
+ "can be read back and deleted.");
+ }
+
+ [Test]
+ public void ProcessIdKeyForPort_IncludesPort()
+ {
+ StringAssert.Contains("26646", McpServerManager.ProcessIdKeyForPort(26646));
+ }
+ }
+}
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs.meta b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs.meta
new file mode 100644
index 000000000..7fe6e68e5
--- /dev/null
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Tests/Editor/McpServerManagerProcessIdKeyTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: be9a124f208946b2b5197e3f1de6fdfa
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: