11import WebSocket from 'ws' ;
22import { v4 as uuidv4 } from 'uuid' ;
33import { McpUnityError , ErrorType } from '../utils/errors.js' ;
4- import { execSync } from 'child_process ' ;
5- import { default as winreg } from 'winreg ' ;
4+ import { promises as fs } from 'fs ' ;
5+ import path from 'path ' ;
66export class McpUnity {
77 logger ;
8- port ;
8+ port = null ;
99 ws = null ;
1010 pendingRequests = new Map ( ) ;
11- REQUEST_TIMEOUT ;
11+ requestTimeout = 10000 ;
1212 retryDelay = 1000 ;
1313 constructor ( logger ) {
1414 this . logger = logger ;
15- // Initialize port from environment variable or use default
16- const envRegistry = process . platform === 'win32'
17- ? this . getUnityPortFromWindowsRegistry ( )
18- : this . getUnityPortFromUnixRegistry ( ) ;
19- const envPort = process . env . UNITY_PORT || envRegistry ;
20- this . port = envPort ? parseInt ( envPort , 10 ) : 8090 ;
21- this . logger . info ( `Using port: ${ this . port } for Unity WebSocket connection` ) ;
22- // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds)
23- const envTimeout = process . env . UNITY_REQUEST_TIMEOUT ;
24- this . REQUEST_TIMEOUT = envTimeout ? parseInt ( envTimeout , 10 ) * 1000 : 10000 ;
25- this . logger . info ( `Using request timeout: ${ this . REQUEST_TIMEOUT / 1000 } seconds` ) ;
2615 }
2716 /**
2817 * Start the Unity connection
2918 * @param clientName Optional name of the MCP client connecting to Unity
3019 */
3120 async start ( clientName ) {
3221 try {
22+ this . logger . info ( 'Attempting to read startup parameters...' ) ;
23+ this . parseAndSetConfig ( ) ;
3324 this . logger . info ( 'Attempting to connect to Unity WebSocket...' ) ;
3425 await this . connect ( clientName ) ; // Pass client name to connect
3526 this . logger . info ( 'Successfully connected to Unity WebSocket' ) ;
@@ -45,6 +36,19 @@ export class McpUnity {
4536 }
4637 return Promise . resolve ( ) ;
4738 }
39+ /**
40+ * Reads our configuration file and sets parameters of the server based on them.
41+ */
42+ async parseAndSetConfig ( ) {
43+ const config = await this . readConfigFileAsJson ( ) ;
44+ const configPort = config . Port ;
45+ this . port = configPort ? parseInt ( configPort , 10 ) : 8090 ;
46+ this . logger . info ( `Using port: ${ this . port } for Unity WebSocket connection` ) ;
47+ // Initialize timeout from environment variable (in seconds; it is the same as Cline) or use default (10 seconds)
48+ const configTimeout = config . RequestTimeoutSeconds ;
49+ this . requestTimeout = configTimeout ? parseInt ( configTimeout , 10 ) * 1000 : 10000 ;
50+ this . logger . info ( `Using request timeout: ${ this . requestTimeout / 1000 } seconds` ) ;
51+ }
4852 /**
4953 * Connect to the Unity WebSocket
5054 * @param clientName Optional name of the MCP client connecting to Unity
@@ -74,7 +78,7 @@ export class McpUnity {
7478 this . disconnect ( ) ;
7579 reject ( new McpUnityError ( ErrorType . CONNECTION , 'Connection timeout' ) ) ;
7680 }
77- } , this . REQUEST_TIMEOUT ) ;
81+ } , this . requestTimeout ) ;
7882 this . ws . onopen = ( ) => {
7983 clearTimeout ( connectionTimeout ) ;
8084 this . logger . debug ( 'WebSocket connected' ) ;
@@ -193,12 +197,12 @@ export class McpUnity {
193197 // Create timeout for the request
194198 const timeout = setTimeout ( ( ) => {
195199 if ( this . pendingRequests . has ( requestId ) ) {
196- this . logger . error ( `Request ${ requestId } timed out after ${ this . REQUEST_TIMEOUT } ms` ) ;
200+ this . logger . error ( `Request ${ requestId } timed out after ${ this . requestTimeout } ms` ) ;
197201 this . pendingRequests . delete ( requestId ) ;
198202 reject ( new McpUnityError ( ErrorType . TIMEOUT , 'Request timed out' ) ) ;
199203 }
200204 this . reconnect ( ) ;
201- } , this . REQUEST_TIMEOUT ) ;
205+ } , this . requestTimeout ) ;
202206 // Store pending request
203207 this . pendingRequests . set ( requestId , {
204208 resolve,
@@ -225,27 +229,20 @@ export class McpUnity {
225229 return this . ws !== null && this . ws . readyState === WebSocket . OPEN ;
226230 }
227231 /**
228- * Retrieves the UNITY_PORT value from the Windows registry (HKCU\Environment)
229- * @returns The port value as a string if found, otherwise an empty string
230- */
231- getUnityPortFromWindowsRegistry ( ) {
232- const regKey = new winreg ( { hive : winreg . HKCU , key : '\\Environment' } ) ;
233- let result = '' ;
234- regKey . get ( 'UNITY_PORT' , ( err , item ) => {
235- if ( err ) {
236- this . logger . error ( `Error getting registry value: ${ err . message } ` ) ;
237- }
238- else {
239- result = item . value ;
240- }
241- } ) ;
242- return result ;
243- }
244- /**
245- * Retrieves the UNITY_PORT value from Unix-like system environment variables
246- * @returns The port value as a string if found, otherwise an empty string
232+ * Read the McpUnitySettings.json file and return its contents as a JSON object.
233+ * @returns a JSON object with the contents of the McpUnitySettings.json file.
247234 */
248- getUnityPortFromUnixRegistry ( ) {
249- return execSync ( 'printenv UNITY_PORT' , { stdio : [ 'pipe' , 'pipe' , 'ignore' ] } ) . toString ( ) . trim ( ) ;
235+ async readConfigFileAsJson ( ) {
236+ const configPath = path . resolve ( process . cwd ( ) , 'build/McpUnitySettings.json' ) ;
237+ this . logger . debug ( `Reading McpUnitySettings.json from ${ configPath } ` ) ;
238+ try {
239+ const content = await fs . readFile ( configPath , 'utf-8' ) ;
240+ const json = JSON . parse ( content ) ;
241+ return json ;
242+ }
243+ catch ( err ) {
244+ this . logger . debug ( `McpUnitySettings.json not found or unreadable: ${ err instanceof Error ? err . message : String ( err ) } ` ) ;
245+ return { } ;
246+ }
250247 }
251248}
0 commit comments