/* Unit tests for handler covering its documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1113: replace load-verification shim with version-negotiation tests. RFC-1113: align agent discovery surface with RFC 9727 and MCP 2026-07-28 stateless era */ import { test, expect } from "vitest"; import { handleJsonRpcRequest, type McpHandlerContext } from "../handler.ts"; import { SUPPORTED_MCP_PROTOCOL_VERSIONS, MCP_PROTOCOL_VERSION_META_KEY, JSON_RPC_ERROR, type JsonRpcRequest, } from "../protocol.ts"; import { buildAgentSurfaceManifest } from "@warpgogol/werkstatt-shared/agent"; const SUPPORTED = SUPPORTED_MCP_PROTOCOL_VERSIONS[0]!; function makeCtx(): McpHandlerContext { const manifest = buildAgentSurfaceManifest({ generatedAt: "2026-01-01T00:00:00.000Z", site: "test-bundle", baseUrl: "https://test.example", languages: { default: "de", supported: ["de"] }, }); return { manifest, catalog: [], ports: { knowledge: { read: async () => null }, dispatch: { send: async () => { throw new Error("not used"); }, }, now: () => new Date("2026-01-01T00:00:00.000Z"), }, }; } function req(method: string, params?: Record): JsonRpcRequest { return { jsonrpc: "2.0", id: 1, method, ...(params ? { params } : {}) }; } function withVersion(params: Record = {}, version: string = SUPPORTED) { return { ...params, _meta: { [MCP_PROTOCOL_VERSION_META_KEY]: version } }; } function errorOf(res: Awaited>) { if (!("error" in res)) throw new Error("expected a JsonRpcError"); return res.error; } function resultOf(res: Awaited>) { if (!("result" in res)) throw new Error("expected a JsonRpcSuccess"); return res.result; } test("server/discover: answers unconditionally with the supported version list", async () => { const res = await handleJsonRpcRequest(req("server/discover"), makeCtx()); const result = resultOf(res) as { resultType: string; supportedVersions: string[]; capabilities: unknown; _meta: Record; }; expect(result.resultType).toBe("complete"); expect(result.supportedVersions).toEqual([...SUPPORTED_MCP_PROTOCOL_VERSIONS]); expect(result.capabilities).toEqual({ tools: {}, resources: {} }); expect(result._meta["io.modelcontextprotocol/serverInfo"]!.name).toContain("agent surface"); }); test("initialize: returns UnsupportedProtocolVersionError naming supported + requested", async () => { const res = await handleJsonRpcRequest( req("initialize", { protocolVersion: "2025-06-18" }), makeCtx(), ); const error = errorOf(res); expect(error.code).toBe(JSON_RPC_ERROR.UNSUPPORTED_PROTOCOL_VERSION); const data = error.data as { supported: string[]; requested: string }; expect(data.supported).toEqual([...SUPPORTED_MCP_PROTOCOL_VERSIONS]); expect(data.requested).toBe("2025-06-18"); }); test("version gate: missing _meta version → UnsupportedProtocolVersionError", async () => { const res = await handleJsonRpcRequest(req("ping"), makeCtx()); const error = errorOf(res); expect(error.code).toBe(JSON_RPC_ERROR.UNSUPPORTED_PROTOCOL_VERSION); const data = error.data as { supported: string[]; requested: unknown }; expect(data.supported).toEqual([...SUPPORTED_MCP_PROTOCOL_VERSIONS]); expect(data.requested).toBeNull(); }); test("version gate: unsupported _meta version → UnsupportedProtocolVersionError", async () => { const res = await handleJsonRpcRequest( req("tools/list", withVersion({}, "1999-01-01")), makeCtx(), ); const error = errorOf(res); expect(error.code).toBe(JSON_RPC_ERROR.UNSUPPORTED_PROTOCOL_VERSION); expect((error.data as { requested: string }).requested).toBe("1999-01-01"); }); test("version gate: supported _meta version → request proceeds", async () => { const res = await handleJsonRpcRequest(req("ping", withVersion()), makeCtx()); expect(resultOf(res)).toEqual({}); }); test("version gate: runs before method dispatch — unknown method with bad version gets -32022", async () => { const res = await handleJsonRpcRequest(req("prompts/list"), makeCtx()); expect(errorOf(res).code).toBe(JSON_RPC_ERROR.UNSUPPORTED_PROTOCOL_VERSION); }); test("version gate: unknown method with valid version still gets -32601", async () => { const res = await handleJsonRpcRequest(req("prompts/list", withVersion()), makeCtx()); expect(errorOf(res).code).toBe(JSON_RPC_ERROR.METHOD_NOT_FOUND); });