/*
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);
});