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:
commit
c24d2a952f
4 changed files with 87 additions and 52 deletions
|
|
@ -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`)) {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue