Skip to main content
Glama

brand_preflight

Check HTML/CSS against brand rules: detect off-brand colors, wrong fonts, missing logo, and anti-pattern violations. Returns pass/warn/fail per rule.

Instructions

Check HTML/CSS against brand rules — catches off-brand colors, wrong fonts, missing logo, and anti-pattern violations (drop shadows, gradients, etc.). Pass an HTML string or file path. Mode 'check' (default) runs all compliance checks and returns pass/warn/fail per rule. Mode 'rules' lists all active preflight rules without checking content. Use after generating any visual content to validate brand compliance. Returns overall status and per-check details. NOT for scoring content copy — use brand_audit_content. NOT for brand directory validation — use brand_audit.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
htmlYesHTML to validate: either a full HTML string (with <style> blocks) or a file path ending in .html (e.g. 'output.html')
modeNo'check' (default): validates HTML against all brand rules. 'rules': lists all active rules without running checks.check

Implementation Reference

  • Main handler function for the brand_preflight tool. Accepts 'mode' (check|rules) and 'html' (string or file path). In 'rules' mode, lists active preflight rules. In 'check' mode, resolves HTML (inline or file), then runs all compliance checks (colors, typography, logo, anti-patterns). Returns overall PASS/WARN/FAIL with per-check details.
    async function handler(input: Params) {
      const brandDir = new BrandDir(process.cwd());
    
      if (!(await brandDir.exists())) {
        return buildResponse({
          what_happened: "No .brand/ directory found",
          next_steps: ["Run brand_start to create a brand system first"],
          data: { error: ERROR_CODES.NOT_INITIALIZED },
        });
      }
    
      const mode = input.mode || "check";
    
      if (mode === "rules") {
        return handleRules(brandDir);
      }
    
      // Resolve HTML: if it looks like a file path, read it
      let html = input.html;
      if (
        !html.includes("<") &&
        (html.endsWith(".html") || html.endsWith(".htm") || html.startsWith("/"))
      ) {
        const resolvedPath = resolve(process.cwd(), html);
        if (!isPathWithinBase(resolvedPath, process.cwd())) {
          return buildResponse({
            what_happened: "File path must be within the current working directory",
            next_steps: ["Provide an HTML string or a file path within your project"],
            data: { error: ERROR_CODES.PATH_OUTSIDE_CWD },
          });
        }
        try {
          html = await readFile(resolvedPath, "utf-8");
        } catch {
          return buildResponse({
            what_happened: `Could not read file: ${input.html}`,
            next_steps: ["Provide valid HTML content or a readable file path"],
            data: { error: ERROR_CODES.FILE_NOT_FOUND, path: input.html },
          });
        }
      }
    
      return handleCheck(brandDir, html);
    }
  • Registers the brand_preflight tool on the MCP server with input parameters (html: string, mode: 'check'|'rules') and a description of its functionality.
    export function register(server: McpServer) {
      server.tool(
        "brand_preflight",
        "Check HTML/CSS against brand rules — catches off-brand colors, wrong fonts, missing logo, and anti-pattern violations (drop shadows, gradients, etc.). Pass an HTML string or file path. Mode 'check' (default) runs all compliance checks and returns pass/warn/fail per rule. Mode 'rules' lists all active preflight rules without checking content. Use after generating any visual content to validate brand compliance. Returns overall status and per-check details. NOT for scoring content copy — use brand_audit_content. NOT for brand directory validation — use brand_audit.",
        paramsShape,
        async (args) => {
          const parsed = safeParseParams(ParamsSchema, args);
          if (!parsed.success) return parsed.response;
          return handler(parsed.data);
        }
      );
    }
  • Zod schema defining the input parameters for brand_preflight: 'html' (string, required) and 'mode' (enum 'check'|'rules' with default 'check').
    const paramsShape = {
      html: z
        .string()
        .describe(
          "HTML to validate: either a full HTML string (with <style> blocks) or a file path ending in .html (e.g. 'output.html')"
        ),
      mode: z
        .enum(["check", "rules"])
        .default("check")
        .describe(
          "'check' (default): validates HTML against all brand rules. 'rules': lists all active rules without running checks."
        ),
    };
    
    const ParamsSchema = z.object(paramsShape);
    type Params = z.infer<typeof ParamsSchema>;
  • Core check logic: loads brand identity, parses HTML with cheerio, runs color checks, typography checks, logo presence checks, and anti-pattern matchers. Returns overall PASS/WARN/FAIL with per-check details.
    async function handleCheck(brandDir: BrandDir, html: string) {
      const identity = await brandDir.readCoreIdentity();
    
      let antiPatterns: AntiPatternRule[] = [];
      if (await brandDir.hasVisualIdentity()) {
        const vi = await brandDir.readVisualIdentity();
        antiPatterns = vi.anti_patterns || [];
      }
    
      let clientName = "";
      try {
        const config = await brandDir.readConfig();
        clientName = config.client_name || "";
      } catch {
        // Non-critical — logo checks just won't match by name
      }
    
      // Parse HTML
      const $ = cheerio.load(html);
      const css = extractAllCss($);
    
      // Run all checks
      const checks: PreflightCheck[] = [
        ...checkColors(css, identity),
        ...checkTypography(css, identity),
        ...checkLogo($, identity, clientName),
        ...checkAntiPatterns(css, antiPatterns),
      ];
    
      // Compute summary
      const pass = checks.filter((c) => c.status === "pass").length;
      const warn = checks.filter((c) => c.status === "warn").length;
      const fail = checks.filter((c) => c.status === "fail").length;
      const overall = fail > 0 ? "FAIL" : warn > 0 ? "WARN" : "PASS";
    
      const nextSteps: string[] = [];
      if (fail > 0) nextSteps.push("Fix failing checks (hard anti-patterns) before shipping");
      if (warn > 0) nextSteps.push("Review warnings — some may be intentional deviations");
      if (fail === 0 && warn === 0) nextSteps.push("All checks pass — content is brand-compliant");
    
      return buildResponse({
        what_happened: `Preflight ${overall}: ${pass} pass, ${warn} warn, ${fail} fail`,
        next_steps: nextSteps,
        data: {
          overall,
          summary: { pass, warn, fail },
          checks: checks as unknown as Record<string, unknown>[],
        },
      });
    }
  • Handler for 'rules' mode: compiles all preflight rules from brand identity (colors, typography, logo, anti-patterns) and returns them without running checks.
    async function handleRules(brandDir: BrandDir) {
      const identity = await brandDir.readCoreIdentity();
    
      let antiPatterns: AntiPatternRule[] = [];
      if (await brandDir.hasVisualIdentity()) {
        const vi = await brandDir.readVisualIdentity();
        antiPatterns = vi.anti_patterns || [];
      }
    
      const rules = compileRules(identity, antiPatterns);
    
      return buildResponse({
        what_happened: `Compiled ${rules.length} preflight rules from brand system`,
        next_steps: [
          "Run brand_preflight with mode 'check' and HTML content to run compliance checks",
          rules.some((r) => !r.checkable)
            ? "Some rules are not checkable — add more data to core-identity.yaml"
            : "All rules are checkable",
        ],
        data: {
          rule_count: rules.length,
          rules: rules as unknown as Record<string, unknown>[],
        },
      });
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It details what the tool catches (off-brand colors, fonts, logo, anti-patterns) and its return format (pass/warn/fail, overall status). It does not explicitly state it is read-only, but the nature of a preflight check implies no side effects. Slightly more explicit disclosure would improve it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact (≈100 words) with a clear front-loaded purpose, followed by parameter and mode details, and ends with exclusionary statements. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description adequately explains return format (overall status, per-check details) and covers both modes. It provides usage context (after visual content) and differentiates from siblings, making it complete for agent invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds meaning by specifying 'HTML string or file path' for the html parameter and explaining the effects of each mode value, including the default. This goes beyond the schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool checks HTML/CSS against brand rules and lists specific violations. It explicitly distinguishes from siblings like brand_audit_content and brand_audit, making purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises use after generating visual content and explains modes 'check' and 'rules' with their purposes. It explicitly states when not to use and names alternative tools, providing complete usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Brandcode-Studio/brandsystem-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server