From e97556a1f0b975da4b6d1bbe23880e4360550770 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Tue, 10 Feb 2026 11:38:42 +0100 Subject: [PATCH 1/4] fix(mcp-server): use random available ports in server tests Replace hardcoded port numbers with dynamically assigned ports to avoid EADDRINUSE errors in CI environments where ports may already be in use. Co-Authored-By: Claude Opus 4.6 --- packages/mcp-server/test/server.test.ts | 39 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/mcp-server/test/server.test.ts b/packages/mcp-server/test/server.test.ts index 376aa2eee..44c238912 100644 --- a/packages/mcp-server/test/server.test.ts +++ b/packages/mcp-server/test/server.test.ts @@ -1,6 +1,7 @@ import type * as http from 'http'; import jsonwebtoken from 'jsonwebtoken'; +import * as net from 'net'; import request from 'supertest'; import createMockForestServerClient from './helpers/forest-server-client'; @@ -8,6 +9,17 @@ import MockServer from './test-utils/mock-server'; import ForestMCPServer from '../src/server'; import { clearSchemaCache } from '../src/utils/schema-fetcher'; +function getAvailablePort(): Promise { + return new Promise((resolve, reject) => { + const srv = net.createServer(); + srv.listen(0, () => { + const { port } = srv.address() as net.AddressInfo; + srv.close(() => resolve(port)); + }); + srv.on('error', reject); + }); +} + function shutDownHttpServer(server: http.Server | undefined): Promise { if (!server) return Promise.resolve(); @@ -125,7 +137,7 @@ describe('ForestMCPServer Instance', () => { }); it('should start server on specified port', async () => { - const testPort = 39310; // Use a different port for testing + const testPort = await getAvailablePort(); process.env.MCP_SERVER_PORT = testPort.toString(); server = new ForestMCPServer({ @@ -155,7 +167,7 @@ describe('ForestMCPServer Instance', () => { }); it('should create transport instance', async () => { - const testPort = 39311; + const testPort = await getAvailablePort(); process.env.MCP_SERVER_PORT = testPort.toString(); server = new ForestMCPServer({ @@ -175,13 +187,14 @@ describe('ForestMCPServer Instance', () => { describe('HTTP endpoint', () => { let httpServer: http.Server; + let httpEndpointPort: number; beforeAll(async () => { process.env.FOREST_ENV_SECRET = 'test-env-secret'; process.env.FOREST_AUTH_SECRET = 'test-auth-secret'; process.env.FOREST_SERVER_URL = 'https://test.forestadmin.com'; - const testPort = 39312; - process.env.MCP_SERVER_PORT = testPort.toString(); + httpEndpointPort = await getAvailablePort(); + process.env.MCP_SERVER_PORT = httpEndpointPort.toString(); server = new ForestMCPServer({ envSecret: 'test-env-secret', @@ -240,12 +253,16 @@ describe('ForestMCPServer Instance', () => { expect(response.status).toBe(200); expect(response.headers['content-type']).toMatch(/application\/json/); - expect(response.body.issuer).toBe('http://localhost:39312/'); + expect(response.body.issuer).toBe(`http://localhost:${httpEndpointPort}/`); expect(response.body.registration_endpoint).toBe( 'https://test.forestadmin.com/oauth/register', ); - expect(response.body.authorization_endpoint).toBe(`http://localhost:39312/oauth/authorize`); - expect(response.body.token_endpoint).toBe(`http://localhost:39312/oauth/token`); + expect(response.body.authorization_endpoint).toBe( + `http://localhost:${httpEndpointPort}/oauth/authorize`, + ); + expect(response.body.token_endpoint).toBe( + `http://localhost:${httpEndpointPort}/oauth/token`, + ); expect(response.body.revocation_endpoint).toBeUndefined(); expect(response.body.scopes_supported).toEqual([ 'mcp:read', @@ -266,7 +283,7 @@ describe('ForestMCPServer Instance', () => { // Clean up previous server await shutDownHttpServer(server?.httpServer as http.Server); - process.env.MCP_SERVER_PORT = '39314'; + process.env.MCP_SERVER_PORT = (await getAvailablePort()).toString(); server = new ForestMCPServer({ authSecret: 'AUTH_SECRET', @@ -424,7 +441,7 @@ describe('ForestMCPServer Instance', () => { process.env.FOREST_ENV_SECRET = 'test-env-secret'; process.env.FOREST_AUTH_SECRET = 'test-auth-secret'; process.env.FOREST_SERVER_URL = 'https://test.forestadmin.com'; - process.env.MCP_SERVER_PORT = '39320'; + process.env.MCP_SERVER_PORT = (await getAvailablePort()).toString(); // Setup mock for Forest Admin server API responses mcpMockServer = new MockServer(); @@ -904,7 +921,7 @@ describe('ForestMCPServer Instance', () => { process.env.FOREST_AUTH_SECRET = 'test-auth-secret'; process.env.FOREST_SERVER_URL = 'https://test.forestadmin.com'; process.env.AGENT_HOSTNAME = 'http://localhost:3310'; - process.env.MCP_SERVER_PORT = '39330'; + process.env.MCP_SERVER_PORT = (await getAvailablePort()).toString(); listMockServer = new MockServer(); listMockServer @@ -1975,7 +1992,7 @@ describe('ForestMCPServer Instance', () => { process.env.FOREST_AUTH_SECRET = 'test-auth-secret'; process.env.FOREST_SERVER_URL = 'https://test.forestadmin.com'; process.env.AGENT_HOSTNAME = 'http://localhost:3310'; - process.env.MCP_SERVER_PORT = '39331'; + process.env.MCP_SERVER_PORT = (await getAvailablePort()).toString(); loggingMockServer = new MockServer(); loggingMockServer From a0414cfb982649ca1a6faf3377de8f0caa249b1e Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Tue, 10 Feb 2026 11:42:50 +0100 Subject: [PATCH 2/4] fix(mcp-server): assert server listens on specified port Co-Authored-By: Claude Opus 4.6 --- packages/mcp-server/test/server.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/test/server.test.ts b/packages/mcp-server/test/server.test.ts index 44c238912..c4d8c8470 100644 --- a/packages/mcp-server/test/server.test.ts +++ b/packages/mcp-server/test/server.test.ts @@ -154,9 +154,11 @@ describe('ForestMCPServer Instance', () => { setTimeout(resolve, 500); }); - // Verify the server is running by making a request + // Verify the server is running on the specified port const { httpServer } = server; expect(httpServer).toBeDefined(); + const address = (httpServer as http.Server).address() as net.AddressInfo; + expect(address.port).toBe(testPort); // Make a request to verify server is responding const response = await request(httpServer as http.Server) From d84f3488f57be845a84ad87a4e9e6fea30602265 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Tue, 10 Feb 2026 11:51:58 +0100 Subject: [PATCH 3/4] refactor(mcp-server): extract getAvailablePort to reusable test util Co-Authored-By: Claude Opus 4.6 --- packages/mcp-server/test/server.test.ts | 12 +----------- .../mcp-server/test/test-utils/get-available-port.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 packages/mcp-server/test/test-utils/get-available-port.ts diff --git a/packages/mcp-server/test/server.test.ts b/packages/mcp-server/test/server.test.ts index c4d8c8470..6675a3961 100644 --- a/packages/mcp-server/test/server.test.ts +++ b/packages/mcp-server/test/server.test.ts @@ -5,21 +5,11 @@ import * as net from 'net'; import request from 'supertest'; import createMockForestServerClient from './helpers/forest-server-client'; +import getAvailablePort from './test-utils/get-available-port'; import MockServer from './test-utils/mock-server'; import ForestMCPServer from '../src/server'; import { clearSchemaCache } from '../src/utils/schema-fetcher'; -function getAvailablePort(): Promise { - return new Promise((resolve, reject) => { - const srv = net.createServer(); - srv.listen(0, () => { - const { port } = srv.address() as net.AddressInfo; - srv.close(() => resolve(port)); - }); - srv.on('error', reject); - }); -} - function shutDownHttpServer(server: http.Server | undefined): Promise { if (!server) return Promise.resolve(); diff --git a/packages/mcp-server/test/test-utils/get-available-port.ts b/packages/mcp-server/test/test-utils/get-available-port.ts new file mode 100644 index 000000000..68f1e80f6 --- /dev/null +++ b/packages/mcp-server/test/test-utils/get-available-port.ts @@ -0,0 +1,12 @@ +import * as net from 'net'; + +export default function getAvailablePort(): Promise { + return new Promise((resolve, reject) => { + const srv = net.createServer(); + srv.listen(0, () => { + const { port } = srv.address() as net.AddressInfo; + srv.close(() => resolve(port)); + }); + srv.on('error', reject); + }); +} From f707374faac830e73fcd9a701c606dd0fe79e761 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Tue, 10 Feb 2026 12:07:50 +0100 Subject: [PATCH 4/4] fix(mcp-server): fix lint import order in server tests Co-Authored-By: Claude Opus 4.6 --- packages/mcp-server/test/server.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/test/server.test.ts b/packages/mcp-server/test/server.test.ts index 6675a3961..a3f51a3c9 100644 --- a/packages/mcp-server/test/server.test.ts +++ b/packages/mcp-server/test/server.test.ts @@ -1,7 +1,7 @@ import type * as http from 'http'; +import type * as net from 'net'; import jsonwebtoken from 'jsonwebtoken'; -import * as net from 'net'; import request from 'supertest'; import createMockForestServerClient from './helpers/forest-server-client';