Brand MCP Server
Supports OAuth 2.1 resource-server authentication using Auth0 as an OIDC identity provider, validating JWTs against JWKS, enforcing scopes, and mapping app roles to per-brand access.
Imports design tokens from Figma Variables via the Figma REST API, exporting local variables to DTCG token files and mapping colors, aliases, dimensions, and font variables.
Supports OAuth 2.1 resource-server authentication using Keycloak as an OIDC identity provider, validating JWTs against JWKS, enforcing scopes, and mapping app roles to per-brand access.
Supports OAuth 2.1 resource-server authentication using Okta as an OIDC identity provider, validating JWTs against JWKS, enforcing scopes, and mapping app roles to per-brand access.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Brand MCP server
A remote MCP server that gives AI agents (Claude, Cursor, Copilot, VS Code) a brand's rules, design tokens, logos and ad formats, and lets them check their own output against those rules before a human sees it.
TypeScript, MCP TypeScript SDK v2 (
@modelcontextprotocol/server2.4), spec 2026-07-28, also serves 2025-era clients.Streamable HTTP, stateless: one web-standard
fetchhandler that runs on Node, in Docker, on Vercel and other fetch runtimes. stdio works for local use too.OAuth 2.1 resource server: JWT validation against your IdP (Entra ID, Okta, Auth0, Keycloak), RFC 9728 protected-resource metadata, scopes, and per-brand access from app roles.
Design tokens in DTCG 2025.10, built with Style Dictionary v5, imported from Figma Variables.
Check tools built on headless Chromium (Playwright) and axe-core (WCAG 2.1 AA).
Evals in CI: deterministic tool evals on every change, plus an agent eval in which Claude must answer verifiable questions using only the tools.
The three brands in brands/ (Haferglück, Kiesel, Sonnfeld) are fictional German consumer brands. They show the structure and the kind of rules the tools enforce, including real German and EU advertising rules: "Hafermilch", biocide disclaimers and sunscreen claims. Replace them with your own.
Quick start
npm ci
npx playwright install chromium # for check_ad (html), check_page, check_visual
npm test # builds brands, runs 80+ tests
npm run eval # deterministic tool evals
npm start # http://127.0.0.1:3000/mcp (no auth locally)Connect a client to the local server:
claude mcp add --transport http brand http://127.0.0.1:3000/mcp # Claude Code
npx @modelcontextprotocol/inspector # MCP Inspector → Streamable HTTP → the URL// Cursor: .cursor/mcp.json · VS Code: .vscode/mcp.json ("servers" instead of "mcpServers")
{ "mcpServers": { "brand": { "url": "https://brand-mcp.example.com/mcp" } } }For a local child process instead of HTTP: { "command": "npx", "args": ["tsx", "src/stdio.ts"], "cwd": "/path/to/brand-mcp-server" }.
Related MCP server: frontend-design-mcp
Tools
The server has twelve tools. Each one answers a whole question an agent has; none is a thin wrapper over a single data file. Every tool takes brand, an enum of the brand ids, so the model never has to guess a brand name. All tools are annotated readOnlyHint and idempotentHint. They return a short JSON text and structuredContent. Check tools also return image content when there is a screenshot.
Tool | What the agent gets |
| Start here. Summary, personality, du/Sie, fonts, semantic colours, approved colour pairs, logo versions, booked ad slots, and the index of guideline sections. |
| Tokens by group ( |
| Reverse lookup from a raw value ( |
| BM25 search over the guideline Markdown, in German or English, or direct access by section or page. Results carry |
| The right logo version for a background, as SVG, with minimum size, clear space and approved backgrounds. Refuses backgrounds no logo is approved for. |
| The slots a brand books, merged with its rules: size, file types, weight, animation, safe zone, headline length, CTA, logo version, minimum width and placement, and backgrounds. Also covers organic and print formats. |
| WCAG 2.1 ratios plus the brand's own approved and forbidden pairs per usage (text, large text, UI). With only a background, it lists the approved foregrounds. |
| German copy rules: banned or legally risky terms (inflections included), du/Sie, brand-name spelling, exclamation marks, mandatory disclaimers, CTA labels, and the headline length for a slot. |
| CSS, SCSS, HTML, JSX and Tailwind: hard-coded and off-palette colours, primitive or unknown tokens, foreign fonts, and sizes off the scale. Each finding has a line number and the token to use instead. |
| Checks a creative against the slot spec from its facts. With HTML5 source it also renders the ad at slot size: overflow, safe zone, logo size and placement, CTA, background and border, fonts, palette, axe contrast, and copy. |
| Renders HTML (or an allow-listed URL) at any viewport. Checks axe-core WCAG 2.1 A/AA, palette, fonts, text size, line length, tap targets, horizontal overflow and logo size. |
| Screenshot plus pixel analysis: palette coverage, dominant colours mapped to tokens, and whether the key brand colours are present. The image is returned so the model can judge composition itself. |
Every check tool returns the same shape: { passed, errors, warnings, findings: [{ rule, severity, message, where, suggestion, source }] }. rule is a stable id, so evals and CI can assert on it. source is the brand:// URI of the rule behind the finding.
Resources
URI | Content |
| One-page Markdown summary |
| Style Dictionary builds and the DTCG source |
| Guideline pages: |
| SVG |
| Machine-readable rules |
Prompts
review_ad, review_page and review_copy tell the agent which tools to call, in which order, and how to report: a findings table with severity, rule, location, fix and source, followed by a verdict (Approved, Approved with changes, Not approved).
Brand repo (phase 1)
brands/
_shared/ad-slots.json IAB display + social + DOOH slots, shared by all brands
_shared/formats.json organic, email and print formats
<brand>/
brand.json name, fonts, logo specs, layout and visual rules
tokens/*.tokens.json DTCG 2025.10 (exported from Figma Variables)
guidelines/*.md guidelines as Markdown, split into sections at "## "
rules/color-pairs.json approved and forbidden foreground/background pairs per usage
rules/copy.json du/Sie, banned terms, mandatory disclaimers, brand-name spelling, CTA labels
rules/ad-slots.json booked slots, brand defaults, per-slot overrides
logos/*.svgTokens use the DTCG 2025.10 value forms: colours as { colorSpace, components, alpha?, hex }, dimensions and durations as { value, unit }, and references as {color.primitive.forest.700}. Each brand has a primitive layer (color.primitive.*) and a semantic layer (color.text.default, color.action.primary …). Product code and agents use only the semantic layer.
Style Dictionary v5 (scripts/build-tokens.ts) builds CSS custom properties (with references kept as var()), SCSS, an ES module and a flat JSON index the server reads. Three small value transforms turn the 2025.10 object forms into CSS before the standard transforms run.
Figma: npm run figma:export -- --file <key> --brand <id> [--mode Light] reads the file's local variables through the Figma REST API (Enterprise plan, file_variables:read). It writes one DTCG file per collection. It maps colours to 2025.10 colour objects, aliases to references, FLOAT variables by scope (FONT_WEIGHT becomes fontWeight, everything else becomes dimension), and font-family strings to arrays.
Validation: npm run build:brands validates the whole repo and fails CI if anything is wrong:
the DTCG structure and types;
every token referenced by rules, logos and ad slots;
that every approved colour pair actually passes WCAG for its stated usage;
that the logo files exist.
It then bundles everything into one JSON file, so the server needs no file system at runtime.
Authorization (OAuth / SSO)
The server is an OAuth 2.1 resource server, following the MCP authorization spec. It never issues tokens. For each request it:
answers
401withWWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp"when there is no valid token;serves the RFC 9728 protected-resource metadata, which points at your IdP, plus a mirror of the IdP's metadata;
verifies JWTs against the IdP's JWKS: signature,
iss,aud,exp, and allowed algorithms;requires the configured scope, returning
403 insufficient_scopeif it is missing;reads per-brand access from app roles.
Brand.Allsees every brand;Brand.Kieselsees only Kiesel. WithBRAND_ROLES_REQUIRED=true, a token without a brand role sees nothing.
It also enforces a Host allow-list (DNS-rebinding protection) and an optional Origin allow-list.
Entra ID setup
App registrations → New registration, for example "Brand MCP API".
Expose an API: set the Application ID URI (
api://brand-mcp) and add the scopeBrand.Read.App roles: add
Brand.All,Brand.Haferglueck,Brand.KieselandBrand.Sonnfeld(allowed member types: users/groups and applications). Assign them to groups under Enterprise applications.Manifest: set
"requestedAccessTokenVersion": 2.Configure the server:
AUTH_MODE=oidc
OIDC_ISSUER=https://login.microsoftonline.com/<tenant-id>/v2.0
OIDC_AUDIENCE=<api-client-id>,api://brand-mcp
OIDC_REQUIRED_SCOPES=Brand.Read
OIDC_SCOPES_SUPPORTED=api://brand-mcp/Brand.Read
BRAND_ROLES_REQUIRED=true
MCP_PUBLIC_URL=https://brand-mcp.example.com/mcp
ALLOWED_HOSTS=brand-mcp.example.comApp-only tokens (client credentials, for CI bots) carry roles instead of scp. A Brand.* app role grants access.
Entra ID does not support dynamic client registration. Clients that can be configured with a pre-registered client id work directly against Entra. For clients that require dynamic registration, put an OAuth broker in front of Entra, such as a Cloudflare workers-oauth-provider, Auth0 or Keycloak federating to Entra. The server only needs the broker's issuer and audience.
Without OIDC_ISSUER, the server runs without auth for local development. It refuses to start that way in production unless ALLOW_ANONYMOUS=true is set explicitly.
Check tools (phase 4)
check_ad (with html), check_page and check_visual render in headless Chromium:
Isolation: each check gets a fresh browser context, and every network request is blocked except
data:/blob:and the hosts inBRAND_CHECK_ASSET_HOSTS(Google Fonts by default). Live-URL checks are only allowed forhttps://hosts listed inBRAND_CHECK_URL_HOSTS, so a check can never reach internal services.axe-core runs with the
wcag2a,wcag2aa,wcag21aandwcag21aatags. Serious and critical violations are errors.Brand rules use computed styles (colour, background, border, font family and size, element boxes) compared against tokens with OKLab ΔE, and screenshot pixels for palette coverage.
Where the browser comes from: locally and in Docker it is Playwright's Chromium. On serverless platforms set
BROWSER_WS_ENDPOINT(a Playwright server) orBROWSER_CDP_ENDPOINT(any CDP browser service). Without a browser, these three tools return a clear error, and all other tools keep working.
Evals (phase 3)
npm run eval # evals/cases/tools.json + evals/client-cases/*.json
npm run eval:agent # needs ANTHROPIC_API_KEY; EVAL_MODEL, EVAL_MIN_PASS optionalTool evals are deterministic. There are 31 cases, one tool call each, with assertions on the result:
{ "id": "copy-biocide-disclaimer", "tool": "check_copy",
"args": { "brand": "kiesel", "text": "Der neue Hygienespüler." },
"expect": { "passed": false, "rules": ["copy.required-disclaimer"] } }The available assertions are isError, passed, rules (must include), notRules, equals (dot paths into the JSON result) and includes. HTML fixtures can be referenced as "@fixture:goodAd". Existing test cases go into evals/client-cases/*.json in the same format and run with the rest.
Agent eval: Claude gets only the MCP tools and 15 verifiable questions. Examples: "Which CSS custom property should a Kiesel button use for its background?" and "Is the Sonnfeld headline „Ihr Sunblocker für den ganzen Tag“ allowed?" Answers are graded mechanically (exact, includes, regex, oneOf). This measures tool design, not just tool correctness: a question fails when the model can't find or use the right tool.
Both suites write evals/results/*.json, JUnit XML, and a Markdown table to the GitHub job summary.
CI (.github/workflows/ci.yml) runs on every push and pull request:
brand validation and the token build;
typecheck;
tests;
tool evals;
the agent eval, when the
ANTHROPIC_API_KEYsecret is set;a container smoke test that builds the Docker image and calls the server over HTTP.
Deploy
Target | How |
Docker / any VM / Azure Container Apps / Cloud Run |
|
Vercel |
|
Other fetch runtimes |
|
The endpoint is stateless (SDK v2 per-request servers), so it scales horizontally without sticky sessions.
Project layout
src/
server.ts tools, resources, prompts (createServer factory)
http.ts fetch handler: /mcp, OAuth metadata, auth gate, host checks, /healthz
auth.ts JWT/JWKS verification, Entra ID claims, brand roles
node.ts Node entry (npm start) stdio.ts stdio entry
data.ts brand bundle access, colour resolution
checks/ copy, code, contrast, ad-spec, browser + render (Playwright/axe)
lib/ colour maths (WCAG, OKLab), BM25 guideline search
scripts/ build-tokens (Style Dictionary), build-data (validate + bundle), figma-export
api/index.ts Vercel entry
evals/ runner, cases, client-cases
tests/ unit, protocol (real MCP client over Streamable HTTP), OAuth, browser, FigmaSecurity notes
The server has no write tools. Brand data changes only through pull requests to this repository, which pass CI.
Inputs are bounded: string lengths, a 50-pair contrast limit, and
maxToolInputElements. Rendered HTML cannot make network requests except to allow-listed font hosts.Tokens are verified locally against cached JWKS. No token is logged or passed on.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Your brand's Styles, logos and asset library in your AI app, for on-brand assets that match.
Give your agent your brand's DNA: context, F-VAL validation and on-brand content generation.
Give your agent a real design system: tokens, measured WCAG contrast, and rules to follow.
Brand strategy and content-calendar context for agents, with human-confirmed approval gates.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA memory-backed brand generation runtime for agent-led creative iteration. Enables AI agents to plan, generate, review, and improve brand materials with persistent brand memory and structured workflows.MIT
- AlicenseAqualityBmaintenanceEnables AI coding agents to search public design-system catalogs and retrieve only the relevant tokens or sections for a chosen brand, so generated UI matches a specified visual style instead of generic AI output.832 npm1BSD 3-Clause
- AlicenseNot gradedqualityCmaintenanceEnables coding agents to retrieve accurate design system information, component APIs, design tokens, and coding standards, so they build with real specs rather than guessing.2MIT
- AlicenseAqualityBmaintenanceIt lets AI coding agents look up design tokens, component specifications, and prohibition rules on demand, then validate generated HTML or JSX with the same lint logic used by CI and editor hooks so violations are caught and corrected immediately. It also exposes the design constitution and rule sets as resources for reference during generation.6272 npm202MIT