Skip to content

Commit 4ffb699

Browse files
committed
Generate the session ID from the server
We also make the identifying hashes longer
1 parent 3dbb6b5 commit 4ffb699

File tree

3 files changed

+66
-10
lines changed

3 files changed

+66
-10
lines changed

MCPForUnity/Editor/Helpers/ProjectIdentityUtility.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ private static string ComputeProjectHash(string dataPath)
9494
{
9595
sb.Append(b.ToString("x2"));
9696
}
97-
return sb.ToString(0, Math.Min(8, sb.Length));
97+
return sb.ToString(0, Math.Min(16, sb.Length));
9898
}
9999
catch
100100
{
@@ -122,6 +122,32 @@ private static string ComputeProjectName(string dataPath)
122122
}
123123
}
124124

125+
/// <summary>
126+
/// Persists a server-assigned session id.
127+
/// Safe to call from background threads.
128+
/// </summary>
129+
public static void SetSessionId(string sessionId)
130+
{
131+
if (string.IsNullOrEmpty(sessionId))
132+
{
133+
return;
134+
}
135+
136+
EditorApplication.delayCall += () =>
137+
{
138+
try
139+
{
140+
string projectHash = GetProjectHash();
141+
string projectSpecificKey = $"{SessionPrefKey}_{projectHash}";
142+
EditorPrefs.SetString(projectSpecificKey, sessionId);
143+
}
144+
catch (Exception ex)
145+
{
146+
McpLog.Warn($"Failed to persist session ID: {ex.Message}");
147+
}
148+
};
149+
}
150+
125151
/// <summary>
126152
/// Retrieves a persistent session id for the plugin, creating one if absent.
127153
/// The session id is unique per project (scoped by project hash).

MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public class WebSocketTransportClient : IMcpTransportClient, IDisposable
4242

4343
private Uri _endpointUri;
4444
private string _sessionId;
45+
private string _projectHash;
46+
private string _projectName;
47+
private string _unityVersion;
4548
private TimeSpan _keepAliveInterval = DefaultKeepAliveInterval;
4649
private TimeSpan _socketKeepAliveInterval = DefaultKeepAliveInterval;
4750
private volatile bool _isConnected;
@@ -54,19 +57,25 @@ public class WebSocketTransportClient : IMcpTransportClient, IDisposable
5457

5558
public async Task<bool> StartAsync()
5659
{
60+
// Capture identity values on the main thread before any async context switching
61+
_projectName = ProjectIdentityUtility.GetProjectName();
62+
_projectHash = ProjectIdentityUtility.GetProjectHash();
63+
_unityVersion = Application.unityVersion;
64+
5765
await StopAsync();
5866

5967
_lifecycleCts = new CancellationTokenSource();
6068
_endpointUri = BuildWebSocketUri(HttpEndpointUtility.GetBaseUrl());
61-
_sessionId = ProjectIdentityUtility.GetOrCreateSessionId();
69+
_sessionId = null;
6270

6371
if (!await EstablishConnectionAsync(_lifecycleCts.Token))
6472
{
6573
await StopAsync();
6674
return false;
6775
}
6876

69-
_state = TransportState.Connected(TransportDisplayName, sessionId: _sessionId, details: _endpointUri.ToString());
77+
// State is connected but session ID might be pending until 'registered' message
78+
_state = TransportState.Connected(TransportDisplayName, sessionId: "pending", details: _endpointUri.ToString());
7079
_isConnected = true;
7180
return true;
7281
}
@@ -281,6 +290,9 @@ private async Task HandleMessageAsync(string message, CancellationToken token)
281290
case "welcome":
282291
ApplyWelcome(payload);
283292
break;
293+
case "registered":
294+
HandleRegistered(payload);
295+
break;
284296
case "execute":
285297
await HandleExecuteAsync(payload, token).ConfigureAwait(false);
286298
break;
@@ -311,6 +323,18 @@ private void ApplyWelcome(JObject payload)
311323
}
312324
}
313325

326+
private void HandleRegistered(JObject payload)
327+
{
328+
string newSessionId = payload.Value<string>("session_id");
329+
if (!string.IsNullOrEmpty(newSessionId))
330+
{
331+
_sessionId = newSessionId;
332+
ProjectIdentityUtility.SetSessionId(_sessionId);
333+
_state = TransportState.Connected(TransportDisplayName, sessionId: _sessionId, details: _endpointUri.ToString());
334+
McpLog.Info($"[WebSocket] Registered with session ID: {_sessionId}");
335+
}
336+
}
337+
314338
private async Task HandleExecuteAsync(JObject payload, CancellationToken token)
315339
{
316340
string commandId = payload.Value<string>("id");
@@ -409,10 +433,10 @@ private async Task SendRegisterAsync(CancellationToken token)
409433
var registerPayload = new JObject
410434
{
411435
["type"] = "register",
412-
["session_id"] = _sessionId,
413-
["project_name"] = ProjectIdentityUtility.GetProjectName(),
414-
["project_hash"] = ProjectIdentityUtility.GetProjectHash(),
415-
["unity_version"] = Application.unityVersion
436+
// session_id is now server-authoritative; omitted here or sent as null
437+
["project_name"] = _projectName,
438+
["project_hash"] = _projectHash,
439+
["unity_version"] = _unityVersion
416440
};
417441

418442
await SendJsonAsync(registerPayload, token).ConfigureAwait(false);

Server/src/transport/plugin_hub.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,21 @@ async def _handle_register(self, websocket: WebSocket, payload: Dict[str, Any])
149149
await websocket.close(code=1011)
150150
raise RuntimeError("PluginHub not configured")
151151

152-
session_id = payload.get("session_id")
153152
project_name = payload.get("project_name", "Unknown Project")
154153
project_hash = payload.get("project_hash")
155154
unity_version = payload.get("unity_version", "Unknown")
156155

157-
if not session_id or not project_hash:
156+
if not project_hash:
158157
await websocket.close(code=4400)
159158
raise ValueError(
160-
"Plugin registration missing session_id or project_hash")
159+
"Plugin registration missing project_hash")
160+
161+
session_id = str(uuid.uuid4())
162+
# Inform the plugin of its assigned session ID
163+
await websocket.send_json({
164+
"type": "registered",
165+
"session_id": session_id
166+
})
161167

162168
session = await registry.register(session_id, project_name, project_hash, unity_version)
163169
async with lock:

0 commit comments

Comments
 (0)