Merge pull request #555 from modelcontextprotocol/fweinberger/fix-proxy-port-config

Fix proxy port configuration for non-default SERVER_PORT
This commit is contained in:
Cliff Hall 2025-06-27 13:28:02 -04:00 • committed by GitHub
commit c24d2a952f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 87 additions and 52 deletions

View file

@ -1,5 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import open from "open";
import { join, dirname } from "path"; import { join, dirname } from "path";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import handler from "serve-handler"; import handler from "serve-handler";
@ -42,9 +43,12 @@ const server = http.createServer((request, response) => {
const port = parseInt(process.env.CLIENT_PORT || "6274", 10); const port = parseInt(process.env.CLIENT_PORT || "6274", 10);
const host = process.env.HOST || "localhost"; const host = process.env.HOST || "localhost";
server.on("listening", () => { server.on("listening", () => {
console.log( const url = process.env.INSPECTOR_URL || `http://${host}:${port}`;
`🔍 MCP Inspector is up and running at http://${host}:${port} 🚀`, console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
); if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
console.log(`🌐 Opening browser...`);
open(url);
}
}); });
server.on("error", (err) => { server.on("error", (err) => {
if (err.message.includes(`EADDRINUSE`)) { if (err.message.includes(`EADDRINUSE`)) {

View file

@ -7,17 +7,24 @@ import { fileURLToPath } from "url";
import { randomBytes } from "crypto"; import { randomBytes } from "crypto";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
function delay(ms) { function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms, true)); return new Promise((resolve) => setTimeout(resolve, ms, true));
} }
function getClientUrl(port, authDisabled, sessionToken) { function getClientUrl(port, authDisabled, sessionToken, serverPort) {
const host = process.env.HOST || "localhost"; const host = process.env.HOST || "localhost";
const baseUrl = `http://${host}:${port}`; const baseUrl = `http://${host}:${port}`;
return authDisabled
? baseUrl const params = new URLSearchParams();
: `${baseUrl}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) {
params.set("MCP_PROXY_PORT", serverPort);
}
if (!authDisabled) {
params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
}
return params.size > 0 ? `${baseUrl}/?${params.toString()}` : baseUrl;
} }
async function startDevServer(serverOptions) { async function startDevServer(serverOptions) {
@ -31,8 +38,8 @@ async function startDevServer(serverOptions) {
cwd: resolve(__dirname, "../..", "server"), cwd: resolve(__dirname, "../..", "server"),
env: { env: {
...process.env, ...process.env,
SERVER_PORT: SERVER_PORT, SERVER_PORT,
CLIENT_PORT: CLIENT_PORT, CLIENT_PORT,
MCP_PROXY_TOKEN: sessionToken, MCP_PROXY_TOKEN: sessionToken,
MCP_ENV_VARS: JSON.stringify(envVars), MCP_ENV_VARS: JSON.stringify(envVars),
}, },
@ -90,8 +97,8 @@ async function startProdServer(serverOptions) {
{ {
env: { env: {
...process.env, ...process.env,
SERVER_PORT: SERVER_PORT, SERVER_PORT,
CLIENT_PORT: CLIENT_PORT, CLIENT_PORT,
MCP_PROXY_TOKEN: sessionToken, MCP_PROXY_TOKEN: sessionToken,
MCP_ENV_VARS: JSON.stringify(envVars), MCP_ENV_VARS: JSON.stringify(envVars),
}, },
@ -107,29 +114,40 @@ async function startProdServer(serverOptions) {
} }
async function startDevClient(clientOptions) { async function startDevClient(clientOptions) {
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = const {
clientOptions; CLIENT_PORT,
SERVER_PORT,
authDisabled,
sessionToken,
abort,
cancelled,
} = clientOptions;
const clientCommand = "npx"; const clientCommand = "npx";
const host = process.env.HOST || "localhost"; const host = process.env.HOST || "localhost";
const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host]; const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
const client = spawn(clientCommand, clientArgs, { const client = spawn(clientCommand, clientArgs, {
cwd: resolve(__dirname, ".."), cwd: resolve(__dirname, ".."),
env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, env: { ...process.env, CLIENT_PORT },
signal: abort.signal, signal: abort.signal,
echoOutput: true, echoOutput: true,
}); });
// Auto-open browser after vite starts const url = getClientUrl(
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { CLIENT_PORT,
const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); authDisabled,
sessionToken,
SERVER_PORT,
);
// Give vite time to start before opening browser // Give vite time to start before opening or logging the URL
setTimeout(() => { setTimeout(() => {
console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
console.log("🌐 Opening browser...");
open(url); open(url);
console.log(`\n🔗 Opening browser at: ${url}\n`); }
}, 3000); }, 3000);
}
await new Promise((resolve) => { await new Promise((resolve) => {
client.subscribe({ client.subscribe({
@ -146,8 +164,14 @@ async function startDevClient(clientOptions) {
} }
async function startProdClient(clientOptions) { async function startProdClient(clientOptions) {
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = const {
clientOptions; CLIENT_PORT,
SERVER_PORT,
authDisabled,
sessionToken,
abort,
cancelled,
} = clientOptions;
const inspectorClientPath = resolve( const inspectorClientPath = resolve(
__dirname, __dirname,
"../..", "../..",
@ -156,14 +180,19 @@ async function startProdClient(clientOptions) {
"client.js", "client.js",
); );
// Only auto-open browser if not cancelled const url = getClientUrl(
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) { CLIENT_PORT,
const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); authDisabled,
open(url); sessionToken,
} SERVER_PORT,
);
await spawnPromise("node", [inspectorClientPath], { await spawnPromise("node", [inspectorClientPath], {
env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, env: {
...process.env,
CLIENT_PORT,
INSPECTOR_URL: url,
},
signal: abort.signal, signal: abort.signal,
echoOutput: true, echoOutput: true,
}); });
@ -210,7 +239,7 @@ async function main() {
} }
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274"; const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
const SERVER_PORT = process.env.SERVER_PORT ?? "6277"; const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT;
console.log( console.log(
isDev isDev
@ -255,6 +284,7 @@ async function main() {
try { try {
const clientOptions = { const clientOptions = {
CLIENT_PORT, CLIENT_PORT,
SERVER_PORT,
authDisabled, authDisabled,
sessionToken, sessionToken,
abort, abort,

View file

@ -4,12 +4,26 @@ import {
DEFAULT_INSPECTOR_CONFIG, DEFAULT_INSPECTOR_CONFIG,
} from "@/lib/constants"; } from "@/lib/constants";
const getSearchParam = (key: string): string | null => {
try {
const url = new URL(window.location.href);
return url.searchParams.get(key);
} catch {
return null;
}
};
export const getMCPProxyAddress = (config: InspectorConfig): string => { export const getMCPProxyAddress = (config: InspectorConfig): string => {
const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string;
if (proxyFullAddress) { if (proxyFullAddress) {
return proxyFullAddress; return proxyFullAddress;
} }
return `${window.location.protocol}//${window.location.hostname}:${DEFAULT_MCP_PROXY_LISTEN_PORT}`;
// Check for proxy port from query params, fallback to default
const proxyPort =
getSearchParam("MCP_PROXY_PORT") || DEFAULT_MCP_PROXY_LISTEN_PORT;
return `${window.location.protocol}//${window.location.hostname}:${proxyPort}`;
}; };
export const getMCPServerRequestTimeout = (config: InspectorConfig): number => { export const getMCPServerRequestTimeout = (config: InspectorConfig): number => {
@ -40,15 +54,6 @@ export const getMCPProxyAuthToken = (
}; };
}; };
const getSearchParam = (key: string): string | null => {
try {
const url = new URL(window.location.href);
return url.searchParams.get(key);
} catch {
return null;
}
};
export const getInitialTransportType = (): export const getInitialTransportType = ():
| "stdio" | "stdio"
| "sse" | "sse"

View file

@ -21,6 +21,7 @@ import { findActualExecutable } from "spawn-rx";
import mcpProxy from "./mcpProxy.js"; import mcpProxy from "./mcpProxy.js";
import { randomUUID, randomBytes, timingSafeEqual } from "node:crypto"; import { randomUUID, randomBytes, timingSafeEqual } from "node:crypto";
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
const SSE_HEADERS_PASSTHROUGH = ["authorization"]; const SSE_HEADERS_PASSTHROUGH = ["authorization"];
const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = [ const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = [
"authorization", "authorization",
@ -528,24 +529,19 @@ app.get("/config", originValidationMiddleware, authMiddleware, (req, res) => {
} }
}); });
const PORT = parseInt(process.env.SERVER_PORT || "6277", 10); const PORT = parseInt(
process.env.SERVER_PORT || DEFAULT_MCP_PROXY_LISTEN_PORT,
10,
);
const HOST = process.env.HOST || "localhost"; const HOST = process.env.HOST || "localhost";
const server = app.listen(PORT, HOST); const server = app.listen(PORT, HOST);
server.on("listening", () => { server.on("listening", () => {
console.log(`⚙️ Proxy server listening on ${HOST}:${PORT}`); console.log(`⚙️ Proxy server listening on ${HOST}:${PORT}`);
if (!authDisabled) { if (!authDisabled) {
console.log(`🔑 Session token: ${sessionToken}`);
console.log( console.log(
`Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth`, `🔑 Session token: ${sessionToken}\n ` +
); `Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth`,
// Display clickable URL with pre-filled token
const clientPort = process.env.CLIENT_PORT || "6274";
const clientHost = process.env.HOST || "localhost";
const clientUrl = `http://${clientHost}:${clientPort}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
console.log(
`\n🔗 Open inspector with token pre-filled:\n ${clientUrl}\n`,
); );
} else { } else {
console.log( console.log(