From f280bd70df99d115fd568b43863ddd013404fb6d Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:02:21 +0100 Subject: [PATCH 1/6] fix(port): support configurable/free electron and cli ports --- mcpjam-inspector/bin/start.js | 62 ++++++++++++++++------ mcpjam-inspector/src/main.ts | 98 +++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 22 deletions(-) diff --git a/mcpjam-inspector/bin/start.js b/mcpjam-inspector/bin/start.js index 5be373298..6bd6cea29 100755 --- a/mcpjam-inspector/bin/start.js +++ b/mcpjam-inspector/bin/start.js @@ -120,11 +120,11 @@ function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms, true)); } -function isPortAvailable(port) { +function isPortAvailable(port, host = "127.0.0.1") { return new Promise((resolve) => { const server = createServer(); - server.listen(port, "127.0.0.1", () => { + server.listen(port, host, () => { server.close(() => { resolve(true); }); @@ -137,6 +137,31 @@ function isPortAvailable(port) { }); } +function parsePort(value) { + const parsed = Number.parseInt(value, 10); + if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) { + throw new Error(`Invalid port value: ${value}`); + } + return parsed; +} + +async function findAvailablePort(startPort, maxPortOffset = 100, verbose = false) { + const defaultHost = process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; + + for (let port = startPort; port <= startPort + maxPortOffset; port++) { + const isAvailable = await isPortAvailable(port, defaultHost); + if (isAvailable) { + return port; + } + + if (verbose) { + logWarning(`Port ${port} unavailable; checking next port`); + } + } + + throw new Error(`No available port found in range ${startPort}-${startPort + maxPortOffset}`); +} + function spawnPromise(command, args, options) { return new Promise((resolve, reject) => { const child = spawn(command, args, { @@ -623,17 +648,25 @@ async function main() { // Apply parsed environment variables to process.env first Object.assign(process.env, envVars); - // Port configuration (fixed default to 6274) - const requestedPort = 6274; + const requestedPortCandidate = + process.env.SERVER_PORT !== undefined + ? process.env.SERVER_PORT + : envVars.PORT; + const requestedPort = requestedPortCandidate + ? parsePort(requestedPortCandidate) + : 6274; let PORT; + const defaultHost = + process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; + const baseHost = process.env.HOST || defaultHost; try { // Check if user explicitly set a port via --port flag - const hasExplicitPort = envVars.PORT !== undefined; + const hasExplicitPort = requestedPortCandidate !== undefined; if (hasExplicitPort) { - if (await isPortAvailable(requestedPort)) { - PORT = requestedPort.toString(); + if (await isPortAvailable(requestedPort, baseHost)) { + PORT = String(requestedPort); } else { logError(`Explicitly requested port ${requestedPort} is not available`); logInfo( @@ -642,23 +675,18 @@ async function main() { throw new Error(`Port ${requestedPort} is already in use`); } } else { - // Fixed port policy: use default port 6274 and fail fast if unavailable - if (await isPortAvailable(requestedPort)) { - PORT = requestedPort.toString(); - } else { - logError( - `Default port ${requestedPort} is already in use. Please free the port`, + const resolvedPort = await findAvailablePort(requestedPort, 100, true); + if (resolvedPort !== requestedPort) { + logInfo( + `Default port ${requestedPort} is busy. Using next available port ${resolvedPort}.`, ); - throw new Error(`Port ${requestedPort} is already in use`); } + PORT = String(resolvedPort); } // Update environment variables with the final port envVars.PORT = PORT; // Default: localhost in development, 127.0.0.1 in production - const defaultHost = - process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; - const baseHost = process.env.HOST || defaultHost; envVars.BASE_URL = `http://${baseHost}:${PORT}`; Object.assign(process.env, envVars); } catch (error) { diff --git a/mcpjam-inspector/src/main.ts b/mcpjam-inspector/src/main.ts index f13a4dac3..3a4a16ed2 100644 --- a/mcpjam-inspector/src/main.ts +++ b/mcpjam-inspector/src/main.ts @@ -9,8 +9,8 @@ Sentry.init({ import { app, BrowserWindow, shell, Menu } from "electron"; import { serve } from "@hono/node-server"; +import { createServer } from "node:net"; import path from "path"; -import { createHonoApp } from "../server/app.js"; import log from "electron-log"; import { updateElectronApp } from "update-electron-app"; import { registerListeners } from "./ipc/listeners-register.js"; @@ -41,10 +41,99 @@ let server: any = null; let serverPort: number = 0; const isDev = process.env.NODE_ENV === "development"; +const DEFAULT_ELECTRON_PORT = 6274; +const PORT_SCAN_LIMIT = 100; + +type PortParseResult = { + value: number; + isExplicit: boolean; +}; + +function parsePort(value: string | undefined, fallback: number): PortParseResult { + if (value === undefined || value.trim() === "") { + return { value: fallback, isExplicit: false }; + } + + const parsed = Number.parseInt(value, 10); + if ( + !Number.isFinite(parsed) || + !Number.isInteger(parsed) || + parsed <= 0 || + parsed > 65535 + ) { + log.warn(`Ignoring invalid port value "${value}", using fallback ${fallback}`); + return { value: fallback, isExplicit: false }; + } + + return { value: parsed, isExplicit: true }; +} + +function getRequestedPort(): { + port: number; + hasExplicitPort: boolean; +} { + const explicitPort = + process.env.ELECTRON_PORT ?? + process.env.SERVER_PORT ?? + process.env.PORT; + const parsedPort = parsePort(explicitPort, DEFAULT_ELECTRON_PORT); + + return { + port: parsedPort.value, + hasExplicitPort: parsedPort.isExplicit, + }; +} + +function isPortAvailable(port: number, host: string): Promise { + return new Promise((resolve) => { + const server = createServer(); + server.listen(port, host, () => { + server.close(() => { + resolve(true); + }); + }); + + server.on("error", () => { + resolve(false); + }); + }); +} + +async function findAvailablePort( + requestedPort: number, + host: string, + hasExplicitPort = false, +): Promise { + if (await isPortAvailable(requestedPort, host)) { + return requestedPort; + } + + if (hasExplicitPort) { + throw new Error(`Requested port ${requestedPort} is already in use`); + } + + for (let port = requestedPort + 1; port <= requestedPort + PORT_SCAN_LIMIT; port++) { + if (await isPortAvailable(port, host)) { + log.warn( + `Port ${requestedPort} was unavailable. Using fallback free port ${port}`, + ); + return port; + } + } + + throw new Error( + `No available port found in range ${requestedPort}-${ + requestedPort + PORT_SCAN_LIMIT + }`, + ); +} async function startHonoServer(): Promise { try { - const port = 6274; + const hostname = app.isPackaged ? "127.0.0.1" : "localhost"; + const { port: requestedPort, hasExplicitPort } = getRequestedPort(); + const port = await findAvailablePort(requestedPort, hostname, hasExplicitPort); + // Set environment variables to tell the server it's running in Electron process.env.ELECTRON_APP = "true"; process.env.IS_PACKAGED = app.isPackaged ? "true" : "false"; @@ -53,12 +142,11 @@ async function startHonoServer(): Promise { ? process.resourcesPath : app.getAppPath(); process.env.NODE_ENV = app.isPackaged ? "production" : "development"; + process.env.SERVER_PORT = String(port); + const { createHonoApp } = await import("../server/app.js"); const honoApp = createHonoApp(); - // Bind to 127.0.0.1 when packaged to avoid IPv6-only localhost issues - const hostname = app.isPackaged ? "127.0.0.1" : "localhost"; - server = serve({ fetch: honoApp.fetch, port, From 63fd30be09e08a2e799a74873a9b6ddd50d2bc8d Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:15:55 +0100 Subject: [PATCH 2/6] fix: align port scan host/availability checks - respect HOST in CLI port scanning fallback - harden port probe lifecycle with timeout and listener cleanup - cap port scan at 65535 and improve fallback error handling --- mcpjam-inspector/bin/start.js | 74 +++++++++++++++++++++++---------- mcpjam-inspector/src/main.ts | 78 ++++++++++++++++++++++++++--------- 2 files changed, 112 insertions(+), 40 deletions(-) diff --git a/mcpjam-inspector/bin/start.js b/mcpjam-inspector/bin/start.js index 6bd6cea29..1671c208a 100755 --- a/mcpjam-inspector/bin/start.js +++ b/mcpjam-inspector/bin/start.js @@ -123,17 +123,46 @@ function delay(ms) { function isPortAvailable(port, host = "127.0.0.1") { return new Promise((resolve) => { const server = createServer(); + let settled = false; + const timeout = setTimeout(() => { + if (settled) { + return; + } + settled = true; + cleanup(); + server.close(); + resolve(false); + }, 1000); + + const cleanup = () => { + clearTimeout(timeout); + server.removeListener("error", onError); + server.removeListener("listening", onListening); + }; - server.listen(port, host, () => { + const onListening = () => { + if (settled) { + return; + } + settled = true; + cleanup(); server.close(() => { resolve(true); }); - }); + }; - server.on("error", () => { - // Port is not available + const onError = () => { + if (settled) { + return; + } + settled = true; + cleanup(); resolve(false); - }); + }; + + server.once("error", onError); + server.once("listening", onListening); + server.listen(port, host); }); } @@ -145,11 +174,22 @@ function parsePort(value) { return parsed; } -async function findAvailablePort(startPort, maxPortOffset = 100, verbose = false) { - const defaultHost = process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; +async function findAvailablePort( + startPort, + host, + maxPortOffset = 100, + verbose = false, +) { + const maxPort = Math.min(startPort + maxPortOffset, 65535); + + if (maxPort <= startPort) { + throw new Error( + `No available port found in range ${startPort}-${maxPort}`, + ); + } - for (let port = startPort; port <= startPort + maxPortOffset; port++) { - const isAvailable = await isPortAvailable(port, defaultHost); + for (let port = startPort; port <= maxPort; port++) { + const isAvailable = await isPortAvailable(port, host); if (isAvailable) { return port; } @@ -159,7 +199,7 @@ async function findAvailablePort(startPort, maxPortOffset = 100, verbose = false } } - throw new Error(`No available port found in range ${startPort}-${startPort + maxPortOffset}`); + throw new Error(`No available port found in range ${startPort}-${maxPort}`); } function spawnPromise(command, args, options) { @@ -382,11 +422,6 @@ async function main() { if (parsingFlags && arg === "--port" && i + 1 < args.length) { const port = args[++i]; envVars.PORT = port; - // Default: localhost in development, 127.0.0.1 in production - const defaultHost = - process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; - const baseHost = process.env.HOST || defaultHost; - envVars.BASE_URL = `http://${baseHost}:${port}`; continue; } @@ -659,13 +694,14 @@ async function main() { const defaultHost = process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; const baseHost = process.env.HOST || defaultHost; + const host = baseHost; try { // Check if user explicitly set a port via --port flag const hasExplicitPort = requestedPortCandidate !== undefined; if (hasExplicitPort) { - if (await isPortAvailable(requestedPort, baseHost)) { + if (await isPortAvailable(requestedPort, host)) { PORT = String(requestedPort); } else { logError(`Explicitly requested port ${requestedPort} is not available`); @@ -675,7 +711,7 @@ async function main() { throw new Error(`Port ${requestedPort} is already in use`); } } else { - const resolvedPort = await findAvailablePort(requestedPort, 100, true); + const resolvedPort = await findAvailablePort(requestedPort, host, 100, true); if (resolvedPort !== requestedPort) { logInfo( `Default port ${requestedPort} is busy. Using next available port ${resolvedPort}.`, @@ -686,7 +722,6 @@ async function main() { // Update environment variables with the final port envVars.PORT = PORT; - // Default: localhost in development, 127.0.0.1 in production envVars.BASE_URL = `http://${baseHost}:${PORT}`; Object.assign(process.env, envVars); } catch (error) { @@ -772,9 +807,6 @@ async function main() { // Open the browser automatically // Use BASE_URL if set, otherwise construct from HOST and PORT // Default: localhost in development, 127.0.0.1 in production - const defaultHost = - process.env.ENVIRONMENT === "dev" ? "localhost" : "127.0.0.1"; - const host = process.env.HOST || defaultHost; let url = process.env.BASE_URL || `http://${host}:${PORT}`; // Append initial tab hash if specified diff --git a/mcpjam-inspector/src/main.ts b/mcpjam-inspector/src/main.ts index 3a4a16ed2..834705264 100644 --- a/mcpjam-inspector/src/main.ts +++ b/mcpjam-inspector/src/main.ts @@ -43,6 +43,7 @@ let serverPort: number = 0; const isDev = process.env.NODE_ENV === "development"; const DEFAULT_ELECTRON_PORT = 6274; const PORT_SCAN_LIMIT = 100; +const MAX_PORT_NUMBER = 65535; type PortParseResult = { value: number; @@ -55,12 +56,7 @@ function parsePort(value: string | undefined, fallback: number): PortParseResult } const parsed = Number.parseInt(value, 10); - if ( - !Number.isFinite(parsed) || - !Number.isInteger(parsed) || - parsed <= 0 || - parsed > 65535 - ) { + if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0 || parsed > MAX_PORT_NUMBER) { log.warn(`Ignoring invalid port value "${value}", using fallback ${fallback}`); return { value: fallback, isExplicit: false }; } @@ -87,15 +83,46 @@ function getRequestedPort(): { function isPortAvailable(port: number, host: string): Promise { return new Promise((resolve) => { const server = createServer(); - server.listen(port, host, () => { + let settled = false; + const timeout = setTimeout(() => { + if (settled) { + return; + } + settled = true; + cleanup(); + server.close(); + resolve(false); + }, 1000); + + const cleanup = () => { + clearTimeout(timeout); + server.removeListener("error", onError); + server.removeListener("listening", onListening); + }; + + const onListening = () => { + if (settled) { + return; + } + settled = true; + cleanup(); server.close(() => { resolve(true); }); - }); + }; - server.on("error", () => { + const onError = () => { + if (settled) { + return; + } + settled = true; + cleanup(); resolve(false); - }); + }; + + server.once("error", onError); + server.once("listening", onListening); + server.listen(port, host); }); } @@ -104,6 +131,10 @@ async function findAvailablePort( host: string, hasExplicitPort = false, ): Promise { + if (requestedPort < 1 || requestedPort > MAX_PORT_NUMBER) { + throw new Error(`Requested port ${requestedPort} is outside valid range 1-${MAX_PORT_NUMBER}`); + } + if (await isPortAvailable(requestedPort, host)) { return requestedPort; } @@ -112,7 +143,12 @@ async function findAvailablePort( throw new Error(`Requested port ${requestedPort} is already in use`); } - for (let port = requestedPort + 1; port <= requestedPort + PORT_SCAN_LIMIT; port++) { + const maxPort = Math.min(requestedPort + PORT_SCAN_LIMIT, MAX_PORT_NUMBER); + if (maxPort <= requestedPort) { + throw new Error(`No available port found in range ${requestedPort}-${maxPort}`); + } + + for (let port = requestedPort + 1; port <= maxPort; port++) { if (await isPortAvailable(port, host)) { log.warn( `Port ${requestedPort} was unavailable. Using fallback free port ${port}`, @@ -122,12 +158,14 @@ async function findAvailablePort( } throw new Error( - `No available port found in range ${requestedPort}-${ - requestedPort + PORT_SCAN_LIMIT - }`, + `No available port found in range ${requestedPort}-${maxPort}`, ); } +function getServerUrl(port: number, host: string): string { + return `http://${host}:${port}`; +} + async function startHonoServer(): Promise { try { const hostname = app.isPackaged ? "127.0.0.1" : "localhost"; @@ -153,7 +191,7 @@ async function startHonoServer(): Promise { hostname, }); - log.info(`🚀 MCPJam Server started on port ${port}`); + log.info(`🚀 MCPJam Server started on port ${port} (${hostname})`); return port; } catch (error) { log.error("Failed to start Hono server:", error); @@ -289,8 +327,9 @@ function createAppMenu(): void { app.whenReady().then(async () => { try { // Start the embedded Hono server + const serverHost = app.isPackaged ? "127.0.0.1" : "localhost"; serverPort = await startHonoServer(); - const serverUrl = `http://127.0.0.1:${serverPort}`; + const serverUrl = getServerUrl(serverPort, serverHost); // Create the main window createAppMenu(); @@ -325,14 +364,15 @@ app.on("window-all-closed", () => { app.on("activate", async () => { // On macOS, re-create window when the dock icon is clicked if (BrowserWindow.getAllWindows().length === 0) { + const serverHost = app.isPackaged ? "127.0.0.1" : "localhost"; if (serverPort > 0) { - const serverUrl = `http://127.0.0.1:${serverPort}`; + const serverUrl = getServerUrl(serverPort, serverHost); mainWindow = createMainWindow(serverUrl); } else { // Restart server if needed try { serverPort = await startHonoServer(); - const serverUrl = `http://127.0.0.1:${serverPort}`; + const serverUrl = getServerUrl(serverPort, serverHost); mainWindow = createMainWindow(serverUrl); } catch (error) { log.error("Failed to restart server:", error); @@ -358,7 +398,7 @@ app.on("open-url", (event, url) => { // Compute the base URL the renderer should load const baseUrl = isDev ? MAIN_WINDOW_VITE_DEV_SERVER_URL - : `http://127.0.0.1:${serverPort}`; + : getServerUrl(serverPort, app.isPackaged ? "127.0.0.1" : "localhost"); const callbackUrl = new URL("/callback", baseUrl); if (code) callbackUrl.searchParams.set("code", code); From 0947472dba5fa697d98819faead2895a2881cd3f Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:23:31 +0100 Subject: [PATCH 3/6] fix: harden CLI/Electron port probe edge cases - add no-op close-time error guards with timeout handling in port probes - route fallback port scan verbosity through verboseLogs - align parsePort integer validation checks --- mcpjam-inspector/bin/start.js | 17 +++++++++++++---- mcpjam-inspector/src/main.ts | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mcpjam-inspector/bin/start.js b/mcpjam-inspector/bin/start.js index 1671c208a..55929c567 100755 --- a/mcpjam-inspector/bin/start.js +++ b/mcpjam-inspector/bin/start.js @@ -124,14 +124,23 @@ function isPortAvailable(port, host = "127.0.0.1") { return new Promise((resolve) => { const server = createServer(); let settled = false; + const onCloseError = () => {}; const timeout = setTimeout(() => { if (settled) { return; } settled = true; cleanup(); - server.close(); - resolve(false); + server.once("error", onCloseError); + try { + server.close(() => { + server.removeListener("error", onCloseError); + resolve(false); + }); + } catch { + server.removeListener("error", onCloseError); + resolve(false); + } }, 1000); const cleanup = () => { @@ -168,7 +177,7 @@ function isPortAvailable(port, host = "127.0.0.1") { function parsePort(value) { const parsed = Number.parseInt(value, 10); - if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) { + if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 65535) { throw new Error(`Invalid port value: ${value}`); } return parsed; @@ -711,7 +720,7 @@ async function main() { throw new Error(`Port ${requestedPort} is already in use`); } } else { - const resolvedPort = await findAvailablePort(requestedPort, host, 100, true); + const resolvedPort = await findAvailablePort(requestedPort, host, 100, verboseLogs); if (resolvedPort !== requestedPort) { logInfo( `Default port ${requestedPort} is busy. Using next available port ${resolvedPort}.`, diff --git a/mcpjam-inspector/src/main.ts b/mcpjam-inspector/src/main.ts index 834705264..d99dc68ad 100644 --- a/mcpjam-inspector/src/main.ts +++ b/mcpjam-inspector/src/main.ts @@ -56,7 +56,7 @@ function parsePort(value: string | undefined, fallback: number): PortParseResult } const parsed = Number.parseInt(value, 10); - if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0 || parsed > MAX_PORT_NUMBER) { + if (!Number.isFinite(parsed) || parsed <= 0 || parsed > MAX_PORT_NUMBER) { log.warn(`Ignoring invalid port value "${value}", using fallback ${fallback}`); return { value: fallback, isExplicit: false }; } @@ -84,14 +84,23 @@ function isPortAvailable(port: number, host: string): Promise { return new Promise((resolve) => { const server = createServer(); let settled = false; + const onCloseError = () => {}; const timeout = setTimeout(() => { if (settled) { return; } settled = true; cleanup(); - server.close(); - resolve(false); + server.once("error", onCloseError); + try { + server.close(() => { + server.removeListener("error", onCloseError); + resolve(false); + }); + } catch { + server.removeListener("error", onCloseError); + resolve(false); + } }, 1000); const cleanup = () => { From 04bd5816546e87a79e2e4a35240a9b493db21cad Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:31:38 +0100 Subject: [PATCH 4/6] fix: allow probing maxPort == startPort in start.js - change no-range check from <= to < so single-port scan at boundary is still attempted --- mcpjam-inspector/bin/start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpjam-inspector/bin/start.js b/mcpjam-inspector/bin/start.js index 55929c567..4d502baa8 100755 --- a/mcpjam-inspector/bin/start.js +++ b/mcpjam-inspector/bin/start.js @@ -191,7 +191,7 @@ async function findAvailablePort( ) { const maxPort = Math.min(startPort + maxPortOffset, 65535); - if (maxPort <= startPort) { + if (maxPort < startPort) { throw new Error( `No available port found in range ${startPort}-${maxPort}`, ); From 73a4d7152469b67a09358a0761c7e88a647a9ed8 Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:36:32 +0100 Subject: [PATCH 5/6] docs: add fork/local testing instructions - add README guidance for testing via local checkout and npx - mirror fork testing flow in AGENTS.md testing section --- mcpjam-inspector/AGENTS.md | 17 +++++++++++++++++ mcpjam-inspector/README.md | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/mcpjam-inspector/AGENTS.md b/mcpjam-inspector/AGENTS.md index 7d24c7355..d4fbc9e79 100644 --- a/mcpjam-inspector/AGENTS.md +++ b/mcpjam-inspector/AGENTS.md @@ -54,6 +54,23 @@ Browser `console.*` is acceptable for client-side debugging. **All changes should include tests.** Uses Vitest. Run with `npm run test` (or `test:watch`, `test:coverage`). +### Testing a fork or branch + +When testing changes from a fork/feature branch, prefer one of these flows: + +- Local checkout: + - `git clone https://github.com/ramarivera/inspector.git` + - `cd inspector` + - `git checkout ` + - `npm install` + - `npm run build` + - `npm run start -- --help` + +- Directly from fork with `npx`: + - `npx github:ramarivera/inspector# -- --help` + +- If `npx` branch fetch fails, use `npm link` from a local checkout. + ### Structure Tests live in `__tests__/` directories next to source files. Use existing tests as examples: diff --git a/mcpjam-inspector/README.md b/mcpjam-inspector/README.md index dc07828fe..b7581d328 100644 --- a/mcpjam-inspector/README.md +++ b/mcpjam-inspector/README.md @@ -58,6 +58,31 @@ We recommend starting MCPJam inspector via `npx`: npx @mcpjam/inspector@latest ``` +### Using your fork for testing + +To test changes on your own fork/branch: + +```bash +git clone https://github.com/ramarivera/inspector.git +cd inspector +git checkout codex/fix-dynamic-port-detection +npm install +npm run build +npm run start -- --help +``` + +To run directly from your fork with `npx` (no local install needed): + +```bash +npx github:ramarivera/inspector#codex/fix-dynamic-port-detection -- --help +``` + +> Notes: +> +> - Use `--help` to see all available CLI flags for your local branch version. +> - Use `npm run start -- --port 6274 --verbose` for a quick local smoke run. +> - If `npm pack`/`npx` cannot fetch the branch, use `npm link` from the cloned checkout instead. + We have a Mac and Windows desktop app: - [Install Mac](https://github.com/MCPJam/inspector/releases/latest/download/MCPJam.Inspector.dmg) From b6c529281c431b95e5be42dc0646ee024277ed5d Mon Sep 17 00:00:00 2001 From: Ramiro Rivera Date: Sat, 14 Feb 2026 02:37:07 +0100 Subject: [PATCH 6/6] Revert "docs: add fork/local testing instructions" This reverts commit 73a4d7152469b67a09358a0761c7e88a647a9ed8. --- mcpjam-inspector/AGENTS.md | 17 ----------------- mcpjam-inspector/README.md | 25 ------------------------- 2 files changed, 42 deletions(-) diff --git a/mcpjam-inspector/AGENTS.md b/mcpjam-inspector/AGENTS.md index d4fbc9e79..7d24c7355 100644 --- a/mcpjam-inspector/AGENTS.md +++ b/mcpjam-inspector/AGENTS.md @@ -54,23 +54,6 @@ Browser `console.*` is acceptable for client-side debugging. **All changes should include tests.** Uses Vitest. Run with `npm run test` (or `test:watch`, `test:coverage`). -### Testing a fork or branch - -When testing changes from a fork/feature branch, prefer one of these flows: - -- Local checkout: - - `git clone https://github.com/ramarivera/inspector.git` - - `cd inspector` - - `git checkout ` - - `npm install` - - `npm run build` - - `npm run start -- --help` - -- Directly from fork with `npx`: - - `npx github:ramarivera/inspector# -- --help` - -- If `npx` branch fetch fails, use `npm link` from a local checkout. - ### Structure Tests live in `__tests__/` directories next to source files. Use existing tests as examples: diff --git a/mcpjam-inspector/README.md b/mcpjam-inspector/README.md index b7581d328..dc07828fe 100644 --- a/mcpjam-inspector/README.md +++ b/mcpjam-inspector/README.md @@ -58,31 +58,6 @@ We recommend starting MCPJam inspector via `npx`: npx @mcpjam/inspector@latest ``` -### Using your fork for testing - -To test changes on your own fork/branch: - -```bash -git clone https://github.com/ramarivera/inspector.git -cd inspector -git checkout codex/fix-dynamic-port-detection -npm install -npm run build -npm run start -- --help -``` - -To run directly from your fork with `npx` (no local install needed): - -```bash -npx github:ramarivera/inspector#codex/fix-dynamic-port-detection -- --help -``` - -> Notes: -> -> - Use `--help` to see all available CLI flags for your local branch version. -> - Use `npm run start -- --port 6274 --verbose` for a quick local smoke run. -> - If `npm pack`/`npx` cannot fetch the branch, use `npm link` from the cloned checkout instead. - We have a Mac and Windows desktop app: - [Install Mac](https://github.com/MCPJam/inspector/releases/latest/download/MCPJam.Inspector.dmg)