Skip to content

Commit 57af0c9

Browse files
committed
Added browser open in prod launcher, cleanup up port in use error in prod, removed vestigial client launcher.
1 parent c667931 commit 57af0c9

5 files changed

Lines changed: 58 additions & 94 deletions

File tree

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/bin/client.js

Lines changed: 0 additions & 62 deletions
This file was deleted.

web/bin/start.js

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -112,33 +112,40 @@ async function startProdClient(clientOptions) {
112112
} = clientOptions;
113113
const honoServerPath = resolve(__dirname, "../dist/server.js");
114114

115-
// Inspector API server (Hono) serves static files + /api/* endpoints
116-
// Pass Inspector API auth token and config values explicitly via env vars (read-only, server reads them)
117-
await spawnPromise("node", [honoServerPath], {
118-
env: {
119-
...process.env,
120-
CLIENT_PORT,
121-
...(dangerouslyOmitAuth
122-
? {}
123-
: { [API_SERVER_ENV_VARS.AUTH_TOKEN]: inspectorApiToken }),
124-
// Pass config values for HTML injection
125-
...(command ? { MCP_INITIAL_COMMAND: command } : {}),
126-
...(mcpServerArgs && mcpServerArgs.length > 0
127-
? { MCP_INITIAL_ARGS: mcpServerArgs.join(" ") }
128-
: {}),
129-
...(transport ? { MCP_INITIAL_TRANSPORT: transport } : {}),
130-
...(serverUrl ? { MCP_INITIAL_SERVER_URL: serverUrl } : {}),
131-
...(headers && Object.keys(headers).length > 0
132-
? { MCP_INITIAL_HEADERS: JSON.stringify(headers) }
133-
: {}),
134-
...(envVars && Object.keys(envVars).length > 0
135-
? { MCP_ENV_VARS: JSON.stringify(envVars) }
136-
: {}),
137-
...(cwd ? { MCP_INITIAL_CWD: cwd } : {}),
138-
},
139-
signal: abort.signal,
140-
echoOutput: true,
141-
});
115+
// Inspector API server (Hono) serves static files + /api/*; it logs and opens browser when listening
116+
try {
117+
await spawnPromise("node", [honoServerPath], {
118+
env: {
119+
...process.env,
120+
CLIENT_PORT,
121+
...(dangerouslyOmitAuth
122+
? {}
123+
: { [API_SERVER_ENV_VARS.AUTH_TOKEN]: inspectorApiToken }),
124+
...(command ? { MCP_INITIAL_COMMAND: command } : {}),
125+
...(mcpServerArgs && mcpServerArgs.length > 0
126+
? { MCP_INITIAL_ARGS: mcpServerArgs.join(" ") }
127+
: {}),
128+
...(transport ? { MCP_INITIAL_TRANSPORT: transport } : {}),
129+
...(serverUrl ? { MCP_INITIAL_SERVER_URL: serverUrl } : {}),
130+
...(headers && Object.keys(headers).length > 0
131+
? { MCP_INITIAL_HEADERS: JSON.stringify(headers) }
132+
: {}),
133+
...(envVars && Object.keys(envVars).length > 0
134+
? { MCP_ENV_VARS: JSON.stringify(envVars) }
135+
: {}),
136+
...(cwd ? { MCP_INITIAL_CWD: cwd } : {}),
137+
},
138+
signal: abort.signal,
139+
echoOutput: true,
140+
});
141+
} catch (err) {
142+
// Child already printed the message (e.g. PORT IS IN USE); exit cleanly without stack
143+
const code = err?.code ?? err?.exitCode;
144+
if (typeof code === "number" && code !== 0) {
145+
process.exit(code);
146+
}
147+
throw err;
148+
}
142149
}
143150

144151
async function main() {

web/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@
5353
"react": "^18.3.1",
5454
"react-dom": "^18.3.1",
5555
"react-simple-code-editor": "^0.14.1",
56-
"serve-handler": "^6.1.6",
5756
"tailwind-merge": "^2.5.3",
5857
"zod": "^3.25.76",
58+
"open": "^10.1.0",
5959
"pino": "^9.6.0"
6060
},
6161
"devDependencies": {
@@ -66,7 +66,6 @@
6666
"@types/prismjs": "^1.26.5",
6767
"@types/react": "^18.3.23",
6868
"@types/react-dom": "^18.3.0",
69-
"@types/serve-handler": "^6.1.4",
7069
"@vitejs/plugin-react": "^5.0.4",
7170
"autoprefixer": "^10.4.20",
7271
"co": "^4.6.0",

web/src/server.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
22
import { join, dirname } from "node:path";
33
import { fileURLToPath } from "node:url";
44
import { randomBytes } from "node:crypto";
5+
import open from "open";
56
import { serve } from "@hono/node-server";
67
import { serveStatic } from "@hono/node-server/serve-static";
78
import { Hono } from "hono";
@@ -139,9 +140,12 @@ const httpServer = serve(
139140
hostname: host,
140141
},
141142
(info) => {
142-
console.log(
143-
`\n🚀 MCP Inspector Web is up and running at:\n http://${host}:${info.port}\n`,
144-
);
143+
const baseUrl = `http://${host}:${info.port}`;
144+
const url =
145+
dangerouslyOmitAuth || !authToken
146+
? baseUrl
147+
: `${baseUrl}?${API_SERVER_ENV_VARS.AUTH_TOKEN}=${authToken}`;
148+
console.log(`\n🚀 MCP Inspector Web is up and running at:\n ${url}\n`);
145149
const sandboxUrl = sandboxController.getUrl();
146150
if (sandboxUrl) {
147151
console.log(` Sandbox (MCP Apps): ${sandboxUrl}\n`);
@@ -151,5 +155,20 @@ const httpServer = serve(
151155
} else {
152156
console.log(` Auth token: ${authToken}\n`);
153157
}
158+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
159+
console.log("🌐 Opening browser...");
160+
open(url);
161+
}
154162
},
155163
);
164+
165+
httpServer.on("error", (err: Error) => {
166+
if (err.message.includes("EADDRINUSE")) {
167+
console.error(
168+
`❌ MCP Inspector PORT IS IN USE at http://${host}:${port} ❌ `,
169+
);
170+
process.exit(1);
171+
} else {
172+
throw err;
173+
}
174+
});

0 commit comments

Comments
 (0)