import { describe, expect, it } from "@effect/vitest"; import { Client, StreamableHTTPClientTransport, withInputRequired, type Request as McpRequest, } from "@modelcontextprotocol/client"; import { CallToolResultSchema } from "@modelcontextprotocol/core"; import { createMcpHandler, isInputRequiredResult, type InputRequiredResult, } from "@modelcontextprotocol/server"; import { Effect } from "effect"; import type { ExecutionEngine, ExecutionResult, ResumeResponse } from "@executor-js/execution"; import { defaultMcpResource, type McpResource } from "./seams"; import { FormElicitation, ToolAddress } from "@executor-js/sdk"; import { appsEnabledForClientCapabilities, buildMcpServer, mcpRequestStateBindingFromBody, } from "./tool-server"; import { RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY } from "./mcp-apps"; const REQUEST_STATE_KEY = new Uint8Array(32).fill(7); const TOOL_ADDRESS = ToolAddress.make("tools.test.org.main.echo"); const APP_URI = "ui://executor/shell.html"; type TestServerConfig = { readonly engine: ExecutionEngine; readonly appsEnabled: boolean; readonly elicitationMode?: { readonly mode: "model" } | { readonly mode: "native" }; readonly loadAppShellHtml?: () => Promise; /** Evaluated per request, so a test can swap principals between rounds. */ readonly requestStatePrincipal?: () => string; /** Evaluated per request, so a test can swap resources between rounds. */ readonly requestStateResource?: () => McpResource; }; const makeStubEngine = ( overrides: { readonly executeWithPause?: ExecutionEngine["executeWithPause"]; readonly resume?: ExecutionEngine["resume"]; readonly getPausedExecution?: ExecutionEngine["getPausedExecution"]; } = {}, ): ExecutionEngine => ({ execute: (code) => Effect.succeed({ result: `ran: ${code}` }), executeWithPause: overrides.executeWithPause ?? ((code) => Effect.succeed({ status: "completed", result: { result: `ran: ${code}` } })), resume: overrides.resume ?? (() => Effect.succeed(null)), isExecutionSettled: () => Effect.succeed(false), getPausedExecution: overrides.getPausedExecution ?? (() => Effect.succeed(null)), pausedExecutionCount: () => Effect.succeed(0), hasPausedExecutions: () => Effect.succeed(false), getDescription: Effect.succeed("test executor"), }); const withClient = async ( config: TestServerConfig, run: (client: Client) => Promise, options?: { readonly manualInputRequired?: boolean }, ) => { const requestBodies = new WeakMap(); const handler = createMcpHandler( (context) => Effect.runPromise( Effect.gen(function* () { const requestStatePrincipal = config.requestStatePrincipal?.() ?? "principal-test"; const requestStateResource = config.requestStateResource?.() ?? defaultMcpResource; const requestStateBinding = yield* Effect.promise(() => mcpRequestStateBindingFromBody({ body: context.requestInfo ? requestBodies.get(context.requestInfo) : undefined, principal: requestStatePrincipal, resource: requestStateResource, }), ); return yield* buildMcpServer({ ...config, requestStateSigningKey: REQUEST_STATE_KEY, requestStatePrincipal, ...(requestStateBinding === null ? {} : { requestStateBinding }), }); }), ), { legacy: "reject" }, ); const transport = new StreamableHTTPClientTransport(new URL("http://executor.test/mcp"), { fetch: async (input, init) => { const request = input instanceof Request ? new Request(input, init) : new Request(input.toString(), init); requestBodies.set(request, await request.clone().json()); return handler.fetch(request, { parsedBody: requestBodies.get(request) }); }, }); const client = new Client( { name: "executor-protocol-test", version: "1.0.0" }, { capabilities: { elicitation: { form: {} } }, versionNegotiation: { mode: { pin: "2026-07-28" } }, ...(options?.manualInputRequired ? { inputRequired: { autoFulfill: false } } : {}), }, ); await client.connect(transport); // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: test helper owns the client transport and in-process HTTP handler try { await run(client); } finally { await client.close(); await handler.close(); } }; const manualToolCall = ( client: Client, params: Record, ): Promise>> => { const request: McpRequest = { method: "tools/call", params }; return client.request(request, withInputRequired(CallToolResultSchema), { allowInputRequired: true, }); }; describe("Executor MCP protocol assembly", () => { it("lists Executor tools and executes code end to end over the modern HTTP entry", async () => { await withClient({ engine: makeStubEngine(), appsEnabled: false }, async (client) => { const names = (await client.listTools()).tools.map(({ name }) => name); expect(names).toContain("execute"); expect(names).toContain("skills"); expect(names).toContain("resume"); const result = await client.callTool({ name: "execute", arguments: { code: "1 + 1" }, }); expect(result.content).toEqual([{ type: "text", text: "ran: 1 + 1" }]); expect(result.isError).toBeFalsy(); }); }); it("registers app metadata and app-only tools only for apps-enabled requests", async () => { const inspect = async (appsEnabled: boolean) => { let observed: | { readonly names: readonly string[]; readonly createMeta: Record | undefined; readonly resourceCount: number; } | undefined; await withClient( { engine: makeStubEngine(), appsEnabled, loadAppShellHtml: async () => "", }, async (client) => { const tools = (await client.listTools()).tools; observed = { names: tools.map(({ name }) => name), createMeta: tools.find(({ name }) => name === "create-artifact")?._meta, resourceCount: (await client.listResources()).resources.length, }; }, ); return observed; }; const enabled = await inspect(true); expect(enabled?.names).toContain("execute-action"); expect(enabled?.createMeta).toMatchObject({ ui: { resourceUri: APP_URI, visibility: ["model"] }, [RESOURCE_URI_META_KEY]: APP_URI, }); expect(enabled?.resourceCount).toBe(1); const disabled = await inspect(false); expect(disabled?.names).not.toContain("execute-action"); expect(disabled?.createMeta).toBeUndefined(); expect(disabled?.resourceCount).toBe(0); }); it("returns input_required and resumes native elicitation from signed requestState", async () => { const request = FormElicitation.make({ message: "Which value?", requestedSchema: { type: "object", properties: { value: { type: "string" } }, required: ["value"], }, }); const paused: Extract = { status: "paused", execution: { id: "execution-1", elicitationContext: { address: TOOL_ADDRESS, args: {}, request }, }, }; let resumedWith: ResumeResponse | undefined; const engine = makeStubEngine({ executeWithPause: () => Effect.succeed(paused), getPausedExecution: () => Effect.succeed(paused.execution), resume: (_executionId, response) => { resumedWith = response; return Effect.succeed({ status: "completed", result: { result: response.content?.value }, }); }, }); await withClient( { engine, appsEnabled: false, elicitationMode: { mode: "native" } }, async (client) => { const first = await manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, }); expect(isInputRequiredResult(first)).toBe(true); if (!isInputRequiredResult(first)) return; expect(first.inputRequests?.elicitation).toMatchObject({ method: "elicitation/create", params: { message: "Which value?" }, }); expect(typeof first.requestState).toBe("string"); const completed = await manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, inputResponses: { elicitation: { action: "accept", content: { value: "approved" } }, }, requestState: first.requestState, }); expect(isInputRequiredResult(completed)).toBe(false); expect(completed.content).toEqual([{ type: "text", text: "approved" }]); expect(resumedWith).toEqual({ action: "accept", content: { value: "approved" } }); }, { manualInputRequired: true }, ); }); it("rejects a tampered native-elicitation requestState before resuming", async () => { const request = FormElicitation.make({ message: "Confirm", requestedSchema: {}, }); const paused: Extract = { status: "paused", execution: { id: "execution-2", elicitationContext: { address: TOOL_ADDRESS, args: {}, request }, }, }; let resumeCalls = 0; const engine = makeStubEngine({ executeWithPause: () => Effect.succeed(paused), getPausedExecution: () => Effect.succeed(paused.execution), resume: () => { resumeCalls += 1; return Effect.succeed(null); }, }); await withClient( { engine, appsEnabled: false, elicitationMode: { mode: "native" } }, async (client) => { const first = await manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, }); expect(isInputRequiredResult(first)).toBe(true); if (!isInputRequiredResult(first) || !first.requestState) return; // Corrupt an interior character: changing the final one can only touch // discarded base64url padding bits, which lenient decoders (Bun) drop — // the decoded bytes would be identical and the signature would verify. const middle = Math.floor(first.requestState.length / 2); const swapped = first.requestState[middle] === "A" ? "B" : "A"; const tampered = `${first.requestState.slice(0, middle)}${swapped}${first.requestState.slice(middle + 1)}`; await expect( manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, inputResponses: { elicitation: { action: "accept", content: {} } }, requestState: tampered, }), ).rejects.toMatchObject({ code: -32602 }); expect(resumeCalls).toBe(0); }, { manualInputRequired: true }, ); }); it("rejects a requestState echoed with a different principal, resource, or code", async () => { const request = FormElicitation.make({ message: "Confirm", requestedSchema: {}, }); const paused: Extract = { status: "paused", execution: { id: "execution-3", elicitationContext: { address: TOOL_ADDRESS, args: {}, request }, }, }; let resumeCalls = 0; const engine = makeStubEngine({ executeWithPause: () => Effect.succeed(paused), getPausedExecution: () => Effect.succeed(paused.execution), resume: () => { resumeCalls += 1; return Effect.succeed(null); }, }); let principal = "user-a"; let resource: McpResource = defaultMcpResource; await withClient( { engine, appsEnabled: false, elicitationMode: { mode: "native" }, requestStatePrincipal: () => principal, requestStateResource: () => resource, }, async (client) => { const first = await manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, }); expect(isInputRequiredResult(first)).toBe(true); if (!isInputRequiredResult(first) || !first.requestState) return; principal = "user-b"; await expect( manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, inputResponses: { elicitation: { action: "accept", content: {} } }, requestState: first.requestState, }), ).rejects.toMatchObject({ code: -32602 }); principal = "user-a"; resource = { kind: "toolkit", slug: "other" }; await expect( manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.echo()" }, inputResponses: { elicitation: { action: "accept", content: {} } }, requestState: first.requestState, }), ).rejects.toMatchObject({ code: -32602 }); resource = defaultMcpResource; await expect( manualToolCall(client, { name: "execute", arguments: { code: "await tools.test.different()" }, inputResponses: { elicitation: { action: "accept", content: {} } }, requestState: first.requestState, }), ).rejects.toMatchObject({ code: -32602 }); expect(resumeCalls).toBe(0); }, { manualInputRequired: true }, ); }); it("derives request-scoped app support from the exact MCP Apps MIME capability", () => { expect( appsEnabledForClientCapabilities({ extensions: { "io.modelcontextprotocol/ui": { mimeTypes: [RESOURCE_MIME_TYPE] }, }, }), ).toBe(true); expect( appsEnabledForClientCapabilities({ extensions: { "io.modelcontextprotocol/ui": { mimeTypes: ["text/html"] }, }, }), ).toBe(false); }); });