design-system-mcp
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Fail
- Hardcoded secret — Potential hardcoded credential in deploy/k8s/secret.example.yaml
- exec() — Shell command execution in src/auth/apikey.ts
- exec() — Shell command execution in src/bundle/component-api.ts
Permissions Pass
- Permissions — No dangerous permissions requested
This is a Model Context Protocol (MCP) server that indexes design system repositories (tokens, components, and guidelines). It feeds this authoritative UI context to AI coding agents so they can generate front-end code that strictly adheres to specific design standards.
Security Assessment
The overall risk is High. The automated scan flagged two critical code execution vulnerabilities: shell command execution occurs in `src/auth/apikey.ts` and `src/bundle/component-api.ts`. This means the tool has the potential to spawn system processes, which could be exploited depending on the input it receives. Additionally, there is a hardcoded credential in `deploy/k8s/secret.example.yaml`. While this is a deployment configuration file rather than active source code, it represents a secret management risk. Because the server processes external Git repositories and parses various file formats, the combination of external inputs with active shell execution creates a significant attack surface.
Quality Assessment
The project is actively maintained and was updated very recently. It includes a standard MIT license, making it free for commercial and personal use. However, community trust and visibility are currently extremely low, with only 6 GitHub stars. It functions as a relatively new or niche tool, meaning it has not yet undergone the extensive peer review and real-world testing that larger open-source projects benefit from.
Verdict
Not recommended for production use due to active shell execution risks, hardcoded credentials, and a lack of community review.
UX 🤝 DEV, MCP: Standardizing UX Design System to Developer Handoff. Deterministic UI context for frontend development

Design System MCP Server
A single-instance Model Context Protocol server that gives AI coding agents authoritative design-system context before they generate UI.
It indexes a design-system Git repository containing tokens, principles, patterns, voice/tone guidance, prompt templates, and validation rules. MCP-compatible IDEs, editors, and internal agents can then ask questions like:
- Which design tokens should I use for this button?
- What confirmation-dialog pattern exists?
- What voice and tone should this empty state use?
- Does this generated UI contain raw hex colors or other rule violations?
Why This Exists
AI coding agents often generate UI without knowing your design system. They hard-code colors, invent spacing, miss patterns, and write off-voice copy. This server gives those agents a first-class, current, machine-readable source of truth.
Real Output Examples
These are generated trial pages from real token and handoff sources, not marketing mockups.
| Example | Source compatibility proven |
|---|---|
examples/bmw-m-real-page |
Community Markdown / getdesign.md-style design-system handoff |
examples/material-3-token-page |
Material-style tokens.json export |
examples/dtcg-token-alias-page |
DTCG whole-token alias .@ references |
examples/token-set-context-page |
Token Studio token sets with slash-containing names and context-local aliases |
Community Markdown / getdesign handoff trial

Token Studio contextual token-set trial

Material 3 token export trial

