ts-mcp-template/tests/http.test.ts
Jax 8df0a58dfa feat: migrate verified template implementation into main repo
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-11 22:10:25 +08:00

102 lines
3.2 KiB
TypeScript

import { readFile } from "node:fs/promises";
import type { Server } from "node:http";
import type { AddressInfo } from "node:net";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { afterEach, describe, expect, it } from "vitest";
import { EXAMPLE_ECHO_TOOL_NAME } from "../src/capabilities/index.js";
import { startHttpServer } from "../src/http.js";
const testsDir = dirname(fileURLToPath(import.meta.url));
const projectRoot = resolve(testsDir, "..");
const packageJsonPath = resolve(projectRoot, "package.json");
let activeServer: Server | undefined;
afterEach(async () => {
if (activeServer !== undefined) {
await new Promise<void>((resolveClose, rejectClose) => {
activeServer?.close((error) => {
if (error) {
rejectClose(error);
return;
}
resolveClose();
});
});
activeServer = undefined;
}
});
async function startTestServer(): Promise<URL> {
activeServer = await startHttpServer({ host: "127.0.0.1", port: 0 });
const address = activeServer.address() as AddressInfo;
return new URL(`http://127.0.0.1:${address.port}/mcp`);
}
describe("HTTP entrypoint", () => {
it("supports streamable HTTP initialize flow and shared capabilities", async () => {
const endpoint = await startTestServer();
const transport = new StreamableHTTPClientTransport(endpoint);
const client = new Client({ name: "http-test-client", version: "0.0.0" }, { capabilities: {} });
await client.connect(transport);
const tools = await client.listTools();
expect(tools.tools.map((tool) => tool.name)).toContain(EXAMPLE_ECHO_TOOL_NAME);
await client.close();
await transport.close();
});
it("returns 404 on unknown routes", async () => {
await startTestServer();
const address = activeServer?.address() as AddressInfo;
const response = await fetch(`http://127.0.0.1:${address.port}/not-mcp`);
expect(response.status).toBe(404);
await expect(response.json()).resolves.toMatchObject({
error: "Not Found",
});
});
it("returns explicit invalid-session errors", async () => {
await startTestServer();
const address = activeServer?.address() as AddressInfo;
const response = await fetch(`http://127.0.0.1:${address.port}/mcp`, {
method: "POST",
headers: {
"content-type": "application/json",
"mcp-session-id": "missing-session",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "invalid-session",
method: "ping",
params: {},
}),
});
expect(response.status).toBe(404);
await expect(response.json()).resolves.toMatchObject({
jsonrpc: "2.0",
error: {
message: "Session not found",
},
id: null,
});
});
it("publishes an HTTP entry command", async () => {
const packageJsonRaw = await readFile(packageJsonPath, "utf8");
const packageJson = JSON.parse(packageJsonRaw) as {
scripts?: Record<string, string>;
};
expect(packageJson.scripts?.["dev:http"]).toBe("tsx src/http.ts");
});
});