diff --git a/.changeset/report-bound-http-port.md b/.changeset/report-bound-http-port.md new file mode 100644 index 000000000..75b45f8a5 --- /dev/null +++ b/.changeset/report-bound-http-port.md @@ -0,0 +1,5 @@ +--- +"@upstash/context7-mcp": patch +--- + +Report the actual assigned HTTP port when `--port 0` requests an ephemeral port. diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts index b63ff3657..08bbefc1f 100644 --- a/packages/mcp/src/index.ts +++ b/packages/mcp/src/index.ts @@ -539,8 +539,13 @@ async function main() { }); httpServer.once("listening", () => { + const address = httpServer.address(); + if (!address || typeof address === "string") { + console.error("Failed to determine the bound HTTP port"); + process.exit(1); + } console.error( - `Context7 Documentation MCP Server v${SERVER_VERSION} running on HTTP at http://localhost:${port}/mcp` + `Context7 Documentation MCP Server v${SERVER_VERSION} running on HTTP at http://localhost:${address.port}/mcp` ); }); }; diff --git a/packages/mcp/test/integration.test.ts b/packages/mcp/test/integration.test.ts index 0c9d68401..9550cd0ca 100644 --- a/packages/mcp/test/integration.test.ts +++ b/packages/mcp/test/integration.test.ts @@ -71,13 +71,12 @@ function startStubApi(): Promise { }); } -function startHttpChild(): Promise<{ child: ChildProcess; url: string }> { +function startHttpChild(port = BASE_PORT): Promise<{ child: ChildProcess; url: string }> { return new Promise((resolve, reject) => { - const child = spawn( - process.execPath, - [DIST, "--transport", "http", "--port", String(BASE_PORT)], - { env: childEnv, stdio: ["ignore", "ignore", "pipe"] } - ); + const child = spawn(process.execPath, [DIST, "--transport", "http", "--port", String(port)], { + env: childEnv, + stdio: ["ignore", "ignore", "pipe"], + }); let stderr = ""; child.stderr!.on("data", (chunk: Buffer) => { stderr += chunk.toString(); @@ -105,6 +104,19 @@ afterAll(() => { stubServer?.close(); }); +test("reports the bound port when port zero requests an ephemeral port", async () => { + const { child, url } = await startHttpChild(0); + try { + expect(new URL(url).port).not.toBe("0"); + + const response = await fetch(new URL("/ping", url)); + expect(response.ok).toBe(true); + await expect(response.json()).resolves.toMatchObject({ status: "ok" }); + } finally { + child.kill(); + } +}); + async function connect(transportKind: "http" | "stdio", era: "modern" | "legacy") { const client = new Client( { name: "test-harness", version: "1.0.0" },