Skip to content

Commit c5922f8

Browse files
committed
Fix node 18 incompatibility caused by race condition with closing server by using a newly allocated port for each test
1 parent fd3165c commit c5922f8

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

src/server/streamableHttp.test.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import { createServer, type Server, IncomingMessage, ServerResponse } from "node:http";
2-
import { AddressInfo } from "node:net";
2+
import { createServer as netCreateServer, AddressInfo } from "node:net";
33
import { randomUUID } from "node:crypto";
44
import { EventStore, StreamableHTTPServerTransport, EventId, StreamId } from "./streamableHttp.js";
55
import { McpServer } from "./mcp.js";
66
import { CallToolResult, JSONRPCMessage } from "../types.js";
77
import { z } from "zod";
88
import { AuthInfo } from "./auth/types.js";
99

10+
async function getFreePort() {
11+
return new Promise( res => {
12+
const srv = netCreateServer();
13+
srv.listen(0, () => {
14+
const address = srv.address()!
15+
if (typeof address === "string") {
16+
throw new Error("Unexpected address type: " + typeof address);
17+
}
18+
const port = (address as AddressInfo).port;
19+
srv.close((err) => res(port))
20+
});
21+
})
22+
}
23+
1024
/**
1125
* Test server configuration for StreamableHTTPServerTransport tests
1226
*/
@@ -1441,7 +1455,7 @@ describe("StreamableHTTPServerTransport DNS rebinding protection", () => {
14411455
it("should accept requests with allowed host headers", async () => {
14421456
const result = await createTestServerWithDnsProtection({
14431457
sessionIdGenerator: undefined,
1444-
allowedHosts: ['localhost:3001'],
1458+
allowedHosts: ['localhost'],
14451459
enableDnsRebindingProtection: true,
14461460
});
14471461
server = result.server;
@@ -1563,7 +1577,7 @@ describe("StreamableHTTPServerTransport DNS rebinding protection", () => {
15631577
it("should skip all validations when enableDnsRebindingProtection is false", async () => {
15641578
const result = await createTestServerWithDnsProtection({
15651579
sessionIdGenerator: undefined,
1566-
allowedHosts: ['localhost:3001'],
1580+
allowedHosts: ['localhost'],
15671581
allowedOrigins: ['http://localhost:3000'],
15681582
enableDnsRebindingProtection: false,
15691583
});
@@ -1591,7 +1605,7 @@ describe("StreamableHTTPServerTransport DNS rebinding protection", () => {
15911605
it("should validate both host and origin when both are configured", async () => {
15921606
const result = await createTestServerWithDnsProtection({
15931607
sessionIdGenerator: undefined,
1594-
allowedHosts: ['localhost:3001'],
1608+
allowedHosts: ['localhost'],
15951609
allowedOrigins: ['http://localhost:3001'],
15961610
enableDnsRebindingProtection: true,
15971611
});
@@ -1649,6 +1663,17 @@ async function createTestServerWithDnsProtection(config: {
16491663
{ capabilities: { logging: {} } }
16501664
);
16511665

1666+
const port = await getFreePort();
1667+
1668+
if (config.allowedHosts) {
1669+
config.allowedHosts = config.allowedHosts.map(host => {
1670+
if (host.includes(':')) {
1671+
return host;
1672+
}
1673+
return `localhost:${port}`;
1674+
});
1675+
}
1676+
16521677
const transport = new StreamableHTTPServerTransport({
16531678
sessionIdGenerator: config.sessionIdGenerator,
16541679
allowedHosts: config.allowedHosts,
@@ -1672,10 +1697,9 @@ async function createTestServerWithDnsProtection(config: {
16721697
});
16731698

16741699
await new Promise<void>((resolve) => {
1675-
httpServer.listen(3001, () => resolve());
1700+
httpServer.listen(port, () => resolve());
16761701
});
16771702

1678-
const port = (httpServer.address() as AddressInfo).port;
16791703
const serverUrl = new URL(`http://localhost:${port}/`);
16801704

16811705
return {

0 commit comments

Comments
 (0)