Current Status
Implemented:
- Local source mode from a checked-out design-system repo
- Git source mode with clone/pull refresh
- stdio transport for local IDE use
- Streamable HTTP transport for hosted use
- In-memory bundle and MiniSearch index
- Style Dictionary token loading
- Community Markdown /
getdesign.mdtoken loading for Markdown-only or hybrid handoff repos - Token Studio export compatibility, including contextual token-set references
- DTCG whole-token alias compatibility for trailing
.@references - Markdown and MDX content loading
- Prompt template loading
- JSON regex validation rules
- AST-backed JSX prop-value validation rules
- Component metadata ingestion from
components/*/component.json - TypeScript component API parser for
*Propsinterfaces and type literals - Storybook CSF story parser for canonical examples, variants, controls, and play-function interaction notes
- Canonical usage examples, constraints, and prop metadata
- Composition recommendation and composition/prop validation
- Deterministic decision explanations, recommendation provenance, violation provenance, and repair payloads where a single safe edit is known
- Built-in semantic token, accessibility, copy/voice, deprecated token, and deprecated component checks
- Optional HTTP API-key auth
- Health, readiness, version, and admin refresh endpoints
- MCP prompts registered from the loaded source repo (
prompts/*.prompt.md) - MCP resources for
design://manifest,design://schema,design://entity/{id}, plus per-type templatesdesign://principle/{id},design://pattern/{id},design://component/{id},design://prompt/{name} - Operator runbook (
docs/runbook.md), client setup guide (docs/client-setup.md), sample Fly + Kubernetes deployment manifests underdeploy/ - Performance baseline gates in CI (
tests/integration/perf-baseline.test.ts) - CI-friendly validation CLI (
pnpm validate -- --source <design-system-repo> <file...>) with JSON/SARIF output, composition-plan validation, and nonzero exit on error violations - Machine-readable workflow contract at
design://workflowfor design-system-first agent harnesses
Design Principles
This project intentionally stays small.
- Single Node.js process
- No Redis
- No database
- No object store
- No bundle publishing pipeline
- No multi-instance coordination
- Source of truth is the design-system Git repo
- Hot state is an in-memory bundle rebuilt on startup and refresh
If you need horizontal scaling, persistent user state, OAuth, or external search, treat that as a separate future proposal rather than quietly adding it here.
Architecture
Design-system Git repo
tokens/*.tokens.json
docs/principles/*.md
docs/patterns/*.md
docs/conventions/*.md
docs/voice-and-tone.md
components/
Button/
component.json
Button.tsx
Button.stories.tsx
prompts/*.prompt.md
rules/*.json
manifest.json
|
| clone/pull or local path
v
Single Node.js MCP server
Style Dictionary token resolution
Markdown/frontmatter parsing
JSON rule loading
MiniSearch index
In-memory bundle
|
| stdio or Streamable HTTP
v
AI coding agents
Prerequisites
- Node.js 22.0.0 or newer (LTS recommended; matches
package.jsonengines.node) - pnpm 9.0.0 or newer (
engines.pnpm) - git 2.5+, if using
DS_MCP_SOURCE_MODE=git(modern distros all qualify; we rely on--branch/--single-branch/--depth 1)
Recommended:
corepack enable
corepack prepare [email protected] --activate
In this workspace, Homebrew pnpm is known to work:
PATH=/opt/homebrew/bin:$PATH pnpm test
Install
pnpm install
pnpm build
Design-System Source Repo Format
The server reads a separate design-system content repo. A minimal source repo looks like this:
design-system/
manifest.json
getdesign.md
tokens/
core.tokens.json
semantic.tokens.json
docs/
principles/
clarity.md
patterns/
confirmation-dialog.md
conventions/
forms.mdx
voice-and-tone.md
components/
Button/
component.json
Button.tsx
Button.stories.tsx
prompts/
build_with_design_system.prompt.md
rules/
no-hex-colors.json
manifest.json
The manifest declares content types and relations. New content types belong here, not as new MCP tools.
{
"schemaVersion": "1.0.0",
"schema": {
"types": {
"token": {
"description": "Design token",
"searchable": ["name", "summary", "tags", "$type"]
},
"principle": {
"description": "Design principle",
"searchable": ["title", "summary", "body", "tags"]
},
"pattern": {
"description": "Reusable UI pattern",
"searchable": ["title", "summary", "body", "tags"]
}
},
"relations": {
"follows_principle": { "from": "pattern", "to": "principle" }
}
}
}
Tokens
Tokens use DTCG-style JSON and are resolved through Style Dictionary.
{
"color": {
"blue": {
"500": {
"$value": "#2563EB",
"$type": "color",
"$description": "Brand blue 500"
}
},
"action": {
"primary": {
"$value": "{color.blue.500}",
"$type": "color",
"$description": "Primary action color"
}
}
}
}
Community Markdown can also define tokens in YAML frontmatter. Use tokens: for full DTCG-shaped token trees, or use top-level community sections when the design system is authored as a single Markdown file: colors, spacing, rounded, radius, radii, typography, and components. The server normalizes these sections to DTCG-shaped input, then feeds the result through Style Dictionary with any tokens/*.tokens.json files. This supports Markdown-only repos and hybrid token+Markdown repos while keeping resolve_token, validate_ui, and validate_composition deterministic.
---
tokens:
color:
brand:
primary:
value: "#2563EB"
type: color
description: Primary brand action.
primaryHover:
value: "{color.brand.primary}"
type: color
---
# Design System
Token tables in Markdown prose are searchable guidance only. For machine-readable token resolution, put token data in Markdown frontmatter tokens: or in tokens/*.tokens.json.
---
colors:
canvas: "#000000"
on-dark: "#ffffff"
spacing:
section: 96px
rounded:
none: 0px
typography:
display-xl:
fontFamily: "BMWTypeNextLatin, sans-serif"
fontSize: 80px
components:
button-primary:
backgroundColor: "{colors.canvas}"
textColor: "{colors.on-dark}"
---
# Community Design System
For Markdown-only repositories that intentionally provide tokens plus prose but not full enterprise component/pattern metadata, call inspect_coverage with profile: "community". The default enterprise profile still treats missing required entity types as errors.
Tokens Studio exports are also supported when saved under tokens/*.tokens.json. If a file contains token-set metadata and unqualified references such as {color.primary.40}, the loader rewrites those references before Style Dictionary resolves them. When the current token set owns the target, that local target wins; for example, light/color.color.action.disabled can resolve {color.disabled} to {light/color.color.disabled} while dark/color.color.action.disabled resolves the same reference to {dark/color.color.disabled}. If the current token set does not own the target, the loader falls back to the single token set that owns it globally, for example {global.color.primary.40}. Ambiguous targets that cannot be resolved by either rule remain Style Dictionary errors. The server does not replace Style Dictionary resolution; this is a compatibility shim for common Tokens Studio exports.
CSS platform output encodes non-alphanumeric token-path characters into valid, collision-resistant custom-property names. A token path like light/color.color.action.primary.disabled is returned as var(--light_u002f_color-color-action-primary-disabled), and validate_ui checks that same encoded name. This keeps slash-containing token sets compatible with generated CSS while preserving the original token entity id.
DTCG whole-token aliases that include a trailing .@ marker are normalized when the target token exists. For example, {composite.border.thin.@} is passed to Style Dictionary as {composite.border.thin}. Missing targets are not guessed; they remain Style Dictionary reference errors.
Token Source Compatibility
| Source style | Supported | Notes |
|---|---|---|
DTCG JSON in tokens/*.tokens.json |
yes | Resolved through Style Dictionary |
| Token Studio JSON exports | yes | Supports token-set order, contextual references, and slash-containing token-set names |
DTCG whole-token aliases with .@ |
yes | Normalized only when the target token exists |
Markdown frontmatter tokens: |
yes | Full DTCG-shaped token trees |
| Markdown community sections | yes | colors, spacing, rounded, radius, radii, typography, and components |
| Markdown prose token tables | searchable only | Good for guidance, not deterministic token resolution |
Token-only sources can enforce deterministic token use and catch raw values, unknown CSS variables, deprecated tokens, accessibility issues, and copy issues. Full enterprise handoff still needs component metadata, pattern contracts, voice rules, and conventions beside the tokens.
Markdown Docs
Docs use YAML frontmatter plus Markdown or MDX body:
---
id: principle:clarity
type: principle
title: Clarity
summary: Be clear, not clever.
tags: [principle, accessibility]
---
# Clarity
Use plain language and obvious affordances.
Pattern docs can also include a machine-checkable contract in frontmatter. validate_composition enforces this before code generation.
MDX files are supported in docs/principles, docs/patterns, and docs/conventions. The loader keeps frontmatter and prose searchable while stripping imports, exports, and component-only JSX from the indexed body. It also extracts common handoff structure into entity.data.structured so agents do not need to parse prose themselves:
<DoDont doText="..." dontText="..." />pairs becomestructured.doandstructured.dont.## Do,## Do not,## Accessibility, and## Migrationlist sections become stable arrays.## PropsMarkdown tables becomestructured.propTableswith normalized prop rows.
Community-published root docs are also supported for UX-to-dev handoff. Root files named getdesign.md, design-system.md, design.md, styleguide.md, or guidelines.md are loaded as convention entities by default; root Markdown/MDX files with frontmatter id, type, or tokens are loaded too. This makes public/community formats searchable without adding content-specific MCP tools.
Docs and metadata may also reference entity ids directly, such as component:button or token:color.action.primary. The bundle infers deterministic references relations from those explicit ids, so get_related can walk the graph even when frontmatter did not include a manual related entry.
contract:
requiredComponents:
- component:button
requiredTokens:
- token:color.action.danger
requiredPrinciples:
- principle:clarity
componentOrder:
- component:card
- component:button
propRequirements:
- component: component:button
prop: variant
equals: danger
severity: error
message: Confirmation dialog confirm action must use the danger button variant.
parentChildRules:
- parent: component:card
child: component:button
relationship: required
severity: error
message: Confirmation action must be nested inside the dialog container.
platformRequirements:
- platform: web
framework: react
requiredComponents:
- component:card
forbiddenComponents:
- component:button-group
requiredTokens:
- token:color.surface.default
slots:
- name: confirm-action
required: true
component: component:button
constraints:
- id: confirmation-specific-copy
severity: warning
message: Confirmation copy must name the object and irreversible action.
Prompt Templates
Prompt files live under prompts/*.prompt.md:
---
name: build_with_design_system
description: Build UI using this design system
arguments:
- name: component_type
required: true
---
Build a {{component_type}} using the design system.
Component Metadata
Component metadata lives in components/<ComponentName>/component.json. This gives agents stable imports, prop contracts, canonical examples, constraints, and relationships without requiring the MCP server to generate application code.
When TypeScript source files are present beside component.json, the loader also reads the first matching *Props interface or type literal, preferring <ComponentName>Props. Extracted props include names, types, required flags, string-union values, JSDoc descriptions, @default, @deprecated, replacement hints, and simple controlled-state hints. Extracted props are merged into the metadata. Hand-authored component.json values win when both sources define the same prop.
When Storybook CSF files such as Card.stories.tsx are present, object stories with literal args are converted into additional usage examples. The parser also carries literal argTypes.options as controls and stores play functions as interaction notes. This keeps get_usage aligned with existing component examples without executing Storybook.
{
"id": "component:button",
"type": "component",
"name": "Button",
"summary": "Action trigger for primary, secondary, and destructive user actions.",
"package": "@acme/ui",
"importPath": "@acme/ui/button",
"dependencies": [
{
"package": "@acme/ui",
"version": "^2.0.0",
"type": "runtime",
"reason": "Provides the Button component implementation."
}
],
"importGuidance": {
"named": ["Button"],
"sideEffects": [],
"notes": ["Import Button from @acme/ui/button; do not deep-import internal files."]
},
"status": "stable",
"replacedBy": [],
"tags": ["action", "form"],
"props": [
{
"name": "variant",
"type": "\"primary\" | \"secondary\" | \"danger\"",
"required": true,
"values": ["primary", "secondary", "danger"],
"description": "Visual intent. Use danger only for destructive actions."
}
],
"examples": [
{
"name": "Destructive confirm action",
"language": "tsx",
"code": "import { Button } from \"@acme/ui/button\";\n\n<Button variant=\"danger\">Delete project</Button>"
}
],
"constraints": [
{
"id": "button-specific-label",
"severity": "error",
"message": "Button labels must name the action and object."
}
],
"tokens": ["token:color.action.primary"],
"principles": ["principle:clarity"],
"patterns": ["pattern:confirmation-dialog"],
"related": []
}
Deprecated components can declare migration chains:
{
"id": "component:legacy-button",
"status": "deprecated",
"replacedBy": ["component:button"],
"migration": {
"steps": [
"Replace LegacyButton imports with Button imports.",
"Map intent=\"danger\" to variant=\"danger\"."
],
"examples": [
{
"name": "LegacyButton to Button",
"language": "tsx",
"code": "<Button variant=\"danger\">Delete project</Button>"
}
]
}
}
validate_composition treats deprecated components as error-severity legacy usage and suggests replacement component ids when declared. inspect_coverage reports stale replacedBy targets.
Example source-enriched props:
export interface CardProps {
/** Short heading shown at the top of the card. */
title: string;
/** Visual tone for the card container. */
tone?: "neutral" | "accent" | "danger";
}
Validation Rules
Rules live under rules/*.json. Source repos can define regex detectors for simple text checks and AST-backed JSX prop value detectors for component API constraints.
{
"id": "no-hex-colors",
"description": "Raw hex colors must use design tokens",
"severity": "error",
"appliesTo": ["tsx", "jsx", "ts", "js", "css"],
"detector": {
"type": "regex",
"pattern": "#[0-9a-fA-F]{3,8}\\b",
"message": "Raw hex color {match} - use a color token instead"
}
}
Invalid JSON, schema-invalid rules, duplicate rule IDs, invalid regex patterns, and invalid regex flags are skipped with structured warnings.
{
"id": "no-button-ghost-variant",
"description": "Button variant must be one of the design-system variants.",
"severity": "error",
"appliesTo": ["tsx", "jsx"],
"detector": {
"type": "jsx-prop-value",
"component": "Button",
"prop": "variant",
"disallow": ["ghost"],
"message": "Button variant '{value}' is not in the design system."
}
}
Configuration
All configuration is read from environment variables and validated at boot.
| Variable | Default | Required | Description |
|---|---|---|---|
DS_MCP_MODE |
http |
no | stdio or http |
DS_MCP_SOURCE_MODE |
git |
no | local or git |
DS_MCP_SOURCE_PATH |
none | when local | Local design-system checkout |
DS_MCP_SOURCE_URL |
none | when git | HTTPS URL for the design-system repo |
DS_MCP_SOURCE_BRANCH |
main |
no | Branch to track |
DS_MCP_CACHE_DIR |
~/.cache/ds-mcp |
no | Git clone cache directory |
DS_MCP_REFRESH_INTERVAL_SEC |
300 |
no | Background refresh interval, minimum 30 |
PORT |
3000 |
no | HTTP listen port |
LOG_LEVEL |
info |
no | trace, debug, info, warn, error, or fatal |
DS_MCP_AUTH_MODE |
none |
no | none or apikey |
DS_MCP_API_KEYS |
none | when apikey | Comma-separated SHA-256 hex digests |
DS_MCP_ADMIN_TOKEN |
none | for admin refresh | Bearer token for /admin/refresh |
GIT_AUTH_TOKEN |
none | no | Token used for private HTTPS Git clone/pull |
See .env.example.
Run Locally With stdio
Use stdio mode for IDEs that spawn local MCP servers.
pnpm build
DS_MCP_MODE=stdio \
DS_MCP_SOURCE_MODE=local \
DS_MCP_SOURCE_PATH=/absolute/path/to/design-system \
node dist/index.js
Example MCP client command:
{
"mcpServers": {
"design-system": {
"command": "node",
"args": ["/absolute/path/to/design-system-mcp/dist/index.js"],
"env": {
"DS_MCP_MODE": "stdio",
"DS_MCP_SOURCE_MODE": "local",
"DS_MCP_SOURCE_PATH": "/absolute/path/to/design-system"
}
}
}
}
Run Locally With HTTP
HTTP mode exposes Streamable HTTP MCP at /mcp.
DS_MCP_MODE=http \
DS_MCP_SOURCE_MODE=local \
DS_MCP_SOURCE_PATH=/absolute/path/to/design-system \
PORT=3000 \
pnpm dev
Useful endpoints:
curl http://localhost:3000/healthz
curl http://localhost:3000/readyz
curl http://localhost:3000/version
Run From a Git Source
DS_MCP_MODE=http \
DS_MCP_SOURCE_MODE=git \
DS_MCP_SOURCE_URL=https://github.com/your-org/design-system.git \
DS_MCP_SOURCE_BRANCH=main \
PORT=3000 \
pnpm dev
The server clones the source repo into DS_MCP_CACHE_DIR, pulls periodically, and atomically swaps in a rebuilt bundle when content changes.
For private HTTPS repositories, set GIT_AUTH_TOKEN. The token is injected into Git operations and redacted from logs.
API Key Auth
HTTP auth is optional. When enabled, clients must send:
Authorization: Bearer <api-key>
Create a high-entropy key:
openssl rand -base64 32
Store only its SHA-256 hex digest in DS_MCP_API_KEYS:
printf '%s' 'your-api-key-here' | shasum -a 256 | awk '{print $1}'
Run with auth:
DS_MCP_MODE=http \
DS_MCP_AUTH_MODE=apikey \
DS_MCP_API_KEYS=<sha256-hex-digest> \
DS_MCP_SOURCE_MODE=local \
DS_MCP_SOURCE_PATH=/absolute/path/to/design-system \
pnpm dev
Admin Refresh
Set DS_MCP_ADMIN_TOKEN to enable manual refresh:
curl -X POST http://localhost:3000/admin/refresh \
-H "Authorization: Bearer $DS_MCP_ADMIN_TOKEN"
During graceful drain, /readyz, /mcp, and /admin/refresh return 503. /healthz remains 200 while the process is alive.
MCP Tools
The server exposes generic verbs:
| Tool | Purpose |
|---|---|
describe_schema |
Show content types, relations, and bundle metadata |
search_design_system |
Search tokens, docs, patterns, voice, and prompts |
get_entity |
Fetch one entity by ID |
list_entities |
Page through entities by type or tag |
get_related |
Fetch related entities |
resolve_token |
Find tokens and return platform-formatted values |
validate_ui |
Validate generated code against source-repo rules |
get_usage |
Return canonical imports, examples, props, and constraints |
recommend_composition |
Return an implementation brief for a UI intent |
validate_composition |
Validate planned components, props, patterns, and tokens before coding |
inspect_coverage |
Report content coverage gaps before deterministic generation |
explain_decision |
Explain a chosen entity with deterministic source, relation, and constraint evidence |
Design-System-First Handoff Flow
For best UX-to-dev consistency, agents and CI should follow this sequence:
- Read
design://workflowor calldescribe_schema. - Call
inspect_coverageto understand whether the source is enterprise-complete or token-only/community-grade. - Call
recommend_compositionwith the UI intent. - Call
explain_decisionfor selected components, patterns, or tokens when the harness needs auditable reasoning. - Call
get_usagefor selected components andresolve_tokenfor every concrete token value. - Call
validate_compositionbefore generating code. - Generate code.
- Call
validate_uiand apply deterministicrepair/replaceWithedits first. - In CI or final harness mode, run
pnpm validate -- --mode final_check --composition composition.json <file...>.
The server publishes the workflow contract at design://workflow; hard blocking is enforced by the validation CLI and by any client harness that honors that resource.
Example validate_ui request:
{
"code": "const color = '#2563EB';",
"language": "tsx",
"rules": ["no-hex-colors"]
}
validate_ui also runs built-in semantic token, accessibility, and copy/voice checks:
no-raw-length-valuesblocks rawpx,rem, andemvalues.no-raw-color-functionsblocks rawrgb(),rgba(),hsl(), andhsla()values.no-unknown-css-varsblocks token-like CSS variables that do not resolve to known design tokens.prefer-semantic-tokenswarns when app code uses primitive tokens instead of semantic aliases.no-deprecated-tokensblocks deprecated token aliases and suggests replacements when declared.a11y-img-altrequires images to have alt text or another accessible name.a11y-button-namerequires buttons to have visible text or an accessible name.a11y-link-namerequires links to have visible text or an accessible name.a11y-form-control-labelrequires inputs, selects, and textareas to have labels or accessible names.a11y-no-positive-tabindexblocks positive tab order overrides.a11y-no-autofocuswarns when markup uses autofocus.a11y-valid-aria-roleblocks invalid ARIA role names.copy-no-blameblocks copy that blames the user.copy-no-hypewarns on hype, alarmism, and exclamation marks.copy-no-vague-actionswarns on vague action labels such as "Submit" or "Process".copy-no-destructive-hedgingwarns when destructive copy uses hedging language.
When a violation has one deterministic edit, the response includes replaceWith and a structured repair payload:
{
"ruleId": "no-deprecated-tokens",
"match": "var(--color-action-legacyPrimary)",
"replaceWith": "var(--color-action-primary)",
"repair": {
"operation": "replace",
"before": "var(--color-action-legacyPrimary)",
"after": "var(--color-action-primary)"
}
}
Rules that require product judgment still return human-readable suggestion text without an auto-fix.
Example response:
{
"ok": false,
"violations": [
{
"ruleId": "no-hex-colors",
"severity": "error",
"message": "Raw hex color #2563EB - use a color token instead",
"line": 1,
"column": 16,
"match": "#2563EB",
"provenance": {
"ruleSource": "source-repo",
"rulePath": "rules/no-hex-colors.json"
}
}
],
"ranRules": ["no-hex-colors"],
"bundleVersion": "nogit-2026-05-01T16:40:00.000Z"
}
Docker
Build:
docker build -t ds-mcp-server .
Run against a local source checkout:
docker run --rm -p 3000:3000 \
-e DS_MCP_MODE=http \
-e DS_MCP_SOURCE_MODE=local \
-e DS_MCP_SOURCE_PATH=/design-system \
-v /absolute/path/to/design-system:/design-system:ro \
ds-mcp-server
Use docker-compose.yml as a starting point for local hosted-mode testing.
Development
pnpm install
pnpm lint
pnpm typecheck
pnpm test
pnpm build
Run only unit or integration tests:
pnpm test:unit
pnpm test:integration
Validate changed UI files against a local design-system source repo in CI:
pnpm validate -- --source ./path/to/design-system src/App.tsx
pnpm validate -- --source ./path/to/design-system --format sarif src/App.tsx > ds-results.sarif
pnpm validate -- --source ./path/to/design-system --composition composition.json
pnpm validate -- --source ./path/to/design-system --mode final_check --composition composition.json src/App.tsx
The command prints JSON or SARIF and exits 1 if any error-severity validate_ui / validate_composition violation is found. In --mode final_check, it also exits 1 when required harness evidence is missing, such as running UI validation without a composition plan.
This project follows test-first development for non-trivial changes. Add focused tests first, implement the smallest safe change, then run the relevant verification before committing.
Repository Layout
src/
auth/ API-key validation
bundle/ Manifest, token, markdown, prompt, and rule loading
observability/ Pino logger
search/ MiniSearch index
server/ MCP server wiring and shared types
source/ Local and Git source adapters
tools/ MCP tool handlers
transport/ stdio and Streamable HTTP transports
util/ Small shared utilities
validation/ validate_ui detector helpers
tests/
fixtures/ Sample design-system repo
integration/ End-to-end tool/transport tests
unit/ Unit tests
Contributing
Before opening a pull request:
- Keep the single-instance architecture intact.
- Do not add Redis, a database, object storage, queues, or multi-instance coordination.
- Add or update tests before changing behavior.
- Run:
pnpm lint
pnpm typecheck
pnpm test
pnpm build
Security
- Do not commit
.envfiles, deploy keys, API keys, or admin tokens. - Use high-entropy API keys and store only SHA-256 hex digests.
- Logs redact common secret/header fields.
- The MCP surface is read-only. Authoring stays in the design-system Git repo.
License
MIT. See LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found