Skip to content

Commit 32b418c

Browse files
committed
Merge branch 'main' into full-apps-support-final
2 parents 9465eae + 98f0587 commit 32b418c

3 files changed

Lines changed: 41 additions & 20 deletions

File tree

cli/__tests__/helpers/assertions.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
import { expect } from "vitest";
22
import type { CliResult } from "./cli-runner.js";
33

4+
function formatCliOutput(result: CliResult): string {
5+
const out = result.stdout?.trim() || "(empty)";
6+
const err = result.stderr?.trim() || "(empty)";
7+
return `stdout: ${out}\nstderr: ${err}`;
8+
}
9+
410
/**
511
* Assert that CLI command succeeded (exit code 0)
612
*/
713
export function expectCliSuccess(result: CliResult) {
8-
expect(result.exitCode).toBe(0);
14+
expect(
15+
result.exitCode,
16+
`CLI exited with code ${result.exitCode}. ${formatCliOutput(result)}`,
17+
).toBe(0);
918
}
1019

1120
/**
1221
* Assert that CLI command failed (non-zero exit code)
1322
*/
1423
export function expectCliFailure(result: CliResult) {
15-
expect(result.exitCode).not.toBe(0);
24+
expect(
25+
result.exitCode,
26+
`CLI unexpectedly exited with code ${result.exitCode}. ${formatCliOutput(result)}`,
27+
).not.toBe(0);
1628
}
1729

1830
/**

cli/__tests__/helpers/fixtures.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import fs from "fs";
2-
import path from "path";
3-
import os from "os";
4-
import crypto from "crypto";
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
import * as os from "os";
4+
import * as crypto from "crypto";
55
import { getTestMcpServerCommand } from "./test-server-stdio.js";
66

77
/**

cli/__tests__/helpers/test-server-http.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { Request, Response } from "express";
66
import express from "express";
77
import { createServer as createHttpServer, Server as HttpServer } from "http";
88
import { createServer as createNetServer } from "net";
9+
import { randomUUID } from "crypto";
910
import * as z from "zod/v4";
1011
import type { ServerConfig } from "./test-fixtures.js";
1112

@@ -187,22 +188,24 @@ export class TestServerHttp {
187188
}
188189

189190
/**
190-
* Start the server with the specified transport
191+
* Start the server with the specified transport.
192+
* When requestedPort is omitted, uses port 0 so the OS assigns a unique port (avoids EADDRINUSE when tests run in parallel).
191193
*/
192194
async start(
193195
transport: "http" | "sse",
194196
requestedPort?: number,
195197
): Promise<number> {
196-
const port = requestedPort
197-
? await findAvailablePort(requestedPort)
198-
: await findAvailablePort(transport === "http" ? 3001 : 3000);
199-
200-
this.url = `http://localhost:${port}`;
198+
const port =
199+
requestedPort !== undefined ? await findAvailablePort(requestedPort) : 0;
201200

202201
if (transport === "http") {
203-
return this.startHttp(port);
202+
const actualPort = await this.startHttp(port);
203+
this.url = `http://localhost:${actualPort}`;
204+
return actualPort;
204205
} else {
205-
return this.startSse(port);
206+
const actualPort = await this.startSse(port);
207+
this.url = `http://localhost:${actualPort}`;
208+
return actualPort;
206209
}
207210
}
208211

@@ -213,8 +216,10 @@ export class TestServerHttp {
213216
// Create HTTP server
214217
this.httpServer = createHttpServer(app);
215218

216-
// Create StreamableHTTP transport
217-
this.transport = new StreamableHTTPServerTransport({});
219+
// Create StreamableHTTP transport (stateful so it can handle multiple requests per session)
220+
this.transport = new StreamableHTTPServerTransport({
221+
sessionIdGenerator: () => randomUUID(),
222+
});
218223

219224
// Set up Express route to handle MCP requests
220225
app.post("/mcp", async (req: Request, res: Response) => {
@@ -292,10 +297,12 @@ export class TestServerHttp {
292297
// Connect transport to server
293298
await this.mcpServer.connect(this.transport);
294299

295-
// Start listening
300+
// Start listening (port 0 = OS assigns a unique port)
296301
return new Promise((resolve, reject) => {
297302
this.httpServer!.listen(port, () => {
298-
resolve(port);
303+
const assignedPort = (this.httpServer!.address() as { port: number })
304+
?.port;
305+
resolve(assignedPort ?? port);
299306
});
300307
this.httpServer!.on("error", reject);
301308
});
@@ -371,10 +378,12 @@ export class TestServerHttp {
371378
// Note: SSE transport is created per request, so we don't store a single instance
372379
this.transport = undefined;
373380

374-
// Start listening
381+
// Start listening (port 0 = OS assigns a unique port)
375382
return new Promise((resolve, reject) => {
376383
this.httpServer!.listen(port, () => {
377-
resolve(port);
384+
const assignedPort = (this.httpServer!.address() as { port: number })
385+
?.port;
386+
resolve(assignedPort ?? port);
378387
});
379388
this.httpServer!.on("error", reject);
380389
});

0 commit comments

Comments
 (0)