@@ -7,186 +7,212 @@ import { spawnPromise } from "spawn-rx";
77import { fileURLToPath } from "url" ;
88const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
99function 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 ) ;
2220}
2321function delay ( ms ) {
24- return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
22+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
2523}
2624async 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 ;
6882 }
83+ }
6984}
7085async 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 ,
7899 } ) ;
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 ;
90103 }
104+ }
91105}
92106function 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 } ` ) ;
108113 }
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+ ) ;
114123 }
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+ }
115132}
116133function 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 } ;
124143}
125144function 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 ) ;
168186 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 ,
173191 } ;
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+ } ;
174202}
175203async 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 ) ;
190213 }
214+ } catch ( error ) {
215+ handleError ( error ) ;
216+ }
191217}
192218main ( ) ;
0 commit comments