Files
coreci-chat/tests/mcp-conformance/translator.test.ts
T
CIAgent 28b8aa36c6 feat(P1): Wave F — MCP Gateway core (REQ-015,016,017,018,019,024)
MCP capability broker gateway with closed 9-tool registry, adapter router,
write-method blocklist (INV-7 backstop), token-bucket rate limiter (60/min user,
300/min tenant), SSE stream manager (ULID, per-call, 30s timeout), OpenAI↔MCP
translator, in-process custom transport + stdio, mcp_adapters table with RLS,
5 API routes, 4 stub adapters + McpAdapter interface, 7 MCP conformance tests.

G-012 (audit type widening), G-015 (INV-7 framing), G-016 (two enforcement models),
G-017 (stdio-interop 7th test), G-020 (McpAdapter interface) applied.

Tests: 254 green (224 unit + 32 conformance). Coverage: 88.7% on packages/mcp.
M1 non-regression: all M1 tests pass.

---ci---
phase: 1
milestone: v0.2
status: complete
wave: F
phase_role: execution
---/ci---
2026-08-25 04:43:45 +00:00

66 lines
2.4 KiB
TypeScript

/**
* translator.test.ts — MCP conformance test 5 (R-001 §5, gate item 15).
*
* Asserts the OpenAI ↔ MCP bidirectional translation contract:
* - tool_calls[i].function.{name, arguments(JSON string)} → params.{name, arguments(object)}
* - result.content[].text + isError → OpenAI {role:"tool", tool_call_id, content}
* - parse failures are PROTOCOL errors (TranslationError), not execution errors
*/
import { describe, it, expect } from "vitest";
import {
toolCallToMcp,
mcpResultToToolMessage,
toolsToOpenAi,
TranslationError,
type OpenAiToolCall,
type McpResult,
} from "@coreci/mcp";
import { listTools } from "@coreci/mcp";
describe("conformance 5 — OpenAI ↔ MCP translation (R-001 §5)", () => {
it("parses OpenAI tool_call.arguments (JSON string) → MCP arguments (object)", () => {
const tc: OpenAiToolCall = {
id: "call_1",
type: "function",
function: { name: "proxmox.list_vms", arguments: '{"node":"pve1"}' },
};
expect(toolCallToMcp(tc)).toEqual({ name: "proxmox.list_vms", arguments: { node: "pve1" } });
});
it("throws TranslationError (protocol error) on malformed arguments JSON", () => {
const tc: OpenAiToolCall = {
id: "call_2",
type: "function",
function: { name: "github.list_repos", arguments: "{not json" },
};
expect(() => toolCallToMcp(tc)).toThrow(TranslationError);
});
it("maps MCP isError:false → OpenAI tool message with the text content", () => {
const result: McpResult = {
content: [{ type: "text", text: '{"repos":["a"]}' }],
isError: false,
};
expect(mcpResultToToolMessage(result, "call_1")).toEqual({
role: "tool",
tool_call_id: "call_1",
content: '{"repos":["a"]}',
});
});
it("maps MCP isError:true → OpenAI tool message prefixed with 'ERROR: '", () => {
const result: McpResult = {
content: [{ type: "text", text: "upstream 503" }],
isError: true,
};
expect(mcpResultToToolMessage(result, "call_2").content).toBe("ERROR: upstream 503");
});
it("the registry → OpenAI tools param preserves inputSchema as parameters", () => {
const defs = toolsToOpenAi(listTools());
expect(defs).toHaveLength(9);
const listVms = defs.find((d) => d.function.name === "proxmox.list_vms");
expect(listVms?.function.parameters).toMatchObject({ type: "object", required: ["node"] });
});
});