/** * `POST /api/app-document` (#2056) — the authenticated seam the browser hands a * wrapped MCP App document back through so the backend can serve it from a * dedicated origin. * * The route owns validation and the two "can't host it" answers; the listener * that actually serves the bytes is `clients/web/server/app-origin-controller` * and is tested separately. */ import { describe, it, expect, vi } from "vitest"; import { createRemoteApp } from "@inspector/core/mcp/remote/node/server.js"; function post(body: unknown): Request { return new Request("http://test/api/app-document", { method: "POST", headers: { "Content-Type": "application/json" }, body: typeof body === "string" ? body : JSON.stringify(body), }); } function appWith( publishAppDocument?: (doc: { html: string; csp?: string; }) => { url: string } | null, ) { return createRemoteApp({ dangerouslyOmitAuth: true, allowedOrigins: ["http://127.0.0.1:6274"], initialConfig: { defaultEnvironment: {} }, publishAppDocument, }).app; } describe("createRemoteApp POST /api/app-document", () => { it("publishes the document and returns the URL", async () => { const publish = vi .fn<(doc: { html: string; csp?: string }) => { url: string } | null>() .mockReturnValue({ url: "http://localhost:6276/app-document/abc" }); const res = await appWith(publish).request( post({ html: "
x
", csp: 42 }], ])("rejects %s with 400", async (_label, body) => { const publish = vi .fn<(doc: { html: string; csp?: string }) => { url: string } | null>() .mockReturnValue({ url: "http://x/y" }); const res = await appWith(publish).request(post(body)); expect(res.status).toBe(400); expect(publish).not.toHaveBeenCalled(); }); it("rejects an oversized document with 413 rather than pinning it in memory", async () => { const publish = vi .fn<(doc: { html: string; csp?: string }) => { url: string } | null>() .mockReturnValue({ url: "http://x/y" }); const res = await appWith(publish).request( post({ html: "x".repeat(8 * 1024 * 1024 + 1) }), ); expect(res.status).toBe(413); expect(publish).not.toHaveBeenCalled(); }); it("requires the auth token like every other /api route", async () => { const { app } = createRemoteApp({ authToken: "s3cret", allowedOrigins: ["http://127.0.0.1:6274"], initialConfig: { defaultEnvironment: {} }, publishAppDocument: () => ({ url: "http://x/y" }), }); const unauthorized = await app.request(post({ html: "x
" })); expect(unauthorized.status).toBe(401); const authorized = await app.request( new Request("http://test/api/app-document", { method: "POST", headers: { "Content-Type": "application/json", "x-mcp-remote-auth": "Bearer s3cret", }, body: JSON.stringify({ html: "x
" }), }), ); expect(authorized.status).toBe(200); }); });