@@ -12,6 +12,157 @@ function delay(ms) {
1212 return new Promise ( ( resolve ) => setTimeout ( resolve , ms , true ) ) ;
1313}
1414
15+ async function startDevServer ( serverOptions ) {
16+ const { SERVER_PORT , CLIENT_PORT , sessionToken, envVars, abort } =
17+ serverOptions ;
18+ const serverCommand = "npx" ;
19+ const serverArgs = [ "tsx" , "watch" , "--clear-screen=false" , "src/index.ts" ] ;
20+ const isWindows = process . platform === "win32" ;
21+
22+ const spawnOptions = {
23+ cwd : resolve ( __dirname , "../.." , "server" ) ,
24+ env : {
25+ ...process . env ,
26+ PORT : SERVER_PORT ,
27+ CLIENT_PORT : CLIENT_PORT ,
28+ MCP_PROXY_TOKEN : sessionToken ,
29+ MCP_ENV_VARS : JSON . stringify ( envVars ) ,
30+ } ,
31+ signal : abort . signal ,
32+ echoOutput : true ,
33+ } ;
34+
35+ // For Windows, we need to use stdin: 'ignore' to simulate < NUL
36+ if ( isWindows ) {
37+ spawnOptions . stdin = "ignore" ;
38+ }
39+
40+ const server = spawn ( serverCommand , serverArgs , spawnOptions ) ;
41+
42+ // Give server time to start
43+ const serverOk = await Promise . race ( [
44+ new Promise ( ( resolve ) => {
45+ server . subscribe ( {
46+ complete : ( ) => resolve ( false ) ,
47+ error : ( ) => resolve ( false ) ,
48+ next : ( ) => { } , // We're using echoOutput
49+ } ) ;
50+ } ) ,
51+ delay ( 3000 ) . then ( ( ) => true ) ,
52+ ] ) ;
53+
54+ return { server, serverOk } ;
55+ }
56+
57+ async function startProdServer ( serverOptions ) {
58+ const {
59+ SERVER_PORT ,
60+ CLIENT_PORT ,
61+ sessionToken,
62+ envVars,
63+ abort,
64+ command,
65+ mcpServerArgs,
66+ } = serverOptions ;
67+ const inspectorServerPath = resolve (
68+ __dirname ,
69+ "../.." ,
70+ "server" ,
71+ "build" ,
72+ "index.js" ,
73+ ) ;
74+
75+ const server = spawnPromise (
76+ "node" ,
77+ [
78+ inspectorServerPath ,
79+ ...( command ? [ `--env` , command ] : [ ] ) ,
80+ ...( mcpServerArgs ? [ `--args=${ mcpServerArgs . join ( " " ) } ` ] : [ ] ) ,
81+ ] ,
82+ {
83+ env : {
84+ ...process . env ,
85+ PORT : SERVER_PORT ,
86+ CLIENT_PORT : CLIENT_PORT ,
87+ MCP_PROXY_TOKEN : sessionToken ,
88+ MCP_ENV_VARS : JSON . stringify ( envVars ) ,
89+ } ,
90+ signal : abort . signal ,
91+ echoOutput : true ,
92+ } ,
93+ ) ;
94+
95+ // Make sure server started before starting client
96+ const serverOk = await Promise . race ( [ server , delay ( 2 * 1000 ) ] ) ;
97+
98+ return { server, serverOk } ;
99+ }
100+
101+ async function startDevClient ( clientOptions ) {
102+ const { CLIENT_PORT , authDisabled, sessionToken, abort, cancelled } =
103+ clientOptions ;
104+ const clientCommand = "npx" ;
105+ const clientArgs = [ "vite" , "--port" , CLIENT_PORT ] ;
106+
107+ const client = spawn ( clientCommand , clientArgs , {
108+ cwd : resolve ( __dirname , ".." ) ,
109+ env : { ...process . env , PORT : CLIENT_PORT } ,
110+ signal : abort . signal ,
111+ echoOutput : true ,
112+ } ) ;
113+
114+ // Auto-open browser after vite starts
115+ if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
116+ const url = authDisabled
117+ ? `http://127.0.0.1:${ CLIENT_PORT } `
118+ : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
119+
120+ // Give vite time to start before opening browser
121+ setTimeout ( ( ) => {
122+ open ( url ) ;
123+ console . log ( `\n🔗 Opening browser at: ${ url } \n` ) ;
124+ } , 3000 ) ;
125+ }
126+
127+ await new Promise ( ( resolve ) => {
128+ client . subscribe ( {
129+ complete : resolve ,
130+ error : ( err ) => {
131+ if ( ! cancelled || process . env . DEBUG ) {
132+ console . error ( "Client error:" , err ) ;
133+ }
134+ resolve ( null ) ;
135+ } ,
136+ next : ( ) => { } , // We're using echoOutput
137+ } ) ;
138+ } ) ;
139+ }
140+
141+ async function startProdClient ( clientOptions ) {
142+ const { CLIENT_PORT , authDisabled, sessionToken, abort } = clientOptions ;
143+ const inspectorClientPath = resolve (
144+ __dirname ,
145+ "../.." ,
146+ "client" ,
147+ "bin" ,
148+ "client.js" ,
149+ ) ;
150+
151+ // Auto-open browser with token
152+ if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
153+ const url = authDisabled
154+ ? `http://127.0.0.1:${ CLIENT_PORT } `
155+ : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
156+ open ( url ) ;
157+ }
158+
159+ await spawnPromise ( "node" , [ inspectorClientPath ] , {
160+ env : { ...process . env , PORT : CLIENT_PORT } ,
161+ signal : abort . signal ,
162+ echoOutput : true ,
163+ } ) ;
164+ }
165+
15166async function main ( ) {
16167 // Parse command line arguments
17168 const args = process . argv . slice ( 2 ) ;
@@ -76,146 +227,37 @@ async function main() {
76227 let server , serverOk ;
77228
78229 try {
79- if ( isDev ) {
80- // Development mode - use tsx watch
81- const serverCommand = "npx" ;
82- const serverArgs = [
83- "tsx" ,
84- "watch" ,
85- "--clear-screen=false" ,
86- "src/index.ts" ,
87- ] ;
88- const isWindows = process . platform === "win32" ;
89-
90- const serverOptions = {
91- cwd : resolve ( __dirname , "../.." , "server" ) ,
92- env : {
93- ...process . env ,
94- PORT : SERVER_PORT ,
95- CLIENT_PORT : CLIENT_PORT ,
96- MCP_PROXY_TOKEN : sessionToken ,
97- MCP_ENV_VARS : JSON . stringify ( envVars ) ,
98- } ,
99- signal : abort . signal ,
100- echoOutput : true ,
101- } ;
230+ const serverOptions = {
231+ SERVER_PORT ,
232+ CLIENT_PORT ,
233+ sessionToken,
234+ envVars,
235+ abort,
236+ command,
237+ mcpServerArgs,
238+ } ;
102239
103- // For Windows, we need to use stdin: 'ignore' to simulate < NUL
104- if ( isWindows ) {
105- serverOptions . stdin = "ignore" ;
106- }
240+ const result = isDev
241+ ? await startDevServer ( serverOptions )
242+ : await startProdServer ( serverOptions ) ;
107243
108- server = spawn ( serverCommand , serverArgs , serverOptions ) ;
109-
110- // Give server time to start
111- serverOk = await Promise . race ( [
112- new Promise ( ( resolve ) => {
113- server . subscribe ( {
114- complete : ( ) => resolve ( false ) ,
115- error : ( ) => resolve ( false ) ,
116- next : ( ) => { } , // We're using echoOutput
117- } ) ;
118- } ) ,
119- delay ( 3000 ) . then ( ( ) => true ) ,
120- ] ) ;
121- } else {
122- // Production mode - use built files
123- const inspectorServerPath = resolve (
124- __dirname ,
125- "../.." ,
126- "server" ,
127- "build" ,
128- "index.js" ,
129- ) ;
130-
131- server = spawnPromise (
132- "node" ,
133- [
134- inspectorServerPath ,
135- ...( command ? [ `--env` , command ] : [ ] ) ,
136- ...( mcpServerArgs ? [ `--args=${ mcpServerArgs . join ( " " ) } ` ] : [ ] ) ,
137- ] ,
138- {
139- env : {
140- ...process . env ,
141- PORT : SERVER_PORT ,
142- CLIENT_PORT : CLIENT_PORT ,
143- MCP_PROXY_TOKEN : sessionToken ,
144- MCP_ENV_VARS : JSON . stringify ( envVars ) ,
145- } ,
146- signal : abort . signal ,
147- echoOutput : true ,
148- } ,
149- ) ;
150-
151- // Make sure server started before starting client
152- serverOk = await Promise . race ( [ server , delay ( 2 * 1000 ) ] ) ;
153- }
244+ server = result . server ;
245+ serverOk = result . serverOk ;
154246 } catch ( error ) { }
155247
156248 if ( serverOk ) {
157249 try {
158- if ( isDev ) {
159- // Development mode - use vite
160- const clientCommand = "npx" ;
161- const clientArgs = [ "vite" , "--port" , CLIENT_PORT ] ;
162-
163- const client = spawn ( clientCommand , clientArgs , {
164- cwd : resolve ( __dirname , ".." ) ,
165- env : { ...process . env , PORT : CLIENT_PORT } ,
166- signal : abort . signal ,
167- echoOutput : true ,
168- } ) ;
169-
170- // Auto-open browser after vite starts
171- if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
172- const url = authDisabled
173- ? `http://127.0.0.1:${ CLIENT_PORT } `
174- : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
175-
176- // Give vite time to start before opening browser
177- setTimeout ( ( ) => {
178- open ( url ) ;
179- console . log ( `\n🔗 Opening browser at: ${ url } \n` ) ;
180- } , 3000 ) ;
181- }
182-
183- await new Promise ( ( resolve ) => {
184- client . subscribe ( {
185- complete : resolve ,
186- error : ( err ) => {
187- if ( ! cancelled || process . env . DEBUG ) {
188- console . error ( "Client error:" , err ) ;
189- }
190- resolve ( null ) ;
191- } ,
192- next : ( ) => { } , // We're using echoOutput
193- } ) ;
194- } ) ;
195- } else {
196- // Production mode - use client.js
197- const inspectorClientPath = resolve (
198- __dirname ,
199- "../.." ,
200- "client" ,
201- "bin" ,
202- "client.js" ,
203- ) ;
204-
205- // Auto-open browser with token
206- if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
207- const url = authDisabled
208- ? `http://127.0.0.1:${ CLIENT_PORT } `
209- : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
210- open ( url ) ;
211- }
250+ const clientOptions = {
251+ CLIENT_PORT ,
252+ authDisabled,
253+ sessionToken,
254+ abort,
255+ cancelled,
256+ } ;
212257
213- await spawnPromise ( "node" , [ inspectorClientPath ] , {
214- env : { ...process . env , PORT : CLIENT_PORT } ,
215- signal : abort . signal ,
216- echoOutput : true ,
217- } ) ;
218- }
258+ await ( isDev
259+ ? startDevClient ( clientOptions )
260+ : startProdClient ( clientOptions ) ) ;
219261 } catch ( e ) {
220262 if ( ! cancelled || process . env . DEBUG ) throw e ;
221263 }
0 commit comments