@@ -12,6 +12,152 @@ 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 } = serverOptions ;
17
+ const serverCommand = "npx" ;
18
+ const serverArgs = [
19
+ "tsx" ,
20
+ "watch" ,
21
+ "--clear-screen=false" ,
22
+ "src/index.ts" ,
23
+ ] ;
24
+ const isWindows = process . platform === "win32" ;
25
+
26
+ const spawnOptions = {
27
+ cwd : resolve ( __dirname , "../.." , "server" ) ,
28
+ env : {
29
+ ...process . env ,
30
+ PORT : SERVER_PORT ,
31
+ CLIENT_PORT : CLIENT_PORT ,
32
+ MCP_PROXY_TOKEN : sessionToken ,
33
+ MCP_ENV_VARS : JSON . stringify ( envVars ) ,
34
+ } ,
35
+ signal : abort . signal ,
36
+ echoOutput : true ,
37
+ } ;
38
+
39
+ // For Windows, we need to use stdin: 'ignore' to simulate < NUL
40
+ if ( isWindows ) {
41
+ spawnOptions . stdin = "ignore" ;
42
+ }
43
+
44
+ const server = spawn ( serverCommand , serverArgs , spawnOptions ) ;
45
+
46
+ // Give server time to start
47
+ const serverOk = await Promise . race ( [
48
+ new Promise ( ( resolve ) => {
49
+ server . subscribe ( {
50
+ complete : ( ) => resolve ( false ) ,
51
+ error : ( ) => resolve ( false ) ,
52
+ next : ( ) => { } , // We're using echoOutput
53
+ } ) ;
54
+ } ) ,
55
+ delay ( 3000 ) . then ( ( ) => true ) ,
56
+ ] ) ;
57
+
58
+ return { server, serverOk } ;
59
+ }
60
+
61
+ async function startProdServer ( serverOptions ) {
62
+ const { SERVER_PORT , CLIENT_PORT , sessionToken, envVars, abort, command, mcpServerArgs } = serverOptions ;
63
+ const inspectorServerPath = resolve (
64
+ __dirname ,
65
+ "../.." ,
66
+ "server" ,
67
+ "build" ,
68
+ "index.js" ,
69
+ ) ;
70
+
71
+ const server = spawnPromise (
72
+ "node" ,
73
+ [
74
+ inspectorServerPath ,
75
+ ...( command ? [ `--env` , command ] : [ ] ) ,
76
+ ...( mcpServerArgs ? [ `--args=${ mcpServerArgs . join ( " " ) } ` ] : [ ] ) ,
77
+ ] ,
78
+ {
79
+ env : {
80
+ ...process . env ,
81
+ PORT : SERVER_PORT ,
82
+ CLIENT_PORT : CLIENT_PORT ,
83
+ MCP_PROXY_TOKEN : sessionToken ,
84
+ MCP_ENV_VARS : JSON . stringify ( envVars ) ,
85
+ } ,
86
+ signal : abort . signal ,
87
+ echoOutput : true ,
88
+ } ,
89
+ ) ;
90
+
91
+ // Make sure server started before starting client
92
+ const serverOk = await Promise . race ( [ server , delay ( 2 * 1000 ) ] ) ;
93
+
94
+ return { server, serverOk } ;
95
+ }
96
+
97
+ async function startDevClient ( clientOptions ) {
98
+ const { CLIENT_PORT , authDisabled, sessionToken, abort, cancelled } = clientOptions ;
99
+ const clientCommand = "npx" ;
100
+ const clientArgs = [ "vite" , "--port" , CLIENT_PORT ] ;
101
+
102
+ const client = spawn ( clientCommand , clientArgs , {
103
+ cwd : resolve ( __dirname , ".." ) ,
104
+ env : { ...process . env , PORT : CLIENT_PORT } ,
105
+ signal : abort . signal ,
106
+ echoOutput : true ,
107
+ } ) ;
108
+
109
+ // Auto-open browser after vite starts
110
+ if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
111
+ const url = authDisabled
112
+ ? `http://127.0.0.1:${ CLIENT_PORT } `
113
+ : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
114
+
115
+ // Give vite time to start before opening browser
116
+ setTimeout ( ( ) => {
117
+ open ( url ) ;
118
+ console . log ( `\n🔗 Opening browser at: ${ url } \n` ) ;
119
+ } , 3000 ) ;
120
+ }
121
+
122
+ await new Promise ( ( resolve ) => {
123
+ client . subscribe ( {
124
+ complete : resolve ,
125
+ error : ( err ) => {
126
+ if ( ! cancelled || process . env . DEBUG ) {
127
+ console . error ( "Client error:" , err ) ;
128
+ }
129
+ resolve ( null ) ;
130
+ } ,
131
+ next : ( ) => { } , // We're using echoOutput
132
+ } ) ;
133
+ } ) ;
134
+ }
135
+
136
+ async function startProdClient ( clientOptions ) {
137
+ const { CLIENT_PORT , authDisabled, sessionToken, abort } = clientOptions ;
138
+ const inspectorClientPath = resolve (
139
+ __dirname ,
140
+ "../.." ,
141
+ "client" ,
142
+ "bin" ,
143
+ "client.js" ,
144
+ ) ;
145
+
146
+ // Auto-open browser with token
147
+ if ( process . env . MCP_AUTO_OPEN_ENABLED !== "false" ) {
148
+ const url = authDisabled
149
+ ? `http://127.0.0.1:${ CLIENT_PORT } `
150
+ : `http://127.0.0.1:${ CLIENT_PORT } /?MCP_PROXY_AUTH_TOKEN=${ sessionToken } ` ;
151
+ open ( url ) ;
152
+ }
153
+
154
+ await spawnPromise ( "node" , [ inspectorClientPath ] , {
155
+ env : { ...process . env , PORT : CLIENT_PORT } ,
156
+ signal : abort . signal ,
157
+ echoOutput : true ,
158
+ } ) ;
159
+ }
160
+
15
161
async function main ( ) {
16
162
// Parse command line arguments
17
163
const args = process . argv . slice ( 2 ) ;
@@ -76,146 +222,37 @@ async function main() {
76
222
let server , serverOk ;
77
223
78
224
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
- } ;
102
-
103
- // For Windows, we need to use stdin: 'ignore' to simulate < NUL
104
- if ( isWindows ) {
105
- serverOptions . stdin = "ignore" ;
106
- }
107
-
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
- }
225
+ const serverOptions = {
226
+ SERVER_PORT ,
227
+ CLIENT_PORT ,
228
+ sessionToken,
229
+ envVars,
230
+ abort,
231
+ command,
232
+ mcpServerArgs,
233
+ } ;
234
+
235
+ const result = isDev
236
+ ? await startDevServer ( serverOptions )
237
+ : await startProdServer ( serverOptions ) ;
238
+
239
+ server = result . server ;
240
+ serverOk = result . serverOk ;
154
241
} catch ( error ) { }
155
242
156
243
if ( serverOk ) {
157
244
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
- }
212
-
213
- await spawnPromise ( "node" , [ inspectorClientPath ] , {
214
- env : { ...process . env , PORT : CLIENT_PORT } ,
215
- signal : abort . signal ,
216
- echoOutput : true ,
217
- } ) ;
218
- }
245
+ const clientOptions = {
246
+ CLIENT_PORT ,
247
+ authDisabled,
248
+ sessionToken,
249
+ abort,
250
+ cancelled,
251
+ } ;
252
+
253
+ await ( isDev
254
+ ? startDevClient ( clientOptions )
255
+ : startProdClient ( clientOptions ) ) ;
219
256
} catch ( e ) {
220
257
if ( ! cancelled || process . env . DEBUG ) throw e ;
221
258
}
0 commit comments