Files
webstudio/apps/builder/app/services/api-permits.server.test.ts
Oleg Isonen d291e4b671 feat: Builder api runtime contracts guardrails for MCP (#5857)
This PR expands Webstudio MCP and CLI into a more complete agent
authoring interface. Agents can discover project capabilities, edit real
Webstudio content, use data/resources, verify visual output, and report
useful issues when workflows fail.

## MCP User Capabilities

- Create, update, duplicate, reorder, and delete pages.
- Create pages from templates and manage reusable page templates.
- Inspect project pages, instances, props, styles, assets, variables,
resources, and metadata.
- Insert Webstudio components and authored JSX fragments into pages.
- Edit text, props, styles, breakpoints, design tokens, and CSS
variables.
- Update page metadata, SEO fields, redirects, marketplace metadata, and
project settings.
- Create and use static data variables.
- Create and use dynamic resources fetched over HTTP.
- Use REST, GraphQL, and built-in system resources in authored pages.
- Bind data variables and resources to visible page content.
- Create resource-backed pages such as sitemap XML, structured SEO data,
and API-driven content sections.
- Preview current project state without requiring a publish step.
- Capture screenshots for visual verification.
- Verify responsive designs across desktop, tablet, and mobile
breakpoints.
- Use screenshot diff and OCR-style checks to inspect rendered output.
- Reset and refresh local MCP project state when needed.
- Discover available CLI/MCP commands from generated manuals.
- Use clearer examples for resources, data variables, JSX authoring,
previewing, and visual checks.
- Read marketplace product metadata without requiring a full project
snapshot.
- Get safer guidance when using low-level patch tools.
- Get a ready-to-copy Discord report template when MCP/CLI behavior is
confusing or broken.
2026-07-10 02:13:22 +02:00

51 lines
1.5 KiB
TypeScript

import { expect, test } from "vitest";
import { TRPCError } from "@trpc/server";
import {
assertApiProjectPermit,
getTokenPermits,
loadApiToken,
} from "./api-permits.server";
// @ts-expect-error Builder API project operations do not accept workspace-owner-only permit.
const ownerOnlyApiProjectPermit: Parameters<typeof assertApiProjectPermit>[2] =
"own";
void ownerOnlyApiProjectPermit;
const createContext = ({
allowAdditionalPermissions = true,
}: {
allowAdditionalPermissions?: boolean;
}) =>
({
authorization: { type: "user" },
planFeatures: { allowAdditionalPermissions },
}) as Parameters<typeof loadApiToken>[0] & {
planFeatures: { allowAdditionalPermissions: boolean };
};
test("loadApiToken rejects non-token authorization before database lookup", async () => {
await expect(loadApiToken(createContext({}))).rejects.toBeInstanceOf(
TRPCError
);
await expect(loadApiToken(createContext({}))).rejects.toMatchObject({
code: "FORBIDDEN",
message: "Builder API requires an API token",
});
});
test("getTokenPermits includes api only when token and plan allow it", () => {
const token = {
relation: "viewers",
canUseApi: true,
} as Parameters<typeof getTokenPermits>[0];
const ctx = createContext({});
expect(getTokenPermits(token, ctx)).toContain("api");
expect(getTokenPermits({ ...token, canUseApi: false }, ctx)).not.toContain(
"api"
);
expect(
getTokenPermits(token, createContext({ allowAdditionalPermissions: false }))
).not.toContain("api");
});