@@ -12,6 +12,157 @@ function delay(ms) {
12
12
return new Promise ( ( resolve ) => setTimeout ( resolve , ms , true ) ) ;
13
13
}
14
14
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
+
15
166
async function main ( ) {
16
167
// Parse command line arguments
17
168
const args = process . argv . slice ( 2 ) ;
@@ -76,146 +227,37 @@ async function main() {
76
227
let server , serverOk ;
77
228
78
229
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
+ } ;
102
239
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 ) ;
107
243
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 ;
154
246
} catch ( error ) { }
155
247
156
248
if ( serverOk ) {
157
249
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
+ } ;
212
257
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 ) ) ;
219
261
} catch ( e ) {
220
262
if ( ! cancelled || process . env . DEBUG ) throw e ;
221
263
}
0 commit comments