{"_id":"@avcs/weave-design-system-mcp","_rev":"5-2e7ee5201eca7e67e6cc91b06adbba92","name":"@avcs/weave-design-system-mcp","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@avcs/weave-design-system-mcp","version":"1.0.0","keywords":["mcp","model-context-protocol","design-system","design-tokens","vanilla-extract","tailwind","storybook","ai-agents"],"license":"MIT","_id":"@avcs/weave-design-system-mcp@1.0.0","maintainers":[{"name":"avcs","email":"avcs06@gmail.com"}],"homepage":"https://github.com/avcs06/weave-design-system-mcp#readme","bugs":{"url":"https://github.com/avcs06/weave-design-system-mcp/issues"},"bin":{"weave-design-system-mcp":"dist/mcp/stdio.js"},"dist":{"shasum":"cb9a124a9070e31b9988f72d88ecc33a25b86bce","tarball":"https://registry.npmjs.org/@avcs/weave-design-system-mcp/-/weave-design-system-mcp-1.0.0.tgz","fileCount":87,"integrity":"sha512-kkROgCDxMmMtYrFbDGexMAplYATnOY2Gt/fgRKOOYLFt5KaRwUub2phOqtpd0u7a6Mjabhwxy/5V/JPN9cspZQ==","signatures":[{"sig":"MEUCIBF4EDfN2+2hvOL4EA88DRFAICPmFCPLx9E3DPYjPyIzAiEAv2weonmqwHXT6A/GE/6Zn8p4+UW0CqrtUihD4diAsTI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":220633},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":"^22.18.0 || >=24.11.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c933b52c2a9d5bfafbc915c737c3e633576b9ec1","scripts":{"dev":"tsx watch src/mcp/stdio.ts","test":"vitest run","build":"tsc -p tsconfig.json","start":"node dist/mcp/stdio.js","format":"prettier --write \"src/**/*.ts\" \"*.{json,md}\"","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.ts\" \"*.{json,md}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"avcs","email":"avcs06@gmail.com"},"repository":{"url":"git+https://github.com/avcs06/weave-design-system-mcp.git","type":"git"},"_npmVersion":"11.4.2","description":"Generic MCP server that makes any design system (tokens + components) queryable by coding agents, and agent-generated UI checkable against it.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"zod":"^4.5.4","typescript":"~5.9.3","@babel/parser":"^8.0.4","@babel/traverse":"^8.0.4","react-docgen-typescript":"^2.4.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.13","react":"^19.2.8","vitest":"^3.2.4","prettier":"^3.4.2","@types/node":"^24.13.3","@types/react":"^19.2.18"},"_npmOperationalInternal":{"tmp":"tmp/weave-design-system-mcp_1.0.0_1788679168309_0.5237909236606797","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@avcs/weave-design-system-mcp","version":"1.0.1","keywords":["mcp","model-context-protocol","design-system","design-tokens","vanilla-extract","tailwind","storybook","ai-agents"],"license":"MIT","_id":"@avcs/weave-design-system-mcp@1.0.1","maintainers":[{"name":"avcs","email":"avcs06@gmail.com"}],"homepage":"https://github.com/avcs06/weave-design-system-mcp#readme","bugs":{"url":"https://github.com/avcs06/weave-design-system-mcp/issues"},"bin":{"weave-design-system-mcp":"dist/mcp/stdio.js"},"dist":{"shasum":"b4b8b9d966f15b3f228fa49a2a5547b3b2b1a236","tarball":"https://registry.npmjs.org/@avcs/weave-design-system-mcp/-/weave-design-system-mcp-1.0.1.tgz","fileCount":87,"integrity":"sha512-ZXmgkUvrOXte7yuuQzZekSmOQ2dDd2rMG2SwYWzOY2FYLs1407fSGlDg9SGyRIRGkCJZUGPMboVt/oLvHOrnPQ==","signatures":[{"sig":"MEQCIEwWlDz+dDQJbg6N1pULIZPqbFlCc9PgfN5AOX1a3zJ2AiBTJycT2HhGIyWRRHtwAGxOd/fb81iDJeh6rEW5si0uDQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":220631},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":"^22.18.0 || >=24.11.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b0cf579f09f308e2090ef1681263f9400e9dd6da","scripts":{"dev":"tsx watch src/mcp/stdio.ts","test":"vitest run","build":"tsc -p tsconfig.json","start":"node dist/mcp/stdio.js","format":"prettier --write \"src/**/*.ts\" \"*.{json,md}\"","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.ts\" \"*.{json,md}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"avcs","email":"avcs06@gmail.com"},"repository":{"url":"git+https://github.com/avcs06/weave-design-system-mcp.git","type":"git"},"_npmVersion":"11.4.2","description":"Generic MCP server that makes any design system (tokens + components) queryable by coding agents, and agent-generated UI checkable against it.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"zod":"^4.5.4","typescript":"~5.9.3","@babel/parser":"^8.0.4","@babel/traverse":"^8.0.4","react-docgen-typescript":"^2.4.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.13","react":"^19.2.8","vitest":"^3.2.4","prettier":"^3.4.2","@types/node":"^24.13.3","@types/react":"^19.2.18"},"_npmOperationalInternal":{"tmp":"tmp/weave-design-system-mcp_1.0.1_1788679554008_0.056621809457823025","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@avcs/weave-design-system-mcp","version":"1.0.2","keywords":["mcp","model-context-protocol","design-system","design-tokens","vanilla-extract","tailwind","storybook","ai-agents"],"license":"MIT","_id":"@avcs/weave-design-system-mcp@1.0.2","maintainers":[{"name":"avcs","email":"avcs06@gmail.com"}],"homepage":"https://github.com/avcs06/weave-design-system-mcp#readme","bugs":{"url":"https://github.com/avcs06/weave-design-system-mcp/issues"},"bin":{"weave-design-system-mcp":"dist/mcp/stdio.js"},"dist":{"shasum":"52530d830ce6e9fe20a717c63380c9e37cf8124d","tarball":"https://registry.npmjs.org/@avcs/weave-design-system-mcp/-/weave-design-system-mcp-1.0.2.tgz","fileCount":87,"integrity":"sha512-uEN1kqBOPuqI7CutHmFJN4jYzOxzzsmE2HDR3DwNoYIDQOzbBMwnEAeKSdSOrLHSl1lNuYNbwMil1/1BwttUeA==","signatures":[{"sig":"MEQCICx/OOUtFcEwCCfk3wwuMaH91Xnq0hdT8ZMs7c8Fp+MAAiAAjVWqHSXENDtGfkw0Ge3TKM/fEyDUrwRkLPkzUlct3w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":207639},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":"^22.18.0 || >=24.11.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"9381e46509cda12475714447c5e2ecb736ba1350","scripts":{"dev":"tsx watch src/mcp/stdio.ts","test":"vitest run","build":"tsc -p tsconfig.json","start":"node dist/mcp/stdio.js","format":"prettier --write \"src/**/*.ts\" \"*.{json,md}\"","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.ts\" \"*.{json,md}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"avcs","email":"avcs06@gmail.com"},"repository":{"url":"git+https://github.com/avcs06/weave-design-system-mcp.git","type":"git"},"_npmVersion":"11.4.2","description":"Generic MCP server that makes any design system (tokens + components) queryable by coding agents, and agent-generated UI checkable against it.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"zod":"^4.5.4","typescript":"~5.9.3","@babel/parser":"^8.0.4","@babel/traverse":"^8.0.4","react-docgen-typescript":"^2.4.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.13","react":"^19.2.8","vitest":"^3.2.4","prettier":"^3.4.2","@types/node":"^24.13.3","@types/react":"^19.2.18"},"_npmOperationalInternal":{"tmp":"tmp/weave-design-system-mcp_1.0.2_1788683824178_0.6072866674969395","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Published with stale dist/mcp/sampling.js left over from a removed feature; use 1.0.3."},"1.0.3":{"name":"@avcs/weave-design-system-mcp","version":"1.0.3","keywords":["mcp","model-context-protocol","design-system","design-tokens","vanilla-extract","tailwind","storybook","ai-agents"],"license":"MIT","_id":"@avcs/weave-design-system-mcp@1.0.3","maintainers":[{"name":"avcs","email":"avcs06@gmail.com"}],"homepage":"https://github.com/avcs06/weave-design-system-mcp#readme","bugs":{"url":"https://github.com/avcs06/weave-design-system-mcp/issues"},"bin":{"weave-design-system-mcp":"dist/mcp/stdio.js"},"dist":{"shasum":"85663b111078a17b23df7845b9ae020fae3dd7b0","tarball":"https://registry.npmjs.org/@avcs/weave-design-system-mcp/-/weave-design-system-mcp-1.0.3.tgz","fileCount":83,"integrity":"sha512-jKMI9eIMRASVVm8XQevajG6d+uI26OyXPV0RqF7aA4J+jRfK9UesrtTfVJWXpRek/nBlMEK2ICSGUu3r1cwXuw==","signatures":[{"sig":"MEUCIQDaEXZVNjE/NxJdh9fT1FnKpFSzJSGGfIQ4xyF98ceWrgIgUiiPfp9QIZVIjPdGpU+R4E+q1xUvZVt7X21oB3opfQs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201229},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":"^22.18.0 || >=24.11.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"19e48760bd879779039628918d47e4f9b6ef4897","scripts":{"dev":"tsx watch src/mcp/stdio.ts","test":"vitest run","build":"rm -rf dist && tsc -p tsconfig.json","start":"node dist/mcp/stdio.js","format":"prettier --write \"src/**/*.ts\" \"*.{json,md}\"","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.ts\" \"*.{json,md}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"avcs","email":"avcs06@gmail.com"},"repository":{"url":"git+https://github.com/avcs06/weave-design-system-mcp.git","type":"git"},"_npmVersion":"11.4.2","description":"Generic MCP server that makes any design system (tokens + components) queryable by coding agents, and agent-generated UI checkable against it.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"zod":"^4.5.4","typescript":"~5.9.3","@babel/parser":"^8.0.4","@babel/traverse":"^8.0.4","react-docgen-typescript":"^2.4.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.13","react":"^19.2.8","vitest":"^3.2.4","prettier":"^3.4.2","@types/node":"^24.13.3","@types/react":"^19.2.18"},"_npmOperationalInternal":{"tmp":"tmp/weave-design-system-mcp_1.0.3_1788684043537_0.2097665740466299","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-09-06T07:19:28.123Z","modified":"2026-09-06T08:40:51.653Z","1.0.0":"2026-09-06T07:19:28.434Z","1.0.1":"2026-09-06T07:25:54.149Z","1.0.2":"2026-09-06T08:37:04.314Z","1.0.3":"2026-09-06T08:40:43.662Z"},"bugs":{"url":"https://github.com/avcs06/weave-design-system-mcp/issues"},"license":"MIT","homepage":"https://github.com/avcs06/weave-design-system-mcp#readme","keywords":["mcp","model-context-protocol","design-system","design-tokens","vanilla-extract","tailwind","storybook","ai-agents"],"repository":{"url":"git+https://github.com/avcs06/weave-design-system-mcp.git","type":"git"},"description":"Generic MCP server that makes any design system (tokens + components) queryable by coding agents, and agent-generated UI checkable against it.","maintainers":[{"name":"avcs","email":"avcs06@gmail.com"}],"readme":"# weave-design-system-mcp\n\n[![CI](https://github.com/avcs06/weave-design-system-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/avcs06/weave-design-system-mcp/actions/workflows/ci.yml)\n\nCoding agents generate UI that drifts from the design system, because the system lives in docs,\nStorybook, and reviewer heads — none of that is queryable at generation time, and nothing checks\nthe output afterward. This is an [MCP](https://modelcontextprotocol.io) server that makes a design\nsystem queryable by an agent before it writes code, and its output checkable against that same\nsystem afterward. Nothing about a specific design system, token set, or component library is\nhardcoded — everything comes from a `designsystem.config.json` in whatever workspace you point\nit at.\n\nYour workspace — the codebase holding the design system — keeps its own\n`designsystem.config.json`, and you point the server at that folder when you register it.\n\n## Worked example: before / after\n\nThis runs against the public example design system bundled in `examples/`, so you can see it work\nbefore setting up your own.\n\n[`examples/synthetic-design-system/`](examples/synthetic-design-system/) is a small, fully public\ndesign system (fictional tokens, one `Button` with stories) demonstrating the CSS-in-TS + utility\nclass split this MCP was built around — run it from inside there (`cd\nexamples/synthetic-design-system && node ../../dist/mcp/stdio.js`) to try this yourself.\n\nAn agent about to write `Button.css.ts` hardcodes a color instead of looking it up:\n\n```ts\n// before — an agent invented a hex value\nimport { style } from '@vanilla-extract/css';\nexport const bad = style({ color: '#3b5bdb' });\n```\n\n```jsonc\n// validate({ \"code\": \"...\" }) response\n{\n  \"ok\": false,\n  \"findings\": [\n    {\n      \"rule\": \"hardcoded-literal\",\n      \"severity\": \"error\",\n      \"surface\": \"vanilla-extract\",\n      \"line\": 2,\n      \"column\": 35,\n      \"message\": \"\\\"color: #3b5bdb\\\" hardcodes a color value instead of using a design token. The closest token is \\\"color.accent\\\".\",\n      \"suggestion\": \"vars.color.accent\",\n    },\n  ],\n}\n```\n\nThe agent applies the suggestion directly:\n\n```ts\n// after\nimport { style } from '@vanilla-extract/css';\nimport { vars } from '../theme.css';\nexport const good = style({ color: vars.color.accent });\n```\n\n```jsonc\n// validate(...) response\n{ \"ok\": true, \"findings\": [] }\n```\n\n## Tools\n\n| Tool                | Purpose                                                                                                                                                                                  |\n| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `list_tokens`       | List tokens, optionally filtered to one group. Call with no group first — group names vary by project (`color`, `spacing`, `iconSize`, `zIndex`, whatever the source defines).           |\n| `list_components`   | The component inventory: name, description, category, and which props are variant-like.                                                                                                  |\n| `search_tokens`     | Ranked token search across names, groups, references and values — for when you know what you want but not what this system calls it.                                                     |\n| `search_components` | Ranked component search across names, descriptions, categories and prop names — the first call to make before building any UI element from scratch.                                      |\n| `get_component`     | One component's full contract: every prop with its type and required flag, and the allowed value set for each variant-like prop. An unknown name comes back with the closest real names. |\n| `validate`          | Check a JSX/TSX snippet or a style file's content. Unparseable input comes back as a finding.                                                                                            |\n\n### What `validate` checks\n\nEach finding names the exact constraint broken and, where derivable, the exact fix.\n\n**Values that should be tokens**\n\n1. **Hardcoded literals in style-defining code** — for `vanilla-extract`, that's `style()` and\n   `styleVariants()` (from `@vanilla-extract/css`) and `recipe()` (from the separate\n   `@vanilla-extract/recipes` package), including everything nested inside `selectors`,\n   media-query and variant objects, quoted pseudo-selector keys included. In a system that splits\n   styling between a CSS-in-TS library and utility classes, this is where most real token\n   violations live.\n2. **Hardcoded literals in JSX** — an inline `style={{...}}` prop, and utility-class arbitrary\n   values (`text-[#1e1e22]`, `p-[13px]` under `tailwind`), which step outside the design system's\n   scale by construction.\n\nThe `suggestion` on these comes from a value-to-token reverse index built at load time: nearest\ncolor for a hex value, nearest numeric token for spacing, radius and the like — the fix an agent\ncan apply in one pass.\n\n**Wrong implementations**\n\n3. **Unknown variant value** — a variant-like prop set to a value outside its allowed set, with\n   the allowed set named in the message.\n4. **An invalid alternative to a design system component** — reaching for a raw `<button>`, or for\n   some other library's `MuiButton`, when the system has a `Button` of its own. A component\n   declares what it supersedes with an `@invalidAlternative` JSDoc tag, naming native elements and\n   components alike:\n\n   ```tsx\n   /**\n    * Primary interactive control for triggering an action.\n    * @invalidAlternative button, MuiButton\n    */\n   export function Button(props: ButtonProps) {\n     /* ... */\n   }\n   ```\n\n   Declarations use CSS selector syntax, so a component can name a tag _and the classes on it_ —\n   which is how a layout primitive says \"a plain div is fine, a div doing my job is not\":\n\n   | Declaration      | Matches                             |\n   | ---------------- | ----------------------------------- |\n   | `button`         | any `<button>`                      |\n   | `MuiButton`      | another library's component         |\n   | `div.flex`       | a `<div>` carrying the class `flex` |\n   | `div.flex.gap-2` | a `<div>` carrying both classes     |\n   | `.flex`          | any element carrying `flex`         |\n\n   All the classes named must be present; extras are ignored, so `div.flex` matches\n   `className=\"flex items-center\"`. The classes are plain literals you wrote — this is unrelated\n   to `classNames`, and works whether or not you configure a utility-class convention.\n\n   Any way of writing the value is read, including through a helper — `cn`, `clsx`, `classNames`,\n   `twMerge` or your own, since the name of the call is never inspected:\n\n   ```tsx\n   <div className=\"flex items-center\" />\n   <div className={cn('flex', isActive && 'gap-2')} />\n   <div className={clsx({ flex: isRow })} />   // class as key\n   <div className={`flex ${extra}`} />\n   ```\n\n   Where two declarations both match, the more specific one wins, so `div.flex` is reported over\n   a bare `div`. An invalid alternative is always an error.\n\n**Superseded implementations**\n\n5. **A deprecated usage pattern** — a usage reproducing a prop combination the component's own\n   `.stories` file marks deprecated, either by an `@deprecated` docblock or a story name saying so.\n   The finding names the story, so the reader can go see what replaced it. A warning, not an error.\n\n## Architecture\n\nThe design system model has no MCP dependency — everything under [`src/model/`](src/model/)\n(config loading, adapters, `validate`) is plain TypeScript that knows nothing about the protocol;\n[`src/mcp/`](src/mcp/) is a thin layer that registers tools, calls the model, and formats the\nresult. That split is deliberate: the model is meant to be reusable by something other than an MCP\nserver later (a CLI, a lint rule), and a tool handler containing logic beyond formatting would be\na bug rather than a feature.\n\nExactly three adapters — `tsx-adapter`, `styles-adapter`, `classname-adapter` — one per concern.\nAll three are dispatchers: they contain no library-specific code of their own, only routing to\nwhichever implementation `config.source` names, so no particular styling system or component\nformat is baked into the thing that's supposed to be generic.\n\n```\nsrc/\n  model/\n    types.ts                  DesignSystem, ComponentContract, DesignToken, Finding\n    config.ts                 Zod schema + loadConfig(cwd) -> ResolvedConfig\n    design-system.ts          createDesignSystem(config) -> DesignSystem: loads every configured\n                               token and component source, builds the reverse index, and holds\n                               the lookup/search API\n    validate.ts               parses once with Babel, calls the two \"validate\" entry points below\n    reverse-index.ts          value -> nearest-token lookup (color distance / numeric proximity)\n    flatten-object-literal.ts shared AST helper both token-reading implementations use\n    check-style-object.ts     shared property-group check every styling implementation, and the\n                               TSX adapter's inline style prop, run an object literal through\n    class-name-strings.ts     reads the classes off a JSX className, whatever expression shape\n                               it takes — knows no className convention\n    adapters/\n      styles-adapter.ts        DISPATCHER — loadTokens(config) and validateStyles(ast, system,\n                                config) each pick a branch on config.source and call into it\n      styles/\n        vanilla-extract.ts      loadTokens() (createThemeContract/createGlobalTheme) and\n                                validate() (style()/styleVariants()/recipe() calls)\n        object.ts               loadTokens() for a plain JS/JSON file\n      classname-adapter.ts      DISPATCHER — check(config, value) picks a branch on config.source\n      classnames/\n        tailwind.ts             check() for arbitrary-value brackets\n      tsx-adapter.ts            DISPATCHER for loadComponents(config), plus validateJsx(ast,\n                                system, classNamesConfig): walks JSX elements, checks variant\n                                props, invalid alternatives and story-derived patterns itself, and\n                                delegates style/className checks to its two sibling adapters\n      components/\n        react-tsx.ts            component contracts from project source files\n        npm-package.ts          component contracts from an installed package's type declarations\n        stories.ts              deprecated prop patterns from a colocated .stories file\n  mcp/\n    server.ts                  tool registration\n    stdio.ts                   entrypoint: loadConfig(workspace) -> createDesignSystem -> serveStdio\n  index.ts                     public exports\n```\n\nAdding another styling system (Sass modules, styled-components) is a new file next to\n`styles/vanilla-extract.ts` plus one branch in `styles-adapter.ts` — no concrete implementation\ngets touched to add another, and neither does `validate.ts` or `tsx-adapter.ts`, which only ever\ncall the dispatcher. Same shape for another className convention next to `classnames/tailwind.ts`,\nand for another component format next to `components/react-tsx.ts`.\n\n**Why the TSX adapter delegates instead of checking styles/classes itself.** An inline JSX\n`style={{...}}` prop needs the _exact_ same governed-property check as a style-authoring call —\nsame properties, same token groups, same reverse index — so both run through the shared\n`check-style-object.ts` rather than keeping a second copy of that logic. Utility-class checking is\nunrelated (it's regex over strings, not object literals), so it's the className adapter's own\nconcern, reached through its dispatcher. `validate.ts` itself calls exactly two things —\n`validateStyles` and `validateJsx` — because there are only two places in a file token violations\nstart from: a style-defining call, or a JSX element.\n\n**Why `styles`/`classNames` are opt-in config.** Earlier this ran the vanilla-extract and Tailwind\nchecks unconditionally, which quietly contradicted the \"nothing hardcoded\" premise by assuming\nevery project uses both. Now each check takes its config field and does nothing when it's absent,\nthe same way a token check does nothing for a group with no tokens: no signal, no finding.\n\n**Why property→group is a map, not value-matching.** Detecting a violation is structural — is this\ngoverned property set to a literal, or to a reference into the token object? — rather than based\non whether the literal happens to match some token's value. `padding: '8px'` is wrong even when\n8px equals a real token today, because it won't track that token if it changes. Value-matching is\nused only to compute `suggestion`, once a violation is already established.\n\n**Why the group list isn't fixed.** A real design system's token groups aren't knowable in advance\n(some have `shadow`/`motion`, plenty don't; some split typography into `fontSize`/`fontWeight`/\n`lineHeight` rather than one `typography` group), so a rule fires only when the configured token\nsource actually has tokens in that group.\n\n**Why `width`/`height` aren't governed properties.** They're too overloaded — an icon's size and a\ncard's layout width use the same CSS property — to map onto one token group without a high\nfalse-positive rate, so they're left unchecked.\n\n**Why token sources aren't merged by name.** If a design system splits token _shape_ (a\nvanilla-extract contract) from token _values_ (a separate JSON file), those two sources produce\nseparate token entries rather than one merged entry. Whoever writes the config decides which files\nto list; there's no cross-file name-matching to get wrong.\n\n## Setup\n\nNode `^22.18.0` or `>=24.11.0` (pinned in `.nvmrc`).\n\nThere's nothing to install or keep running — your MCP client starts the server as a subprocess and\nstops it with the session, and `npx` fetches it on first use.\n\n### 1. Describe your design system\n\nAdd `designsystem.config.json` to the root of your workspace. Paths are relative to that file:\n\n```json\n{\n  \"tokens\": [{ \"source\": \"vanilla-extract\", \"path\": \"src/styles/theme.css.ts\" }],\n  \"components\": [{ \"source\": \"react-tsx\", \"include\": [\"src/components/**/*.tsx\"] }],\n  \"styles\": { \"source\": \"vanilla-extract\" },\n  \"classNames\": { \"source\": \"tailwind\" }\n}\n```\n\nOnly `tokens` and `components` are required — see the [config reference](#config-reference) for\nevery source and its fields. Writing this by hand is optional: point your coding agent at that\nreference and ask it to write the config for the repo it's sitting in.\n\nComponents are read through the real TypeScript checker, so your workspace also needs its own\ndependencies installed for them to resolve.\n\n### 2. Register it with your client\n\nClaude Code:\n\n```bash\nclaude mcp add weave-design-system-mcp -- npx -y @avcs/weave-design-system-mcp /path/to/your-workspace\n```\n\nAny client using `mcpServers` JSON (Claude Desktop, Cursor, Windsurf):\n\n```json\n{\n  \"mcpServers\": {\n    \"weave-design-system-mcp\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@avcs/weave-design-system-mcp\", \"/absolute/path/to/your-workspace\"]\n    }\n  }\n}\n```\n\n`DESIGN_SYSTEM_PATH` works instead of the argument if you'd rather use an environment variable.\nWith neither, the server reads the folder it was started in.\n\n### 3. Confirm it found your design system\n\nIn Claude Code, `/mcp` lists the server and its six tools. Then ask something only the design\nsystem can answer — \"what spacing tokens exist?\" — and you should see it call `list_tokens`.\n\nThat's the whole setup. If the answers come back empty, a client only shows you that the tools\nexist and not what they loaded, so you can optionally start the server yourself to see the counts\nit found — it prints a summary, then waits for protocol traffic, so `Ctrl-C` out:\n\n```bash\nnpx -y @avcs/weave-design-system-mcp /path/to/your-workspace\n# weave-design-system-mcp ready on stdio — 408 tokens, 103 components\n```\n\n`0 components` almost always means the workspace's dependencies aren't installed, or `include`\ndoesn't match its layout.\n\n## Config reference\n\n`tokens` and `components` take either one source object or an array of them.\n\n| Field        | Purpose                                                                                                                                                                                                                                 |\n| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `tokens`     | Where the design tokens are. Tokens can be spread across several files or formats — list each one and they're concatenated.                                                                                                             |\n| `components` | Where the components are: your workspace's own source files, published packages, or both.                                                                                                                                               |\n| `styles`     | _Optional._ Which styling system `validate` should check style-defining code with. Omit it and no style check runs — it isn't assumed from `tokens`, since a project can read token values from one place and author styles in another. |\n| `classNames` | _Optional._ Which utility-class convention `validate` should check `className` with. Omit it and `className` isn't inspected.                                                                                                           |\n\nEach `source` names an implementation, and each implementation defines its own remaining fields\nand its own checks. The ones that ship:\n\n**Token sources** (`tokens[].source`)\n\n- `vanilla-extract` — reads `createThemeContract`/`createGlobalTheme` calls, flattening nested\n  paths to dot-separated names. A `createThemeContract` leaf declares shape without a value, so it\n  produces a token with a `reference` and no `value`.\n- `object` — reads a JSON file, or a `.ts`/`.js` module's `export const X = {...}`, and flattens it\n  the same way. Fields: `export` (which named export, if a file has more than one), `rootPath`\n  (dot-separated — navigate into a nested key before flattening, e.g. a JSON file wrapped in\n  `{ \"tokens\": {...} }`), `referenceRoot` (override the identifier printed before the dotted path;\n  defaults to the export's name, or the file's basename for JSON).\n\n**Component sources** (`components[].source`)\n\n- `react-tsx` — reads React component prop contracts through the real TypeScript type checker\n  (`react-docgen-typescript`, the same tool Storybook's autodocs use), which is what lets a variant\n  prop typed as `keyof typeof someTokenObject` resolve to its actual allowed values rather than\n  only a union written out literally. Also reads each component's colocated `.stories` file and its\n  `@invalidAlternative` JSDoc tag (see above). Fields: `include` (glob pattern(s)), `tsconfig` (path\n  to a tsconfig, needed to resolve path aliases like a monorepo's `@app/*`).\n- `npm-package` — reads an installed package's components from its type declarations, so an icon\n  library or a set of headless primitives becomes part of the queryable inventory rather than\n  something an agent has to guess at. Fields: `package` (the package name, resolved from your\n  workspace), `names` (`\"*\"` or omitted for everything it exports, or an array of\n  specific names).\n\n**Styles sources** (`styles.source`): `vanilla-extract`.\n\n**ClassNames sources** (`classNames.source`): `tailwind`.\n\nA format that isn't listed here needs a new adapter — one file plus one branch, see\n[Architecture](#architecture).\n\n## Known limitations\n\n- **A `TemplateLiteral` value is never flagged**, even a hardcoded one (e.g.\n  `` `0 0 0 3px ${theme.shadow}` ``) — it often mixes a real token reference with literal\n  structure, and resolving that fully isn't worth the false-positive risk.\n- **A computed property key** (`{ [someVar]: '#fff' }`) is checked using the _variable's name_,\n  not its runtime value — harmless unless a local variable happens to share a name with a governed\n  CSS property.\n- **The `react-tsx` component source needs your workspace's own dependencies installed**\n  (`npm install`/`pnpm install` run there). It resolves types through the real TypeScript checker,\n  so without `react`/`@types/react` and anything a component imports actually present, it detects\n  zero components — which looks like a config problem when it's an install problem.\n- **Scanning a large package with `names: \"*\"` is slow.** A full icon library (~3,400 components)\n  takes several seconds at startup. Naming the specific components you use keeps it instant.\n- **`@modelcontextprotocol/server` v2** (this depends on it per the SDK's own migration guidance\n  away from v1's `@modelcontextprotocol/sdk`) reached `2.0.0` a few weeks before this was written.\n  It's maintained by the official MCP org, but has far less real-world mileage than the v1 SDK.\n\n## Development\n\n```bash\ngit clone https://github.com/avcs06/weave-design-system-mcp.git\ncd weave-design-system-mcp\nnpm install\nnpm run build\n```\n\nPoint a client at a local build with `node ./dist/mcp/stdio.js /path/to/your-workspace` in place\nof the `npx` invocation above.\n\n```bash\nnpm run format:check   # prettier\nnpm run typecheck      # tsc --noEmit\nnpm test               # vitest\nnpm run build          # tsc -> dist/\n```\n\nCI runs all four on Node 22 and 24, then starts the built server against the example design system\nto confirm the published entrypoint actually loads one.\n\nRuns against [`examples/synthetic-design-system/`](examples/synthetic-design-system/) — the same\nfixture the worked example above uses, not a second copy that can drift from it — plus unit tests\nper implementation for cases the example doesn't cover (`styles/vanilla-extract.test.ts`,\n`styles/object.test.ts`, `components/stories.test.ts`) and dispatcher-level tests\n(`styles-adapter.test.ts`, `classname-adapter.test.ts`, `tsx-adapter.test.ts`) covering how an\nunrecognized `source` is reported. `createDesignSystem(config)` takes an in-memory config object,\nso tests need no `designsystem.config.json` on disk.\n","readmeFilename":"README.md"}