@@ -7,186 +7,212 @@ import { spawnPromise } from "spawn-rx";
7
7
import { fileURLToPath } from "url" ;
8
8
const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
9
9
function handleError ( error ) {
10
- let message ;
11
- if ( error instanceof Error ) {
12
- message = error . message ;
13
- }
14
- else if ( typeof error === "string" ) {
15
- message = error ;
16
- }
17
- else {
18
- message = "Unknown error" ;
19
- }
20
- console . error ( message ) ;
21
- process . exit ( 1 ) ;
10
+ let message ;
11
+ if ( error instanceof Error ) {
12
+ message = error . message ;
13
+ } else if ( typeof error === "string" ) {
14
+ message = error ;
15
+ } else {
16
+ message = "Unknown error" ;
17
+ }
18
+ console . error ( message ) ;
19
+ process . exit ( 1 ) ;
22
20
}
23
21
function delay ( ms ) {
24
- return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
22
+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
25
23
}
26
24
async function runWebClient ( args ) {
27
- const inspectorServerPath = resolve ( __dirname , ".." , "server" , "build" , "index.js" ) ;
28
- // Path to the client entry point
29
- const inspectorClientPath = resolve ( __dirname , ".." , "client" , "bin" , "cli.js" ) ;
30
- const CLIENT_PORT = process . env . CLIENT_PORT ?? "5173" ;
31
- const SERVER_PORT = process . env . SERVER_PORT ?? "3000" ;
32
- console . log ( "Starting MCP inspector..." ) ;
33
- const abort = new AbortController ( ) ;
34
- let cancelled = false ;
35
- process . on ( "SIGINT" , ( ) => {
36
- cancelled = true ;
37
- abort . abort ( ) ;
38
- } ) ;
39
- const server = spawnPromise ( "node" , [
40
- inspectorServerPath ,
41
- ...( args . command ? [ `--env` , args . command ] : [ ] ) ,
42
- ...( args . args ? [ `--args=${ args . args . join ( " " ) } ` ] : [ ] ) ,
43
- ] , {
44
- env : {
45
- ...process . env ,
46
- PORT : SERVER_PORT ,
47
- MCP_ENV_VARS : JSON . stringify ( args . envArgs ) ,
48
- } ,
49
- signal : abort . signal ,
50
- echoOutput : true ,
51
- } ) ;
52
- const client = spawnPromise ( "node" , [ inspectorClientPath ] , {
53
- env : { ...process . env , PORT : CLIENT_PORT } ,
54
- signal : abort . signal ,
55
- echoOutput : true ,
56
- } ) ;
57
- // Make sure our server/client didn't immediately fail
58
- await Promise . any ( [ server , client , delay ( 2 * 1000 ) ] ) ;
59
- const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${ SERVER_PORT } ` ;
60
- console . log ( `\n🔍 MCP Inspector is up and running at http://127.0.0.1:${ CLIENT_PORT } ${ portParam } 🚀` ) ;
61
- try {
62
- await Promise . any ( [ server , client ] ) ;
63
- }
64
- catch ( e ) {
65
- if ( ! cancelled || process . env . DEBUG ) {
66
- throw e ;
67
- }
25
+ const inspectorServerPath = resolve (
26
+ __dirname ,
27
+ ".." ,
28
+ "server" ,
29
+ "build" ,
30
+ "index.js" ,
31
+ ) ;
32
+ // Path to the client entry point
33
+ const inspectorClientPath = resolve (
34
+ __dirname ,
35
+ ".." ,
36
+ "client" ,
37
+ "bin" ,
38
+ "cli.js" ,
39
+ ) ;
40
+ const CLIENT_PORT = process . env . CLIENT_PORT ?? "5173" ;
41
+ const SERVER_PORT = process . env . SERVER_PORT ?? "3000" ;
42
+ console . log ( "Starting MCP inspector..." ) ;
43
+ const abort = new AbortController ( ) ;
44
+ let cancelled = false ;
45
+ process . on ( "SIGINT" , ( ) => {
46
+ cancelled = true ;
47
+ abort . abort ( ) ;
48
+ } ) ;
49
+ const server = spawnPromise (
50
+ "node" ,
51
+ [
52
+ inspectorServerPath ,
53
+ ...( args . command ? [ `--env` , args . command ] : [ ] ) ,
54
+ ...( args . args ? [ `--args=${ args . args . join ( " " ) } ` ] : [ ] ) ,
55
+ ] ,
56
+ {
57
+ env : {
58
+ ...process . env ,
59
+ PORT : SERVER_PORT ,
60
+ MCP_ENV_VARS : JSON . stringify ( args . envArgs ) ,
61
+ } ,
62
+ signal : abort . signal ,
63
+ echoOutput : true ,
64
+ } ,
65
+ ) ;
66
+ const client = spawnPromise ( "node" , [ inspectorClientPath ] , {
67
+ env : { ...process . env , PORT : CLIENT_PORT } ,
68
+ signal : abort . signal ,
69
+ echoOutput : true ,
70
+ } ) ;
71
+ // Make sure our server/client didn't immediately fail
72
+ await Promise . any ( [ server , client , delay ( 2 * 1000 ) ] ) ;
73
+ const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${ SERVER_PORT } ` ;
74
+ console . log (
75
+ `\n🔍 MCP Inspector is up and running at http://127.0.0.1:${ CLIENT_PORT } ${ portParam } 🚀` ,
76
+ ) ;
77
+ try {
78
+ await Promise . any ( [ server , client ] ) ;
79
+ } catch ( e ) {
80
+ if ( ! cancelled || process . env . DEBUG ) {
81
+ throw e ;
68
82
}
83
+ }
69
84
}
70
85
async function runCli ( args ) {
71
- const projectRoot = resolve ( __dirname , ".." ) ;
72
- const cliPath = resolve ( projectRoot , "cli" , "build" , "index.js" ) ;
73
- const abort = new AbortController ( ) ;
74
- let cancelled = false ;
75
- process . on ( "SIGINT" , ( ) => {
76
- cancelled = true ;
77
- abort . abort ( ) ;
86
+ const projectRoot = resolve ( __dirname , ".." ) ;
87
+ const cliPath = resolve ( projectRoot , "cli" , "build" , "index.js" ) ;
88
+ const abort = new AbortController ( ) ;
89
+ let cancelled = false ;
90
+ process . on ( "SIGINT" , ( ) => {
91
+ cancelled = true ;
92
+ abort . abort ( ) ;
93
+ } ) ;
94
+ try {
95
+ await spawnPromise ( "node" , [ cliPath , args . command , ...args . args ] , {
96
+ env : { ...process . env , ...args . envArgs } ,
97
+ signal : abort . signal ,
98
+ echoOutput : true ,
78
99
} ) ;
79
- try {
80
- await spawnPromise ( "node" , [ cliPath , args . command , ...args . args ] , {
81
- env : { ...process . env , ...args . envArgs } ,
82
- signal : abort . signal ,
83
- echoOutput : true ,
84
- } ) ;
85
- }
86
- catch ( e ) {
87
- if ( ! cancelled || process . env . DEBUG ) {
88
- throw e ;
89
- }
100
+ } catch ( e ) {
101
+ if ( ! cancelled || process . env . DEBUG ) {
102
+ throw e ;
90
103
}
104
+ }
91
105
}
92
106
function loadConfigFile ( configPath , serverName ) {
93
- try {
94
- const resolvedConfigPath = path . isAbsolute ( configPath )
95
- ? configPath
96
- : path . resolve ( process . cwd ( ) , configPath ) ;
97
- if ( ! fs . existsSync ( resolvedConfigPath ) ) {
98
- throw new Error ( `Config file not found: ${ resolvedConfigPath } ` ) ;
99
- }
100
- const configContent = fs . readFileSync ( resolvedConfigPath , "utf8" ) ;
101
- const parsedConfig = JSON . parse ( configContent ) ;
102
- if ( ! parsedConfig . mcpServers || ! parsedConfig . mcpServers [ serverName ] ) {
103
- const availableServers = Object . keys ( parsedConfig . mcpServers || { } ) . join ( ", " ) ;
104
- throw new Error ( `Server '${ serverName } ' not found in config file. Available servers: ${ availableServers } ` ) ;
105
- }
106
- const serverConfig = parsedConfig . mcpServers [ serverName ] ;
107
- return serverConfig ;
107
+ try {
108
+ const resolvedConfigPath = path . isAbsolute ( configPath )
109
+ ? configPath
110
+ : path . resolve ( process . cwd ( ) , configPath ) ;
111
+ if ( ! fs . existsSync ( resolvedConfigPath ) ) {
112
+ throw new Error ( `Config file not found: ${ resolvedConfigPath } ` ) ;
108
113
}
109
- catch ( err ) {
110
- if ( err instanceof SyntaxError ) {
111
- throw new Error ( `Invalid JSON in config file: ${ err . message } ` ) ;
112
- }
113
- throw err ;
114
+ const configContent = fs . readFileSync ( resolvedConfigPath , "utf8" ) ;
115
+ const parsedConfig = JSON . parse ( configContent ) ;
116
+ if ( ! parsedConfig . mcpServers || ! parsedConfig . mcpServers [ serverName ] ) {
117
+ const availableServers = Object . keys ( parsedConfig . mcpServers || { } ) . join (
118
+ ", " ,
119
+ ) ;
120
+ throw new Error (
121
+ `Server '${ serverName } ' not found in config file. Available servers: ${ availableServers } ` ,
122
+ ) ;
114
123
}
124
+ const serverConfig = parsedConfig . mcpServers [ serverName ] ;
125
+ return serverConfig ;
126
+ } catch ( err ) {
127
+ if ( err instanceof SyntaxError ) {
128
+ throw new Error ( `Invalid JSON in config file: ${ err . message } ` ) ;
129
+ }
130
+ throw err ;
131
+ }
115
132
}
116
133
function parseKeyValuePair ( value , previous = { } ) {
117
- const parts = value . split ( "=" ) ;
118
- const key = parts [ 0 ] ;
119
- const val = parts . slice ( 1 ) . join ( "=" ) ;
120
- if ( val === undefined || val === "" ) {
121
- throw new Error ( `Invalid parameter format: ${ value } . Use key=value format.` ) ;
122
- }
123
- return { ...previous , [ key ] : val } ;
134
+ const parts = value . split ( "=" ) ;
135
+ const key = parts [ 0 ] ;
136
+ const val = parts . slice ( 1 ) . join ( "=" ) ;
137
+ if ( val === undefined || val === "" ) {
138
+ throw new Error (
139
+ `Invalid parameter format: ${ value } . Use key=value format.` ,
140
+ ) ;
141
+ }
142
+ return { ...previous , [ key ] : val } ;
124
143
}
125
144
function parseArgs ( ) {
126
- const program = new Command ( ) ;
127
- const argSeparatorIndex = process . argv . indexOf ( "--" ) ;
128
- let preArgs = process . argv ;
129
- let postArgs = [ ] ;
130
- if ( argSeparatorIndex !== - 1 ) {
131
- preArgs = process . argv . slice ( 0 , argSeparatorIndex ) ;
132
- postArgs = process . argv . slice ( argSeparatorIndex + 1 ) ;
133
- }
134
- program
135
- . name ( "inspector-bin" )
136
- . allowExcessArguments ( )
137
- . allowUnknownOption ( )
138
- . option ( "-e <env>" , "environment variables in KEY=VALUE format" , parseKeyValuePair , { } )
139
- . option ( "--config <path>" , "config file path" )
140
- . option ( "--server <n>" , "server name from config file" )
141
- . option ( "--cli" , "enable CLI mode" ) ;
142
- // Parse only the arguments before --
143
- program . parse ( preArgs ) ;
144
- const options = program . opts ( ) ;
145
- const remainingArgs = program . args ;
146
- // Add back any arguments that came after --
147
- const finalArgs = [ ...remainingArgs , ...postArgs ] ;
148
- // Validate that config and server are provided together
149
- if ( ( options . config && ! options . server ) ||
150
- ( ! options . config && options . server ) ) {
151
- throw new Error ( "Both --config and --server must be provided together. If you specify one, you must specify the other." ) ;
152
- }
153
- // If config file is specified, load and use the options from the file. We must merge the args
154
- // from the command line and the file together, or we will miss the method options (--method,
155
- // etc.)
156
- if ( options . config && options . server ) {
157
- const config = loadConfigFile ( options . config , options . server ) ;
158
- return {
159
- command : config . command ,
160
- args : [ ...( config . args || [ ] ) , ...finalArgs ] ,
161
- envArgs : { ...( config . env || { } ) , ...( options . e || { } ) } ,
162
- cli : options . cli || false ,
163
- } ;
164
- }
165
- // Otherwise use command line arguments
166
- const command = finalArgs [ 0 ] || "" ;
167
- const args = finalArgs . slice ( 1 ) ;
145
+ const program = new Command ( ) ;
146
+ const argSeparatorIndex = process . argv . indexOf ( "--" ) ;
147
+ let preArgs = process . argv ;
148
+ let postArgs = [ ] ;
149
+ if ( argSeparatorIndex !== - 1 ) {
150
+ preArgs = process . argv . slice ( 0 , argSeparatorIndex ) ;
151
+ postArgs = process . argv . slice ( argSeparatorIndex + 1 ) ;
152
+ }
153
+ program
154
+ . name ( "inspector-bin" )
155
+ . allowExcessArguments ( )
156
+ . allowUnknownOption ( )
157
+ . option (
158
+ "-e <env>" ,
159
+ "environment variables in KEY=VALUE format" ,
160
+ parseKeyValuePair ,
161
+ { } ,
162
+ )
163
+ . option ( "--config <path>" , "config file path" )
164
+ . option ( "--server <n>" , "server name from config file" )
165
+ . option ( "--cli" , "enable CLI mode" ) ;
166
+ // Parse only the arguments before --
167
+ program . parse ( preArgs ) ;
168
+ const options = program . opts ( ) ;
169
+ const remainingArgs = program . args ;
170
+ // Add back any arguments that came after --
171
+ const finalArgs = [ ...remainingArgs , ...postArgs ] ;
172
+ // Validate that config and server are provided together
173
+ if (
174
+ ( options . config && ! options . server ) ||
175
+ ( ! options . config && options . server )
176
+ ) {
177
+ throw new Error (
178
+ "Both --config and --server must be provided together. If you specify one, you must specify the other." ,
179
+ ) ;
180
+ }
181
+ // If config file is specified, load and use the options from the file. We must merge the args
182
+ // from the command line and the file together, or we will miss the method options (--method,
183
+ // etc.)
184
+ if ( options . config && options . server ) {
185
+ const config = loadConfigFile ( options . config , options . server ) ;
168
186
return {
169
- command,
170
- args,
171
- envArgs : options . e || { } ,
172
- cli : options . cli || false ,
187
+ command : config . command ,
188
+ args : [ ... ( config . args || [ ] ) , ... finalArgs ] ,
189
+ envArgs : { ... ( config . env || { } ) , ... ( options . e || { } ) } ,
190
+ cli : options . cli || false ,
173
191
} ;
192
+ }
193
+ // Otherwise use command line arguments
194
+ const command = finalArgs [ 0 ] || "" ;
195
+ const args = finalArgs . slice ( 1 ) ;
196
+ return {
197
+ command,
198
+ args,
199
+ envArgs : options . e || { } ,
200
+ cli : options . cli || false ,
201
+ } ;
174
202
}
175
203
async function main ( ) {
176
- process . on ( "uncaughtException" , ( error ) => {
177
- handleError ( error ) ;
178
- } ) ;
179
- try {
180
- const args = parseArgs ( ) ;
181
- if ( args . cli ) {
182
- runCli ( args ) ;
183
- }
184
- else {
185
- await runWebClient ( args ) ;
186
- }
187
- }
188
- catch ( error ) {
189
- handleError ( error ) ;
204
+ process . on ( "uncaughtException" , ( error ) => {
205
+ handleError ( error ) ;
206
+ } ) ;
207
+ try {
208
+ const args = parseArgs ( ) ;
209
+ if ( args . cli ) {
210
+ runCli ( args ) ;
211
+ } else {
212
+ await runWebClient ( args ) ;
190
213
}
214
+ } catch ( error ) {
215
+ handleError ( error ) ;
216
+ }
191
217
}
192
218
main ( ) ;
0 commit comments