From ff507b5fc695f9cf618fa80eebead3c7e46349f0 Mon Sep 17 00:00:00 2001 From: Samy Narrainen Date: Wed, 21 May 2025 09:30:22 +0100 Subject: [PATCH 1/5] Read HTTP_PORT from a config file on non-win32 systems. --- Server~/src/unity/mcpUnity.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Server~/src/unity/mcpUnity.ts b/Server~/src/unity/mcpUnity.ts index 83838c00..591ac214 100644 --- a/Server~/src/unity/mcpUnity.ts +++ b/Server~/src/unity/mcpUnity.ts @@ -4,6 +4,8 @@ import { Logger } from '../utils/logger.js'; import { McpUnityError, ErrorType } from '../utils/errors.js'; import { execSync } from 'child_process'; import { default as winreg } from 'winreg'; +import { promises as fs } from 'fs'; +import path from 'path'; interface PendingRequest { resolve: (value: any) => void; @@ -42,11 +44,11 @@ export class McpUnity { // Initialize port from environment variable or use default const envRegistry = process.platform === 'win32' ? this.getUnityPortFromWindowsRegistry() - : this.getUnityPortFromUnixRegistry(); + : this.getUnityPortFromConfig(); const envPort = process.env.UNITY_PORT || envRegistry; this.port = envPort ? parseInt(envPort, 10) : 8090; - this.logger.info(`Using port: ${this.port} for Unity WebSocket connection`); + this.logger.warn(`Using port: ${this.port} for Unity WebSocket connection`); // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds) const envTimeout = process.env.UNITY_REQUEST_TIMEOUT; @@ -300,11 +302,16 @@ export class McpUnity { return result; } - /** - * Retrieves the UNITY_PORT value from Unix-like system environment variables - * @returns The port value as a string if found, otherwise an empty string - */ - private getUnityPortFromUnixRegistry(): string { - return execSync('printenv UNITY_PORT', { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim(); + private getUnityPortFromConfig(): string { + // Read UNITY_PORT value from env.config synchronously using execSync + const configPath = path.resolve(process.cwd(), 'env.config'); + try { + const content = execSync(`cat "${configPath}"`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString(); + const match = content.match(/^UNITY_PORT\s*=\s*(\d+)/m); + return match ? match[1] : ''; + } catch (err) { + this.logger.debug(`env.config not found or unreadable: ${err instanceof Error ? err.message : String(err)}`); + return ''; + } } } From 2867edf38b662ead66f272ddae1c2cd02a6d70b8 Mon Sep 17 00:00:00 2001 From: Samy Narrainen Date: Wed, 21 May 2025 09:44:53 +0100 Subject: [PATCH 2/5] Write out server.env file from C# side. --- Editor/UnityBridge/McpUnitySettings.cs | 20 ++++++++++++++++++++ Editor/Utils/McpConfigUtils.cs | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Editor/UnityBridge/McpUnitySettings.cs b/Editor/UnityBridge/McpUnitySettings.cs index dfa62692..a4ca65ec 100644 --- a/Editor/UnityBridge/McpUnitySettings.cs +++ b/Editor/UnityBridge/McpUnitySettings.cs @@ -110,6 +110,9 @@ public void SaveSettings() // see: https://learn.microsoft.com/en-us/dotnet/api/system.environmentvariabletarget?view=net-8.0#remarks Environment.SetEnvironmentVariable(EnvUnityPort, Port.ToString(), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(EnvUnityRequestTimeout, RequestTimeoutSeconds.ToString(), EnvironmentVariableTarget.Process); + + // For non w32 systems. + SaveSettingsToNodeServer(); } catch (Exception ex) { @@ -117,5 +120,22 @@ public void SaveSettings() Debug.LogError($"[MCP Unity] Failed to save settings: {ex.Message}"); } } + + + public void SaveSettingsToNodeServer() { + try + { + string propertiesPath = GetServerPath() + "/build/server.env"; + using (var writer = new StreamWriter(propertiesPath, false)) + { + writer.WriteLine($"{EnvUnityPort}={Port}"); + writer.WriteLine($"{EnvUnityRequestTimeout}={RequestTimeoutSeconds}"); + } + } + catch (Exception ex) + { + Debug.LogError($"[MCP Unity] Failed to write server env properties: {ex.Message}"); + } + } } } diff --git a/Editor/Utils/McpConfigUtils.cs b/Editor/Utils/McpConfigUtils.cs index 64c0dc65..510df7e3 100644 --- a/Editor/Utils/McpConfigUtils.cs +++ b/Editor/Utils/McpConfigUtils.cs @@ -60,7 +60,7 @@ public static string GenerateMcpConfigJson(bool useTabsIndentation) } /// - /// Gets the absolute path to the Server directory containing package.json + /// Gets the absolute path to the Server directory containing package.json (root server dir). /// Works whether MCP Unity is installed via Package Manager or directly in the Assets folder /// public static string GetServerPath() From 876acb96a6d86d450a0db2d8f423e8f29b99f39a Mon Sep 17 00:00:00 2001 From: Samy Narrainen Date: Thu, 22 May 2025 16:43:28 +0100 Subject: [PATCH 3/5] Replace reading of server settings via system env vars with a config file to bolster cross-platformability. --- Editor/UnityBridge/McpUnitySettings.cs | 42 +------------- README.md | 14 +++++ Server~/build/McpUnitySettings.json | 6 ++ Server~/build/unity/mcpUnity.d.ts | 17 +++--- Server~/build/unity/mcpUnity.js | 75 ++++++++++++------------ Server~/build/utils/errors.js | 2 +- Server~/build/utils/logger.js | 2 +- Server~/src/unity/mcpUnity.ts | 80 +++++++++++--------------- 8 files changed, 104 insertions(+), 134 deletions(-) create mode 100644 Server~/build/McpUnitySettings.json diff --git a/Editor/UnityBridge/McpUnitySettings.cs b/Editor/UnityBridge/McpUnitySettings.cs index a4ca65ec..274a46a9 100644 --- a/Editor/UnityBridge/McpUnitySettings.cs +++ b/Editor/UnityBridge/McpUnitySettings.cs @@ -72,18 +72,6 @@ public void LoadSettings() string json = File.ReadAllText(SettingsPath); JsonUtility.FromJsonOverwrite(json, this); } - - // Check for environment variable PORT - string envPort = System.Environment.GetEnvironmentVariable(EnvUnityPort); - if (!string.IsNullOrEmpty(envPort) && int.TryParse(envPort, out int port)) - { - Port = port; - } - string envTimeout = System.Environment.GetEnvironmentVariable(EnvUnityRequestTimeout); - if (!string.IsNullOrEmpty(envTimeout) && int.TryParse(envTimeout, out int timeout)) - { - RequestTimeoutSeconds = timeout; - } } catch (Exception ex) { @@ -103,16 +91,9 @@ public void SaveSettings() string json = JsonUtility.ToJson(this, true); File.WriteAllText(SettingsPath, json); - // Set environment variable PORT for the Node.js process - // EnvironmentVariableTarget.User and EnvironmentVariableTarget.Machine should be used on .NET implementations running on Windows systems only. - // For non-Windows systems, User and Machine are treated as Process. - // Using Process target for broader compatibility. - // see: https://learn.microsoft.com/en-us/dotnet/api/system.environmentvariabletarget?view=net-8.0#remarks - Environment.SetEnvironmentVariable(EnvUnityPort, Port.ToString(), EnvironmentVariableTarget.Process); - Environment.SetEnvironmentVariable(EnvUnityRequestTimeout, RequestTimeoutSeconds.ToString(), EnvironmentVariableTarget.Process); - - // For non w32 systems. - SaveSettingsToNodeServer(); + // Now save these same settings to the server to read on start-up. + string propertiesPath = GetServerPath() + "/build/McpUnitySettings.json"; + File.WriteAllText(propertiesPath, json); } catch (Exception ex) { @@ -120,22 +101,5 @@ public void SaveSettings() Debug.LogError($"[MCP Unity] Failed to save settings: {ex.Message}"); } } - - - public void SaveSettingsToNodeServer() { - try - { - string propertiesPath = GetServerPath() + "/build/server.env"; - using (var writer = new StreamWriter(propertiesPath, false)) - { - writer.WriteLine($"{EnvUnityPort}={Port}"); - writer.WriteLine($"{EnvUnityRequestTimeout}={RequestTimeoutSeconds}"); - } - } - catch (Exception ex) - { - Debug.LogError($"[MCP Unity] Failed to write server env properties: {ex.Message}"); - } - } } } diff --git a/README.md b/README.md index 2be9bc17..9ad1b1d5 100644 --- a/README.md +++ b/README.md @@ -383,6 +383,20 @@ This error occurs because the bridge connection is lost when the domain reloads The workaround is to turn off **Reload Domain** in **Edit > Project Settings > Editor > "Enter Play Mode Settings"**. +## Node Server +These steps can be useful if you want to build and run the server independently of the Unity plugin. +### Requirements +As well as `node`, you will need `tsc`. +### Steps +1. cd into the `Server~/` directory. +2. run `npm install` to install the project. +3. run `npm run build` to build the project. +4. run `node build/index.js` to run the server! 🚀 + +### Troubleshooting 🔨 +#### Logging +Logging is enabled when the environment variable `LOGGING` is set to true. E.g. `export LOGGING=true`. + ## Support & Feedback If you have any questions or need support, please open an [issue](https://github.com/CoderGamester/mcp-unity/issues) on this repository. diff --git a/Server~/build/McpUnitySettings.json b/Server~/build/McpUnitySettings.json new file mode 100644 index 00000000..c94ddfe5 --- /dev/null +++ b/Server~/build/McpUnitySettings.json @@ -0,0 +1,6 @@ +{ + "Port": 8090, + "RequestTimeoutSeconds": 10, + "AutoStartServer": true, + "EnableInfoLogs": true +} \ No newline at end of file diff --git a/Server~/build/unity/mcpUnity.d.ts b/Server~/build/unity/mcpUnity.d.ts index 98a30487..d46b3912 100644 --- a/Server~/build/unity/mcpUnity.d.ts +++ b/Server~/build/unity/mcpUnity.d.ts @@ -9,7 +9,7 @@ export declare class McpUnity { private port; private ws; private pendingRequests; - private readonly REQUEST_TIMEOUT; + private requestTimeout; private retryDelay; constructor(logger: Logger); /** @@ -17,6 +17,10 @@ export declare class McpUnity { * @param clientName Optional name of the MCP client connecting to Unity */ start(clientName?: string): Promise; + /** + * Reads our configuration file and sets parameters of the server based on them. + */ + private parseAndSetConfig; /** * Connect to the Unity WebSocket * @param clientName Optional name of the MCP client connecting to Unity @@ -48,14 +52,9 @@ export declare class McpUnity { */ get isConnected(): boolean; /** - * Retrieves the UNITY_PORT value from the Windows registry (HKCU\Environment) - * @returns The port value as a string if found, otherwise an empty string - */ - private getUnityPortFromWindowsRegistry; - /** - * Retrieves the UNITY_PORT value from Unix-like system environment variables - * @returns The port value as a string if found, otherwise an empty string + * Read the McpUnitySettings.json file and return its contents as a JSON object. + * @returns a JSON object with the contents of the McpUnitySettings.json file. */ - private getUnityPortFromUnixRegistry; + private readConfigFileAsJson; } export {}; diff --git a/Server~/build/unity/mcpUnity.js b/Server~/build/unity/mcpUnity.js index 7013a8f8..753c55ab 100644 --- a/Server~/build/unity/mcpUnity.js +++ b/Server~/build/unity/mcpUnity.js @@ -1,28 +1,17 @@ import WebSocket from 'ws'; import { v4 as uuidv4 } from 'uuid'; import { McpUnityError, ErrorType } from '../utils/errors.js'; -import { execSync } from 'child_process'; -import { default as winreg } from 'winreg'; +import { promises as fs } from 'fs'; +import path from 'path'; export class McpUnity { logger; - port; + port = null; ws = null; pendingRequests = new Map(); - REQUEST_TIMEOUT; + requestTimeout = 10000; retryDelay = 1000; constructor(logger) { this.logger = logger; - // Initialize port from environment variable or use default - const envRegistry = process.platform === 'win32' - ? this.getUnityPortFromWindowsRegistry() - : this.getUnityPortFromUnixRegistry(); - const envPort = process.env.UNITY_PORT || envRegistry; - this.port = envPort ? parseInt(envPort, 10) : 8090; - this.logger.info(`Using port: ${this.port} for Unity WebSocket connection`); - // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds) - const envTimeout = process.env.UNITY_REQUEST_TIMEOUT; - this.REQUEST_TIMEOUT = envTimeout ? parseInt(envTimeout, 10) * 1000 : 10000; - this.logger.info(`Using request timeout: ${this.REQUEST_TIMEOUT / 1000} seconds`); } /** * Start the Unity connection @@ -30,6 +19,8 @@ export class McpUnity { */ async start(clientName) { try { + this.logger.info('Attempting to read startup parameters...'); + this.parseAndSetConfig(); this.logger.info('Attempting to connect to Unity WebSocket...'); await this.connect(clientName); // Pass client name to connect this.logger.info('Successfully connected to Unity WebSocket'); @@ -45,6 +36,19 @@ export class McpUnity { } return Promise.resolve(); } + /** + * Reads our configuration file and sets parameters of the server based on them. + */ + async parseAndSetConfig() { + const config = await this.readConfigFileAsJson(); + const configPort = config.Port; + this.port = configPort ? parseInt(configPort, 10) : 8090; + this.logger.info(`Using port: ${this.port} for Unity WebSocket connection`); + // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds) + const configTimeout = config.RequestTimeoutSeconds; + this.requestTimeout = configTimeout ? parseInt(configTimeout, 10) * 1000 : 10000; + this.logger.info(`Using request timeout: ${this.requestTimeout / 1000} seconds`); + } /** * Connect to the Unity WebSocket * @param clientName Optional name of the MCP client connecting to Unity @@ -74,7 +78,7 @@ export class McpUnity { this.disconnect(); reject(new McpUnityError(ErrorType.CONNECTION, 'Connection timeout')); } - }, this.REQUEST_TIMEOUT); + }, this.requestTimeout); this.ws.onopen = () => { clearTimeout(connectionTimeout); this.logger.debug('WebSocket connected'); @@ -193,12 +197,12 @@ export class McpUnity { // Create timeout for the request const timeout = setTimeout(() => { if (this.pendingRequests.has(requestId)) { - this.logger.error(`Request ${requestId} timed out after ${this.REQUEST_TIMEOUT}ms`); + this.logger.error(`Request ${requestId} timed out after ${this.requestTimeout}ms`); this.pendingRequests.delete(requestId); reject(new McpUnityError(ErrorType.TIMEOUT, 'Request timed out')); } this.reconnect(); - }, this.REQUEST_TIMEOUT); + }, this.requestTimeout); // Store pending request this.pendingRequests.set(requestId, { resolve, @@ -225,27 +229,20 @@ export class McpUnity { return this.ws !== null && this.ws.readyState === WebSocket.OPEN; } /** - * Retrieves the UNITY_PORT value from the Windows registry (HKCU\Environment) - * @returns The port value as a string if found, otherwise an empty string - */ - getUnityPortFromWindowsRegistry() { - const regKey = new winreg({ hive: winreg.HKCU, key: '\\Environment' }); - let result = ''; - regKey.get('UNITY_PORT', (err, item) => { - if (err) { - this.logger.error(`Error getting registry value: ${err.message}`); - } - else { - result = item.value; - } - }); - return result; - } - /** - * Retrieves the UNITY_PORT value from Unix-like system environment variables - * @returns The port value as a string if found, otherwise an empty string + * Read the McpUnitySettings.json file and return its contents as a JSON object. + * @returns a JSON object with the contents of the McpUnitySettings.json file. */ - getUnityPortFromUnixRegistry() { - return execSync('printenv UNITY_PORT', { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim(); + async readConfigFileAsJson() { + const configPath = path.resolve(process.cwd(), 'build/McpUnitySettings.json'); + this.logger.debug(`Reading McpUnitySettings.json from ${configPath}`); + try { + const content = await fs.readFile(configPath, 'utf-8'); + const json = JSON.parse(content); + return json; + } + catch (err) { + this.logger.debug(`McpUnitySettings.json not found or unreadable: ${err instanceof Error ? err.message : String(err)}`); + return {}; + } } } diff --git a/Server~/build/utils/errors.js b/Server~/build/utils/errors.js index 7382c65f..429a4d72 100644 --- a/Server~/build/utils/errors.js +++ b/Server~/build/utils/errors.js @@ -6,7 +6,7 @@ export var ErrorType; ErrorType["VALIDATION"] = "validation_error"; ErrorType["INTERNAL"] = "internal_error"; ErrorType["TIMEOUT"] = "timeout_error"; -})(ErrorType || (ErrorType = {})); +})(ErrorType = ErrorType || (ErrorType = {})); export class McpUnityError extends Error { type; details; diff --git a/Server~/build/utils/logger.js b/Server~/build/utils/logger.js index ec6b4c13..212c2829 100644 --- a/Server~/build/utils/logger.js +++ b/Server~/build/utils/logger.js @@ -5,7 +5,7 @@ export var LogLevel; LogLevel[LogLevel["INFO"] = 1] = "INFO"; LogLevel[LogLevel["WARN"] = 2] = "WARN"; LogLevel[LogLevel["ERROR"] = 3] = "ERROR"; -})(LogLevel || (LogLevel = {})); +})(LogLevel = LogLevel || (LogLevel = {})); // Check environment variable for logging const isLoggingEnabled = process.env.LOGGING === 'true'; // Check environment variable for logging in a file diff --git a/Server~/src/unity/mcpUnity.ts b/Server~/src/unity/mcpUnity.ts index 591ac214..38bc59e3 100644 --- a/Server~/src/unity/mcpUnity.ts +++ b/Server~/src/unity/mcpUnity.ts @@ -2,8 +2,6 @@ import WebSocket from 'ws'; import { v4 as uuidv4 } from 'uuid'; import { Logger } from '../utils/logger.js'; import { McpUnityError, ErrorType } from '../utils/errors.js'; -import { execSync } from 'child_process'; -import { default as winreg } from 'winreg'; import { promises as fs } from 'fs'; import path from 'path'; @@ -32,28 +30,14 @@ interface UnityResponse { export class McpUnity { private logger: Logger; - private port: number; + private port: number | null = null; private ws: WebSocket | null = null; private pendingRequests: Map = new Map(); - private readonly REQUEST_TIMEOUT: number; + private requestTimeout = 10000; private retryDelay = 1000; constructor(logger: Logger) { this.logger = logger; - - // Initialize port from environment variable or use default - const envRegistry = process.platform === 'win32' - ? this.getUnityPortFromWindowsRegistry() - : this.getUnityPortFromConfig(); - - const envPort = process.env.UNITY_PORT || envRegistry; - this.port = envPort ? parseInt(envPort, 10) : 8090; - this.logger.warn(`Using port: ${this.port} for Unity WebSocket connection`); - - // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds) - const envTimeout = process.env.UNITY_REQUEST_TIMEOUT; - this.REQUEST_TIMEOUT = envTimeout ? parseInt(envTimeout, 10) * 1000 : 10000; - this.logger.info(`Using request timeout: ${this.REQUEST_TIMEOUT / 1000} seconds`); } /** @@ -62,6 +46,9 @@ export class McpUnity { */ public async start(clientName?: string): Promise { try { + this.logger.info('Attempting to read startup parameters...'); + this.parseAndSetConfig(); + this.logger.info('Attempting to connect to Unity WebSocket...'); await this.connect(clientName); // Pass client name to connect this.logger.info('Successfully connected to Unity WebSocket'); @@ -79,6 +66,22 @@ export class McpUnity { return Promise.resolve(); } + + /** + * Reads our configuration file and sets parameters of the server based on them. + */ + private async parseAndSetConfig() { + const config = await this.readConfigFileAsJson(); + + const configPort = config.Port; + this.port = configPort ? parseInt(configPort, 10) : 8090; + this.logger.info(`Using port: ${this.port} for Unity WebSocket connection`); + + // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds) + const configTimeout = config.RequestTimeoutSeconds; + this.requestTimeout = configTimeout ? parseInt(configTimeout, 10) * 1000 : 10000; + this.logger.info(`Using request timeout: ${this.requestTimeout / 1000} seconds`); + } /** * Connect to the Unity WebSocket @@ -114,7 +117,7 @@ export class McpUnity { this.disconnect(); reject(new McpUnityError(ErrorType.CONNECTION, 'Connection timeout')); } - }, this.REQUEST_TIMEOUT); + }, this.requestTimeout); this.ws.onopen = () => { clearTimeout(connectionTimeout); @@ -251,12 +254,12 @@ export class McpUnity { // Create timeout for the request const timeout = setTimeout(() => { if (this.pendingRequests.has(requestId)) { - this.logger.error(`Request ${requestId} timed out after ${this.REQUEST_TIMEOUT}ms`); + this.logger.error(`Request ${requestId} timed out after ${this.requestTimeout}ms`); this.pendingRequests.delete(requestId); reject(new McpUnityError(ErrorType.TIMEOUT, 'Request timed out')); } this.reconnect(); - }, this.REQUEST_TIMEOUT); + }, this.requestTimeout); // Store pending request this.pendingRequests.set(requestId, { @@ -284,34 +287,21 @@ export class McpUnity { // Basic WebSocket connection check return this.ws !== null && this.ws.readyState === WebSocket.OPEN; } - + /** - * Retrieves the UNITY_PORT value from the Windows registry (HKCU\Environment) - * @returns The port value as a string if found, otherwise an empty string + * Read the McpUnitySettings.json file and return its contents as a JSON object. + * @returns a JSON object with the contents of the McpUnitySettings.json file. */ - private getUnityPortFromWindowsRegistry(): string { - const regKey = new winreg({hive: winreg.HKCU, key: '\\Environment'}); - let result = ''; - regKey.get('UNITY_PORT', (err: Error | null, item: any) => { - if (err) { - this.logger.error(`Error getting registry value: ${err.message}`); - } else { - result = item.value; - } - }); - return result; - } - - private getUnityPortFromConfig(): string { - // Read UNITY_PORT value from env.config synchronously using execSync - const configPath = path.resolve(process.cwd(), 'env.config'); + private async readConfigFileAsJson(): Promise { + const configPath = path.resolve(process.cwd(), 'build/McpUnitySettings.json'); + this.logger.debug(`Reading McpUnitySettings.json from ${configPath}`); try { - const content = execSync(`cat "${configPath}"`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString(); - const match = content.match(/^UNITY_PORT\s*=\s*(\d+)/m); - return match ? match[1] : ''; + const content = await fs.readFile(configPath, 'utf-8'); + const json = JSON.parse(content); + return json; } catch (err) { - this.logger.debug(`env.config not found or unreadable: ${err instanceof Error ? err.message : String(err)}`); - return ''; + this.logger.debug(`McpUnitySettings.json not found or unreadable: ${err instanceof Error ? err.message : String(err)}`); + return {}; } } } From ad4b08aebc4f43983da39aece12d21dd9453056a Mon Sep 17 00:00:00 2001 From: Samy Narrainen Date: Thu, 22 May 2025 19:49:28 +0100 Subject: [PATCH 4/5] Update path to read from existing settings file. --- Editor/UnityBridge/McpUnitySettings.cs | 10 ++++++---- README.md | 14 -------------- Server~/build/McpUnitySettings.json | 6 ------ Server~/src/unity/mcpUnity.ts | 2 +- 4 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 Server~/build/McpUnitySettings.json diff --git a/Editor/UnityBridge/McpUnitySettings.cs b/Editor/UnityBridge/McpUnitySettings.cs index 274a46a9..ac43b21f 100644 --- a/Editor/UnityBridge/McpUnitySettings.cs +++ b/Editor/UnityBridge/McpUnitySettings.cs @@ -19,6 +19,9 @@ public class McpUnitySettings private const string EnvUnityPort = "UNITY_PORT"; private const string EnvUnityRequestTimeout = "UNITY_REQUEST_TIMEOUT"; + /// + /// This file path is also read by the MCP server. Changes here will require updates to it. See mcpUnity.ts + /// private const string SettingsPath = "ProjectSettings/McpUnitySettings.json"; private static McpUnitySettings _instance; @@ -83,6 +86,9 @@ public void LoadSettings() /// /// Save settings to disk /// + /// + /// WARNING: This file is also read by the MCP server. Changes here will require updates to it. See mcpUnity.ts + /// public void SaveSettings() { try @@ -90,10 +96,6 @@ public void SaveSettings() // Save settings to McpUnitySettings.json string json = JsonUtility.ToJson(this, true); File.WriteAllText(SettingsPath, json); - - // Now save these same settings to the server to read on start-up. - string propertiesPath = GetServerPath() + "/build/McpUnitySettings.json"; - File.WriteAllText(propertiesPath, json); } catch (Exception ex) { diff --git a/README.md b/README.md index 9ad1b1d5..2be9bc17 100644 --- a/README.md +++ b/README.md @@ -383,20 +383,6 @@ This error occurs because the bridge connection is lost when the domain reloads The workaround is to turn off **Reload Domain** in **Edit > Project Settings > Editor > "Enter Play Mode Settings"**. -## Node Server -These steps can be useful if you want to build and run the server independently of the Unity plugin. -### Requirements -As well as `node`, you will need `tsc`. -### Steps -1. cd into the `Server~/` directory. -2. run `npm install` to install the project. -3. run `npm run build` to build the project. -4. run `node build/index.js` to run the server! 🚀 - -### Troubleshooting 🔨 -#### Logging -Logging is enabled when the environment variable `LOGGING` is set to true. E.g. `export LOGGING=true`. - ## Support & Feedback If you have any questions or need support, please open an [issue](https://github.com/CoderGamester/mcp-unity/issues) on this repository. diff --git a/Server~/build/McpUnitySettings.json b/Server~/build/McpUnitySettings.json deleted file mode 100644 index c94ddfe5..00000000 --- a/Server~/build/McpUnitySettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Port": 8090, - "RequestTimeoutSeconds": 10, - "AutoStartServer": true, - "EnableInfoLogs": true -} \ No newline at end of file diff --git a/Server~/src/unity/mcpUnity.ts b/Server~/src/unity/mcpUnity.ts index 38bc59e3..e4a13018 100644 --- a/Server~/src/unity/mcpUnity.ts +++ b/Server~/src/unity/mcpUnity.ts @@ -293,7 +293,7 @@ export class McpUnity { * @returns a JSON object with the contents of the McpUnitySettings.json file. */ private async readConfigFileAsJson(): Promise { - const configPath = path.resolve(process.cwd(), 'build/McpUnitySettings.json'); + const configPath = path.resolve(process.cwd(), '../ProjectSettings/McpUnitySettings.json'); this.logger.debug(`Reading McpUnitySettings.json from ${configPath}`); try { const content = await fs.readFile(configPath, 'utf-8'); From 63622d811b8720fa547991ca413e230608b9273d Mon Sep 17 00:00:00 2001 From: Samy Narrainen Date: Thu, 22 May 2025 20:07:18 +0100 Subject: [PATCH 5/5] Use await on config file parse call. --- Server~/build/unity/mcpUnity.js | 4 ++-- Server~/src/unity/mcpUnity.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Server~/build/unity/mcpUnity.js b/Server~/build/unity/mcpUnity.js index 753c55ab..81366f6c 100644 --- a/Server~/build/unity/mcpUnity.js +++ b/Server~/build/unity/mcpUnity.js @@ -20,7 +20,7 @@ export class McpUnity { async start(clientName) { try { this.logger.info('Attempting to read startup parameters...'); - this.parseAndSetConfig(); + await this.parseAndSetConfig(); this.logger.info('Attempting to connect to Unity WebSocket...'); await this.connect(clientName); // Pass client name to connect this.logger.info('Successfully connected to Unity WebSocket'); @@ -233,7 +233,7 @@ export class McpUnity { * @returns a JSON object with the contents of the McpUnitySettings.json file. */ async readConfigFileAsJson() { - const configPath = path.resolve(process.cwd(), 'build/McpUnitySettings.json'); + const configPath = path.resolve(process.cwd(), '../ProjectSettings/McpUnitySettings.json'); this.logger.debug(`Reading McpUnitySettings.json from ${configPath}`); try { const content = await fs.readFile(configPath, 'utf-8'); diff --git a/Server~/src/unity/mcpUnity.ts b/Server~/src/unity/mcpUnity.ts index e4a13018..5b54e5f7 100644 --- a/Server~/src/unity/mcpUnity.ts +++ b/Server~/src/unity/mcpUnity.ts @@ -47,7 +47,7 @@ export class McpUnity { public async start(clientName?: string): Promise { try { this.logger.info('Attempting to read startup parameters...'); - this.parseAndSetConfig(); + await this.parseAndSetConfig(); this.logger.info('Attempting to connect to Unity WebSocket...'); await this.connect(clientName); // Pass client name to connect