prettier-fix

This commit is contained in:
Nicolas Barraud
2025-03-31 11:43:23 -04:00
parent 952e13edc1
commit 73d4cecdb1
2 changed files with 186 additions and 160 deletions

View File

@@ -7,186 +7,212 @@ import { spawnPromise } from "spawn-rx";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
function handleError(error) { function handleError(error) {
let message; let message;
if (error instanceof Error) { if (error instanceof Error) {
message = error.message; message = error.message;
} } else if (typeof error === "string") {
else if (typeof error === "string") { message = error;
message = error; } else {
} message = "Unknown error";
else { }
message = "Unknown error"; console.error(message);
} process.exit(1);
console.error(message);
process.exit(1);
} }
function delay(ms) { function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
async function runWebClient(args) { async function runWebClient(args) {
const inspectorServerPath = resolve(__dirname, "..", "server", "build", "index.js"); const inspectorServerPath = resolve(
// Path to the client entry point __dirname,
const inspectorClientPath = resolve(__dirname, "..", "client", "bin", "cli.js"); "..",
const CLIENT_PORT = process.env.CLIENT_PORT ?? "5173"; "server",
const SERVER_PORT = process.env.SERVER_PORT ?? "3000"; "build",
console.log("Starting MCP inspector..."); "index.js",
const abort = new AbortController(); );
let cancelled = false; // Path to the client entry point
process.on("SIGINT", () => { const inspectorClientPath = resolve(
cancelled = true; __dirname,
abort.abort(); "..",
}); "client",
const server = spawnPromise("node", [ "bin",
inspectorServerPath, "cli.js",
...(args.command ? [`--env`, args.command] : []), );
...(args.args ? [`--args=${args.args.join(" ")}`] : []), const CLIENT_PORT = process.env.CLIENT_PORT ?? "5173";
], { const SERVER_PORT = process.env.SERVER_PORT ?? "3000";
env: { console.log("Starting MCP inspector...");
...process.env, const abort = new AbortController();
PORT: SERVER_PORT, let cancelled = false;
MCP_ENV_VARS: JSON.stringify(args.envArgs), process.on("SIGINT", () => {
}, cancelled = true;
signal: abort.signal, abort.abort();
echoOutput: true, });
}); const server = spawnPromise(
const client = spawnPromise("node", [inspectorClientPath], { "node",
env: { ...process.env, PORT: CLIENT_PORT }, [
signal: abort.signal, inspectorServerPath,
echoOutput: true, ...(args.command ? [`--env`, args.command] : []),
}); ...(args.args ? [`--args=${args.args.join(" ")}`] : []),
// Make sure our server/client didn't immediately fail ],
await Promise.any([server, client, delay(2 * 1000)]); {
const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${SERVER_PORT}`; env: {
console.log(`\n🔍 MCP Inspector is up and running at http://127.0.0.1:${CLIENT_PORT}${portParam} 🚀`); ...process.env,
try { PORT: SERVER_PORT,
await Promise.any([server, client]); MCP_ENV_VARS: JSON.stringify(args.envArgs),
} },
catch (e) { signal: abort.signal,
if (!cancelled || process.env.DEBUG) { echoOutput: true,
throw e; },
} );
const client = spawnPromise("node", [inspectorClientPath], {
env: { ...process.env, PORT: CLIENT_PORT },
signal: abort.signal,
echoOutput: true,
});
// Make sure our server/client didn't immediately fail
await Promise.any([server, client, delay(2 * 1000)]);
const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${SERVER_PORT}`;
console.log(
`\n🔍 MCP Inspector is up and running at http://127.0.0.1:${CLIENT_PORT}${portParam} 🚀`,
);
try {
await Promise.any([server, client]);
} catch (e) {
if (!cancelled || process.env.DEBUG) {
throw e;
} }
}
} }
async function runCli(args) { async function runCli(args) {
const projectRoot = resolve(__dirname, ".."); const projectRoot = resolve(__dirname, "..");
const cliPath = resolve(projectRoot, "cli", "build", "index.js"); const cliPath = resolve(projectRoot, "cli", "build", "index.js");
const abort = new AbortController(); const abort = new AbortController();
let cancelled = false; let cancelled = false;
process.on("SIGINT", () => { process.on("SIGINT", () => {
cancelled = true; cancelled = true;
abort.abort(); abort.abort();
});
try {
await spawnPromise("node", [cliPath, args.command, ...args.args], {
env: { ...process.env, ...args.envArgs },
signal: abort.signal,
echoOutput: true,
}); });
try { } catch (e) {
await spawnPromise("node", [cliPath, args.command, ...args.args], { if (!cancelled || process.env.DEBUG) {
env: { ...process.env, ...args.envArgs }, throw e;
signal: abort.signal,
echoOutput: true,
});
}
catch (e) {
if (!cancelled || process.env.DEBUG) {
throw e;
}
} }
}
} }
function loadConfigFile(configPath, serverName) { function loadConfigFile(configPath, serverName) {
try { try {
const resolvedConfigPath = path.isAbsolute(configPath) const resolvedConfigPath = path.isAbsolute(configPath)
? configPath ? configPath
: path.resolve(process.cwd(), configPath); : path.resolve(process.cwd(), configPath);
if (!fs.existsSync(resolvedConfigPath)) { if (!fs.existsSync(resolvedConfigPath)) {
throw new Error(`Config file not found: ${resolvedConfigPath}`); throw new Error(`Config file not found: ${resolvedConfigPath}`);
}
const configContent = fs.readFileSync(resolvedConfigPath, "utf8");
const parsedConfig = JSON.parse(configContent);
if (!parsedConfig.mcpServers || !parsedConfig.mcpServers[serverName]) {
const availableServers = Object.keys(parsedConfig.mcpServers || {}).join(", ");
throw new Error(`Server '${serverName}' not found in config file. Available servers: ${availableServers}`);
}
const serverConfig = parsedConfig.mcpServers[serverName];
return serverConfig;
} }
catch (err) { const configContent = fs.readFileSync(resolvedConfigPath, "utf8");
if (err instanceof SyntaxError) { const parsedConfig = JSON.parse(configContent);
throw new Error(`Invalid JSON in config file: ${err.message}`); if (!parsedConfig.mcpServers || !parsedConfig.mcpServers[serverName]) {
} const availableServers = Object.keys(parsedConfig.mcpServers || {}).join(
throw err; ", ",
);
throw new Error(
`Server '${serverName}' not found in config file. Available servers: ${availableServers}`,
);
} }
const serverConfig = parsedConfig.mcpServers[serverName];
return serverConfig;
} catch (err) {
if (err instanceof SyntaxError) {
throw new Error(`Invalid JSON in config file: ${err.message}`);
}
throw err;
}
} }
function parseKeyValuePair(value, previous = {}) { function parseKeyValuePair(value, previous = {}) {
const parts = value.split("="); const parts = value.split("=");
const key = parts[0]; const key = parts[0];
const val = parts.slice(1).join("="); const val = parts.slice(1).join("=");
if (val === undefined || val === "") { if (val === undefined || val === "") {
throw new Error(`Invalid parameter format: ${value}. Use key=value format.`); throw new Error(
} `Invalid parameter format: ${value}. Use key=value format.`,
return { ...previous, [key]: val }; );
}
return { ...previous, [key]: val };
} }
function parseArgs() { function parseArgs() {
const program = new Command(); const program = new Command();
const argSeparatorIndex = process.argv.indexOf("--"); const argSeparatorIndex = process.argv.indexOf("--");
let preArgs = process.argv; let preArgs = process.argv;
let postArgs = []; let postArgs = [];
if (argSeparatorIndex !== -1) { if (argSeparatorIndex !== -1) {
preArgs = process.argv.slice(0, argSeparatorIndex); preArgs = process.argv.slice(0, argSeparatorIndex);
postArgs = process.argv.slice(argSeparatorIndex + 1); postArgs = process.argv.slice(argSeparatorIndex + 1);
} }
program program
.name("inspector-bin") .name("inspector-bin")
.allowExcessArguments() .allowExcessArguments()
.allowUnknownOption() .allowUnknownOption()
.option("-e <env>", "environment variables in KEY=VALUE format", parseKeyValuePair, {}) .option(
.option("--config <path>", "config file path") "-e <env>",
.option("--server <n>", "server name from config file") "environment variables in KEY=VALUE format",
.option("--cli", "enable CLI mode"); parseKeyValuePair,
// Parse only the arguments before -- {},
program.parse(preArgs); )
const options = program.opts(); .option("--config <path>", "config file path")
const remainingArgs = program.args; .option("--server <n>", "server name from config file")
// Add back any arguments that came after -- .option("--cli", "enable CLI mode");
const finalArgs = [...remainingArgs, ...postArgs]; // Parse only the arguments before --
// Validate that config and server are provided together program.parse(preArgs);
if ((options.config && !options.server) || const options = program.opts();
(!options.config && options.server)) { const remainingArgs = program.args;
throw new Error("Both --config and --server must be provided together. If you specify one, you must specify the other."); // Add back any arguments that came after --
} const finalArgs = [...remainingArgs, ...postArgs];
// If config file is specified, load and use the options from the file. We must merge the args // Validate that config and server are provided together
// from the command line and the file together, or we will miss the method options (--method, if (
// etc.) (options.config && !options.server) ||
if (options.config && options.server) { (!options.config && options.server)
const config = loadConfigFile(options.config, options.server); ) {
return { throw new Error(
command: config.command, "Both --config and --server must be provided together. If you specify one, you must specify the other.",
args: [...(config.args || []), ...finalArgs], );
envArgs: { ...(config.env || {}), ...(options.e || {}) }, }
cli: options.cli || false, // If config file is specified, load and use the options from the file. We must merge the args
}; // from the command line and the file together, or we will miss the method options (--method,
} // etc.)
// Otherwise use command line arguments if (options.config && options.server) {
const command = finalArgs[0] || ""; const config = loadConfigFile(options.config, options.server);
const args = finalArgs.slice(1);
return { return {
command, command: config.command,
args, args: [...(config.args || []), ...finalArgs],
envArgs: options.e || {}, envArgs: { ...(config.env || {}), ...(options.e || {}) },
cli: options.cli || false, cli: options.cli || false,
}; };
}
// Otherwise use command line arguments
const command = finalArgs[0] || "";
const args = finalArgs.slice(1);
return {
command,
args,
envArgs: options.e || {},
cli: options.cli || false,
};
} }
async function main() { async function main() {
process.on("uncaughtException", (error) => { process.on("uncaughtException", (error) => {
handleError(error); handleError(error);
}); });
try { try {
const args = parseArgs(); const args = parseArgs();
if (args.cli) { if (args.cli) {
runCli(args); runCli(args);
} } else {
else { await runWebClient(args);
await runWebClient(args);
}
}
catch (error) {
handleError(error);
} }
} catch (error) {
handleError(error);
}
} }
main(); main();

View File

@@ -28,7 +28,7 @@
"dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"", "dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"",
"dev:windows": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev:windows\"", "dev:windows": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev:windows\"",
"test": "npm run prettier-check && cd client && npm test", "test": "npm run prettier-check && cd client && npm test",
"test:cli": "cd bin && npm run test", "test-cli": "cd bin && npm run test",
"build-bin": "cd bin && npm run build", "build-bin": "cd bin && npm run build",
"build-server": "cd server && npm run build", "build-server": "cd server && npm run build",
"build-client": "cd client && npm run build", "build-client": "cd client && npm run build",