fix: pass proxy port via URL params when non-default

- Update client to read MCP_PROXY_PORT from URL parameters
- Update server to include port in displayed URL when non-default
- Update start scripts to pass SERVER_PORT to client
- Use DEFAULT_MCP_PROXY_LISTEN_PORT constant instead of magic numbers

This fixes the issue where the client couldn't connect to the proxy
when SERVER_PORT was set to a non-default value.
This commit is contained in:
Felix Weinberger 2025-06-24 11:42:45 +01:00
commit 9fcfd89326
No known key found for this signature in database
3 changed files with 77 additions and 23 deletions

View file

@ -7,17 +7,29 @@ import { fileURLToPath } from "url";
import { randomBytes } from "crypto";
const __dirname = dirname(fileURLToPath(import.meta.url));
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
function delay(ms) {
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 baseUrl = `http://${host}:${port}`;
return authDisabled
? baseUrl
: `${baseUrl}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
if (authDisabled) {
return baseUrl;
}
const params = new URLSearchParams();
params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
// Add server port if it's not the default
if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) {
params.set("MCP_PROXY_PORT", serverPort);
}
return `${baseUrl}/?${params.toString()}`;
}
async function startDevServer(serverOptions) {
@ -107,8 +119,14 @@ async function startProdServer(serverOptions) {
}
async function startDevClient(clientOptions) {
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } =
clientOptions;
const {
CLIENT_PORT,
SERVER_PORT,
authDisabled,
sessionToken,
abort,
cancelled,
} = clientOptions;
const clientCommand = "npx";
const host = process.env.HOST || "localhost";
const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
@ -122,7 +140,12 @@ async function startDevClient(clientOptions) {
// Auto-open browser after vite starts
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken);
const url = getClientUrl(
CLIENT_PORT,
authDisabled,
sessionToken,
SERVER_PORT,
);
// Give vite time to start before opening browser
setTimeout(() => {
@ -146,8 +169,14 @@ async function startDevClient(clientOptions) {
}
async function startProdClient(clientOptions) {
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } =
clientOptions;
const {
CLIENT_PORT,
SERVER_PORT,
authDisabled,
sessionToken,
abort,
cancelled,
} = clientOptions;
const inspectorClientPath = resolve(
__dirname,
"../..",
@ -158,7 +187,12 @@ async function startProdClient(clientOptions) {
// Only auto-open browser if not cancelled
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) {
const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken);
const url = getClientUrl(
CLIENT_PORT,
authDisabled,
sessionToken,
SERVER_PORT,
);
open(url);
}
@ -210,7 +244,7 @@ async function main() {
}
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(
isDev
@ -255,6 +289,7 @@ async function main() {
try {
const clientOptions = {
CLIENT_PORT,
SERVER_PORT,
authDisabled,
sessionToken,
abort,

View file

@ -4,12 +4,26 @@ import {
DEFAULT_INSPECTOR_CONFIG,
} 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 => {
const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string;
if (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 => {
@ -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 = ():
| "stdio"
| "sse"

View file

@ -21,6 +21,7 @@ import { findActualExecutable } from "spawn-rx";
import mcpProxy from "./mcpProxy.js";
import { randomUUID, randomBytes, timingSafeEqual } from "node:crypto";
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
const SSE_HEADERS_PASSTHROUGH = ["authorization"];
const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = [
"authorization",
@ -528,7 +529,10 @@ 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 server = app.listen(PORT, HOST);
@ -543,7 +547,17 @@ server.on("listening", () => {
// 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}`;
// Build URL with query parameters
const params = new URLSearchParams();
params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
// Add server port if it's not the default
if (PORT !== parseInt(DEFAULT_MCP_PROXY_LISTEN_PORT, 10)) {
params.set("MCP_PROXY_PORT", PORT.toString());
}
const clientUrl = `http://${clientHost}:${clientPort}/?${params.toString()}`;
console.log(
`\n🔗 Open inspector with token pre-filled:\n ${clientUrl}\n`,
);