import { describe, expect, it } from "@effect/vitest";import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";import { Effect } from "effect"; import type { ExecutionEngine } from "@executor-js/execution"; import { createMcpRequestHandler } from "./mcp"; const engine: ExecutionEngine = { execute: (code) => Effect.succeed({ result: `ran: ${code}` }), executeWithPause: (code) => Effect.succeed({ status: "completed", result: { result: `ran: ${code}` } }), resume: () => Effect.succeed(null), isExecutionSettled: () => Effect.succeed(false), getPausedExecution: () => Effect.succeed(null), pausedExecutionCount: () => Effect.succeed(0), hasPausedExecutions: () => Effect.succeed(false), getDescription: Effect.succeed("local modern MCP test executor"),}; describe("local modern MCP HTTP", () => { it("discovers, lists tools, and executes without creating a legacy session", async () => { const mcp = createMcpRequestHandler({ engine }); const sessionHeaders: Array<string | null> = []; const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), { fetch: async (input, init) => { const request = input instanceof Request ? new Request(input, init) : new Request(input.toString(), init); const response = await mcp.handleRequest(request); sessionHeaders.push(response.headers.get("mcp-session-id")); return response; }, }); const client = new Client( { name: "local-modern-test", version: "1.0.0" }, { capabilities: {}, versionNegotiation: { mode: { pin: "2026-07-28" } } }, ); await client.connect(transport); // oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close the client and local handler try { expect((await client.listTools()).tools.map(({ name }) => name)).toContain("execute"); const result = await client.callTool({ name: "execute", arguments: { code: "2 + 2" }, }); expect(result.content).toEqual([{ type: "text", text: "ran: 2 + 2" }]); expect(sessionHeaders.every((sessionId) => sessionId === null)).toBe(true); } finally { await client.close(); await mcp.close(); } }); it("rejects a pinned modern client with the unsupported-version protocol error", async () => { const mcp = createMcpRequestHandler({ defaultConfig: { engine }, modernEnabled: false }); const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), { fetch: (input, init) => mcp.handleRequest( input instanceof Request ? new Request(input, init) : new Request(input.toString(), init), ), }); const client = new Client( { name: "local-modern-disabled-test", version: "1.0.0" }, { capabilities: {}, versionNegotiation: { mode: { pin: "2026-07-28" } } }, ); // oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close a client whose pinned negotiation is expected to fail try { await expect(client.connect(transport)).rejects.toThrow(/version negotiation failed/i); } finally { await client.close(); await mcp.close(); } }); it("lets an auto-mode v2 client fall back to legacy when modern inbound is disabled", async () => { const mcp = createMcpRequestHandler({ defaultConfig: { engine }, modernEnabled: false }); const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), { fetch: (input, init) => mcp.handleRequest( input instanceof Request ? new Request(input, init) : new Request(input.toString(), init), ), }); const client = new Client( { name: "local-auto-fallback-test", version: "1.0.0" }, { capabilities: {}, versionNegotiation: { mode: "auto" } }, ); await client.connect(transport); // oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close the fallback client and local handler try { expect(client.getProtocolEra()).toBe("legacy"); expect((await client.listTools()).tools.map(({ name }) => name)).toContain("execute"); const result = await client.callTool({ name: "execute", arguments: { code: "3 + 4" }, }); expect(result.content).toEqual([{ type: "text", text: "ran: 3 + 4" }]); expect(transport.sessionId).toBeTruthy(); } finally { await client.close(); await mcp.close(); } });});
import { describe, expect, it } from "@effect/vitest";
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
import { Effect } from "effect";
import type { ExecutionEngine } from "@executor-js/execution";
import { createMcpRequestHandler } from "./mcp";
const engine: ExecutionEngine = {
execute: (code) => Effect.succeed({ result: `ran: ${code}` }),
executeWithPause: (code) =>
Effect.succeed({ status: "completed", result: { result: `ran: ${code}` } }),
resume: () => Effect.succeed(null),
isExecutionSettled: () => Effect.succeed(false),
getPausedExecution: () => Effect.succeed(null),
pausedExecutionCount: () => Effect.succeed(0),
hasPausedExecutions: () => Effect.succeed(false),
getDescription: Effect.succeed("local modern MCP test executor"),
};
describe("local modern MCP HTTP", () => {
it("discovers, lists tools, and executes without creating a legacy session", async () => {
const mcp = createMcpRequestHandler({ engine });
const sessionHeaders: Array<string | null> = [];
const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), {
fetch: async (input, init) => {
const request =
input instanceof Request ? new Request(input, init) : new Request(input.toString(), init);
const response = await mcp.handleRequest(request);
sessionHeaders.push(response.headers.get("mcp-session-id"));
return response;
},
});
const client = new Client(
{ name: "local-modern-test", version: "1.0.0" },
{ capabilities: {}, versionNegotiation: { mode: { pin: "2026-07-28" } } },
);
await client.connect(transport);
// oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close the client and local handler
try {
expect((await client.listTools()).tools.map(({ name }) => name)).toContain("execute");
const result = await client.callTool({
name: "execute",
arguments: { code: "2 + 2" },
});
expect(result.content).toEqual([{ type: "text", text: "ran: 2 + 2" }]);
expect(sessionHeaders.every((sessionId) => sessionId === null)).toBe(true);
} finally {
await client.close();
await mcp.close();
}
});
it("rejects a pinned modern client with the unsupported-version protocol error", async () => {
const mcp = createMcpRequestHandler({ defaultConfig: { engine }, modernEnabled: false });
const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), {
fetch: (input, init) =>
mcp.handleRequest(
input instanceof Request ? new Request(input, init) : new Request(input.toString(), init),
),
});
const client = new Client(
{ name: "local-modern-disabled-test", version: "1.0.0" },
{ capabilities: {}, versionNegotiation: { mode: { pin: "2026-07-28" } } },
);
// oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close a client whose pinned negotiation is expected to fail
try {
await expect(client.connect(transport)).rejects.toThrow(/version negotiation failed/i);
} finally {
await client.close();
await mcp.close();
}
});
it("lets an auto-mode v2 client fall back to legacy when modern inbound is disabled", async () => {
const mcp = createMcpRequestHandler({ defaultConfig: { engine }, modernEnabled: false });
const transport = new StreamableHTTPClientTransport(new URL("http://local.test/mcp"), {
fetch: (input, init) =>
mcp.handleRequest(
input instanceof Request ? new Request(input, init) : new Request(input.toString(), init),
),
});
const client = new Client(
{ name: "local-auto-fallback-test", version: "1.0.0" },
{ capabilities: {}, versionNegotiation: { mode: "auto" } },
);
await client.connect(transport);
// oxlint-disable-next-line executor/no-try-catch-or-throw -- test boundary: always close the fallback client and local handler
try {
expect(client.getProtocolEra()).toBe("legacy");
expect((await client.listTools()).tools.map(({ name }) => name)).toContain("execute");
const result = await client.callTool({
name: "execute",
arguments: { code: "3 + 4" },
});
expect(result.content).toEqual([{ type: "text", text: "ran: 3 + 4" }]);
expect(transport.sessionId).toBeTruthy();
} finally {
await client.close();
await mcp.close();
}
});
});