import { describe, expect, it } from "vitest"; import { initializeMcpHttpSession, MCP_HTTP_ACCEPT, MCP_PROTOCOL_VERSION, mcpHttpRequestHeaders, parseMcpHttpResponseBody, } from "../services/mcp-http.js"; describe("mcpHttpRequestHeaders", () => { it("advertises both JSON and SSE on every request", () => { expect(mcpHttpRequestHeaders()).toMatchObject({ "content-type": "application/json", accept: "application/json, text/event-stream", }); expect(MCP_HTTP_ACCEPT).toBe("application/json, text/event-stream"); }); it("preserves caller-supplied headers while keeping the required Accept value", () => { expect(mcpHttpRequestHeaders({ Authorization: "Bearer x", accept: "application/json" })).toMatchObject({ accept: "application/json, text/event-stream", Authorization: "Bearer x", }); }); }); describe("initializeMcpHttpSession", () => { it("returns the negotiated protocol and ephemeral session headers", async () => { const requests: Array<{ headers: Headers; payload: Record }> = []; const sessionHeaders = await initializeMcpHttpSession({ requestId: "test-request", headers: { Authorization: "Bearer token" }, send: async (init) => { const payload = JSON.parse(String(init.body)) as Record; requests.push({ headers: new Headers(init.headers), payload }); if (payload.method === "initialize") { return new Response(JSON.stringify({ jsonrpc: "2.0", id: payload.id, result: { protocolVersion: MCP_PROTOCOL_VERSION, capabilities: { tools: {} }, serverInfo: { name: "stateful-test", version: "1" }, }, }), { status: 200, headers: { "content-type": "application/json", "mcp-session-id": "session-123" }, }); } return new Response(null, { status: 202 }); }, }); expect(requests.map(({ payload }) => payload.method)).toEqual([ "initialize", "notifications/initialized", ]); expect(requests[1]!.headers.get("authorization")).toBe("Bearer token"); expect(requests[1]!.headers.get("mcp-session-id")).toBe("session-123"); expect(requests[1]!.headers.get("mcp-protocol-version")).toBe(MCP_PROTOCOL_VERSION); expect(sessionHeaders).toMatchObject({ Authorization: "Bearer token", "Mcp-Session-Id": "session-123", "MCP-Protocol-Version": MCP_PROTOCOL_VERSION, }); }); }); describe("parseMcpHttpResponseBody", () => { it("parses a plain application/json body", () => { const payload = { jsonrpc: "2.0", id: "1", result: { tools: [] } }; expect(parseMcpHttpResponseBody(JSON.stringify(payload), "application/json")).toEqual(payload); }); it("parses an SSE-framed body, extracting the JSON-RPC message", () => { const payload = { jsonrpc: "2.0", id: "1", result: { tools: [{ name: "kv_get" }] } }; const body = `event: message\ndata: ${JSON.stringify(payload)}\n\n`; expect(parseMcpHttpResponseBody(body, "text/event-stream; charset=utf-8")).toEqual(payload); }); it("skips non-JSON-RPC SSE events and returns the response message", () => { const ping = "event: ping\ndata: {\"type\":\"ping\"}"; const message = { jsonrpc: "2.0", id: "1", result: { ok: true } }; const body = `${ping}\n\nevent: message\ndata: ${JSON.stringify(message)}\n\n`; expect(parseMcpHttpResponseBody(body, "text/event-stream")).toEqual(message); }); it("handles multi-line SSE data fields", () => { const payload = { jsonrpc: "2.0", id: "1", result: { note: "line" } }; const json = JSON.stringify(payload, null, 2); const body = `data: ${json.split("\n").join("\ndata: ")}\n\n`; expect(parseMcpHttpResponseBody(body, "text/event-stream")).toEqual(payload); }); it("throws when an SSE stream carries no data events", () => { expect(() => parseMcpHttpResponseBody("event: ping\n\n", "text/event-stream")).toThrow(); }); });