Skip to content

Commit b86aef2

Browse files
Update WebSocket port to 5010 in configuration files and improve project path sanitization
1 parent 1d7010e commit b86aef2

File tree

10 files changed

+215
-209
lines changed

10 files changed

+215
-209
lines changed

Editor/MCPConnectionManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class MCPConnectionManager
1111
{
1212
private static readonly string ComponentName = "MCPConnectionManager";
1313
private ClientWebSocket webSocket;
14-
private Uri serverUri = new Uri("ws://localhost:8080"); // Changed to allow changing
14+
private Uri serverUri = new Uri("ws://localhost:5010"); // Changed to allow changing
1515
private readonly CancellationTokenSource cts = new CancellationTokenSource();
1616
private bool isConnected = false;
1717
private float reconnectTimer = 0f;

Editor/UI/MCPDebugWindow.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public void CreateGUI()
8888
// Set default port if empty
8989
if (serverPortField != null && string.IsNullOrWhiteSpace(serverPortField.value))
9090
{
91-
serverPortField.value = "8080";
91+
serverPortField.value = "5010";
9292
}
9393

9494
// Setup UI events
@@ -113,7 +113,7 @@ private void CreateFallbackUI(VisualElement root)
113113

114114
// Removed serverUrlField - only using port field as requested
115115

116-
serverPortField = new TextField("Port (Default: 8080)") { value = "8080" };
116+
serverPortField = new TextField("Port (Default: 5010)") { value = "5010" };
117117
root.Add(serverPortField);
118118

119119
var connectButton = new Button(OnConnectClicked) { text = "Connect" };
@@ -240,10 +240,10 @@ private void OnConnectClicked()
240240
// Get the server port from the text field
241241
string portText = serverPortField.value;
242242

243-
// If port is empty, default to 8080
243+
// If port is empty, default to 5010
244244
if (string.IsNullOrWhiteSpace(portText))
245245
{
246-
portText = "8080";
246+
portText = "5010";
247247
serverPortField.value = portText;
248248
}
249249

Editor/UI/MCPDebugWindow.uxml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<ui:VisualElement style="flex-direction: row; align-items: center; margin-bottom: 10px;">
1919
<ui:Label text="Port:" class="server-url-label" />
20-
<ui:TextField name="server-port-field" value="8080" placeholder="Default: 8080" class="server-url-field" />
20+
<ui:TextField name="server-port-field" value="5010" placeholder="Default: 5010" class="server-url-field" />
2121
</ui:VisualElement>
2222

2323
<ui:VisualElement style="flex-direction: row; align-items: center;">

mcpServer/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Unity MCP Server Configuration
22

33
# WebSocket port for Unity Editor connection
4-
MCP_WEBSOCKET_PORT=8080
4+
MCP_WEBSOCKET_PORT=5010

mcpServer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ COPY src/ ./src/
1717
RUN npm run build
1818

1919
# Default environment variable
20-
ENV MCP_WEBSOCKET_PORT=8080
20+
ENV MCP_WEBSOCKET_PORT=5010
2121

2222
# Expose the port dynamically using the environment variable
2323
EXPOSE ${MCP_WEBSOCKET_PORT}

mcpServer/build/index.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,20 @@ class UnityMCPServer {
2020
});
2121
// Get port from environment variable or use default
2222
// Add port range to try if the default port is taken
23-
let wsPort = parseInt(process.env.MCP_WEBSOCKET_PORT || '8080');
23+
let wsPort = parseInt(process.env.MCP_WEBSOCKET_PORT || '5010');
2424
// Determine Unity project path - with improved path sanitization
25-
let projectPath = process.env.UNITY_PROJECT_PATH || path.resolve(process.cwd());
25+
let projectPath = process.env.UNITY_PROJECT_PATH || (() => {
26+
// Get the current working directory
27+
const cwd = path.resolve(process.cwd());
28+
// Find the Assets directory in the path
29+
const assetsIndex = cwd.indexOf('Assets');
30+
// If Assets is found, truncate the path to include Assets
31+
if (assetsIndex !== -1) {
32+
return cwd.substring(0, assetsIndex + 'Assets'.length);
33+
}
34+
// If Assets is not found, return the original path
35+
return cwd;
36+
})();
2637
// Sanitize the path to remove any unexpected characters
2738
projectPath = projectPath.replace(/["']/g, '');
2839
// Fix potential issue with backslashes being removed

mcpServer/build/websocketHandler.js

Lines changed: 83 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import WebSocket, { WebSocketServer } from 'ws';
1+
import { WebSocketServer, WebSocket } from 'ws';
22
export class WebSocketHandler {
3-
server;
4-
clients;
3+
wsServer;
54
port;
65
unityConnection = null;
76
editorState = {
@@ -17,95 +16,57 @@ export class WebSocketHandler {
1716
lastHeartbeat = 0;
1817
connectionEstablished = false;
1918
pendingRequests = {};
20-
constructor(port = parseInt(process.env.MCP_WEBSOCKET_PORT || '8080')) {
19+
constructor(port = 5010) {
2120
this.port = port;
22-
this.clients = new Set();
23-
// Create WebSocket server
24-
this.server = new WebSocketServer({ port });
25-
// Setup event handlers
26-
this.server.on('connection', this.handleConnection.bind(this));
27-
this.server.on('error', this.handleError.bind(this));
28-
console.error(`[WebSocket] Server initialized on port ${port}`);
21+
// Initialize WebSocket Server
22+
this.wsServer = new WebSocketServer({ port });
23+
this.setupWebSocketServer();
2924
}
30-
handleConnection(ws) {
31-
console.error('[WebSocket] Client connected');
32-
this.clients.add(ws);
33-
ws.on('message', (message) => {
34-
try {
35-
const messageStr = message.toString();
36-
console.error(`[WebSocket] Received message: ${messageStr}`);
37-
// Parse message
38-
const data = JSON.parse(messageStr);
39-
// Handle different message types here
40-
this.handleMessage(data, ws);
41-
}
42-
catch (err) {
43-
console.error('[WebSocket] Error processing message:', err);
44-
}
45-
});
46-
ws.on('close', () => {
47-
console.error('[WebSocket] Client disconnected');
48-
this.clients.delete(ws);
25+
setupWebSocketServer() {
26+
console.error(`[Unity MCP] WebSocket server starting on port ${this.port}`);
27+
this.wsServer.on('listening', () => {
28+
console.error('[Unity MCP] WebSocket server is listening for connections');
4929
});
50-
ws.on('error', (error) => {
51-
console.error('[WebSocket] Client error:', error);
52-
this.clients.delete(ws);
30+
this.wsServer.on('error', (error) => {
31+
console.error('[Unity MCP] WebSocket server error:', error);
5332
});
54-
// Send welcome message
55-
ws.send(JSON.stringify({
56-
type: 'connected',
57-
message: 'Connected to Unity MCP WebSocket server'
58-
}));
59-
}
60-
handleMessage(data, client) {
61-
// Handle Unity-specific messages here
62-
console.error(`[WebSocket] Handling message of type: ${data.type}`);
63-
// Add specific message handling as needed
64-
}
65-
handleError(error) {
66-
console.error('[WebSocket] Server error:', error);
67-
}
68-
async sendMessage(message) {
69-
const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
70-
const promises = Array.from(this.clients).map((client) => {
71-
return new Promise((resolve, reject) => {
72-
if (client.readyState === WebSocket.OPEN) {
73-
client.send(messageStr, (err) => {
74-
if (err) {
75-
reject(err);
76-
}
77-
else {
78-
resolve();
79-
}
80-
});
33+
this.wsServer.on('connection', (ws) => {
34+
console.error('[Unity MCP] Unity Editor connected');
35+
this.unityConnection = ws;
36+
this.connectionEstablished = true;
37+
this.lastHeartbeat = Date.now();
38+
// Send a simple handshake message to verify connection
39+
this.sendHandshake();
40+
ws.on('message', (data) => {
41+
try {
42+
// Update heartbeat on any message
43+
this.lastHeartbeat = Date.now();
44+
const message = JSON.parse(data.toString());
45+
console.error('[Unity MCP] Received message type:', message.type);
46+
this.handleUnityMessage(message);
8147
}
82-
else {
83-
resolve(); // Client not ready, skip it
48+
catch (error) {
49+
console.error('[Unity MCP] Error handling message:', error);
8450
}
8551
});
86-
});
87-
await Promise.all(promises);
88-
}
89-
async close() {
90-
// Close all client connections
91-
const closePromises = Array.from(this.clients).map((client) => {
92-
return new Promise((resolve) => {
93-
client.terminate();
94-
resolve();
52+
ws.on('error', (error) => {
53+
console.error('[Unity MCP] WebSocket error:', error);
54+
this.connectionEstablished = false;
9555
});
96-
});
97-
await Promise.all(closePromises);
98-
this.clients.clear();
99-
// Close the server
100-
return new Promise((resolve, reject) => {
101-
this.server.close((err) => {
102-
if (err) {
103-
reject(err);
56+
ws.on('close', () => {
57+
console.error('[Unity MCP] Unity Editor disconnected');
58+
this.unityConnection = null;
59+
this.connectionEstablished = false;
60+
});
61+
// Keep the automatic heartbeat for internal connection validation
62+
const pingInterval = setInterval(() => {
63+
if (ws.readyState === WebSocket.OPEN) {
64+
this.sendPing();
10465
}
10566
else {
106-
resolve();
67+
clearInterval(pingInterval);
10768
}
108-
});
69+
}, 30000); // Send heartbeat every 30 seconds
10970
});
11071
}
11172
sendHandshake() {
@@ -122,7 +83,7 @@ export class WebSocketHandler {
12283
console.error('[Unity MCP] Error sending handshake:', error);
12384
}
12485
}
125-
// Rename from sendHeartbeat to sendPing for consistency with protocol
86+
// Renamed from sendHeartbeat to sendPing for consistency with protocol
12687
sendPing() {
12788
try {
12889
if (this.unityConnection && this.unityConnection.readyState === WebSocket.OPEN) {
@@ -175,7 +136,8 @@ export class WebSocketHandler {
175136
}
176137
break;
177138
default:
178-
console.error('[Unity MCP] Unknown message type:', message.type);
139+
console.error('[Unity MCP] Unknown message type:');
140+
break;
179141
}
180142
}
181143
addLogEntry(logEntry) {
@@ -193,10 +155,12 @@ export class WebSocketHandler {
193155
// Start timing the command execution
194156
this.commandStartTime = Date.now();
195157
// Send the command to Unity
196-
this.unityConnection.send(JSON.stringify({
197-
type: 'executeEditorCommand',
198-
data: { code }
199-
}));
158+
if (this.unityConnection) {
159+
this.unityConnection.send(JSON.stringify({
160+
type: 'executeEditorCommand',
161+
data: { code }
162+
}));
163+
}
200164
// Wait for result with timeout
201165
return await Promise.race([
202166
new Promise((resolve, reject) => {
@@ -271,7 +235,7 @@ export class WebSocketHandler {
271235
return true;
272236
}
273237
requestEditorState() {
274-
if (!this.isConnected()) {
238+
if (!this.isConnected() || !this.unityConnection) {
275239
return;
276240
}
277241
try {
@@ -286,7 +250,7 @@ export class WebSocketHandler {
286250
}
287251
}
288252
async requestSceneInfo(detailLevel) {
289-
if (!this.isConnected()) {
253+
if (!this.isConnected() || !this.unityConnection) {
290254
throw new Error('Unity Editor is not connected');
291255
}
292256
const requestId = crypto.randomUUID();
@@ -316,7 +280,7 @@ export class WebSocketHandler {
316280
return responsePromise;
317281
}
318282
async requestGameObjectsInfo(instanceIDs, detailLevel) {
319-
if (!this.isConnected()) {
283+
if (!this.isConnected() || !this.unityConnection) {
320284
throw new Error('Unity Editor is not connected');
321285
}
322286
const requestId = crypto.randomUUID();
@@ -346,4 +310,33 @@ export class WebSocketHandler {
346310
}));
347311
return responsePromise;
348312
}
313+
// Support for file system tools by adding a method to send generic messages
314+
async sendMessage(message) {
315+
if (this.unityConnection && this.unityConnection.readyState === WebSocket.OPEN) {
316+
const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
317+
return new Promise((resolve, reject) => {
318+
this.unityConnection.send(messageStr, (err) => {
319+
if (err) {
320+
reject(err);
321+
}
322+
else {
323+
resolve();
324+
}
325+
});
326+
});
327+
}
328+
return Promise.resolve();
329+
}
330+
async close() {
331+
if (this.unityConnection) {
332+
this.unityConnection.close();
333+
this.unityConnection = null;
334+
}
335+
return new Promise((resolve) => {
336+
this.wsServer.close(() => {
337+
console.error('[Unity MCP] WebSocket server closed');
338+
resolve();
339+
});
340+
});
341+
}
349342
}

mcpServer/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ services:
44
unity-mcp-server:
55
build: .
66
ports:
7-
- "${MCP_WEBSOCKET_PORT:-8080}:${MCP_WEBSOCKET_PORT:-8080}"
7+
- "${MCP_WEBSOCKET_PORT:-5010}:${MCP_WEBSOCKET_PORT:-5010}"
88
environment:
9-
- MCP_WEBSOCKET_PORT=${MCP_WEBSOCKET_PORT:-8080}
9+
- MCP_WEBSOCKET_PORT=${MCP_WEBSOCKET_PORT:-5010}
1010
restart: unless-stopped
1111
volumes:
1212
# Optional volume for persisting data if needed

mcpServer/src/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,21 @@ class UnityMCPServer {
2626

2727
// Get port from environment variable or use default
2828
// Add port range to try if the default port is taken
29-
let wsPort = parseInt(process.env.MCP_WEBSOCKET_PORT || '8080');
29+
let wsPort = parseInt(process.env.MCP_WEBSOCKET_PORT || '5010');
3030

3131
// Determine Unity project path - with improved path sanitization
32-
let projectPath = process.env.UNITY_PROJECT_PATH || path.resolve(process.cwd());
32+
let projectPath = process.env.UNITY_PROJECT_PATH || (() => {
33+
// Get the current working directory
34+
const cwd = path.resolve(process.cwd());
35+
// Find the Assets directory in the path
36+
const assetsIndex = cwd.indexOf('Assets');
37+
// If Assets is found, truncate the path to include Assets
38+
if (assetsIndex !== -1) {
39+
return cwd.substring(0, assetsIndex + 'Assets'.length);
40+
}
41+
// If Assets is not found, return the original path
42+
return cwd;
43+
})();
3344

3445
// Sanitize the path to remove any unexpected characters
3546
projectPath = projectPath.replace(/["']/g, '');

0 commit comments

Comments
 (0)