Design-system MCP server
The optimized context for agents: components, tokens, rules and examples, read from the design system source.
What
packages/ds-mcp is an MCP server that tells an agent what it needs to build a screen
with @vektos/ds. It has four tools, plus one that is opt-in:
| Tool | Returns |
|---|---|
get_guidelines | The rules in Markdown: tokens only, colors by meaning, which component for what |
list_components | Every component, one line each, with its compound parts |
get_component(name) | Props table with types and defaults, the import line, examples that compile |
list_tokens(category?) | Semantic colors with light value, dark value and job; every other scale, including fonts and breakpoints |
check_code(filename, code) | Opt-in. The benchmark's graders on a snippet |
Everything is read from the design system's source when the tool is first called: props
and descriptions from the components (via react-docgen), examples from the stories,
tokens from panda.config.ts, rules from the Storybook MDX pages. Nothing is written
twice, so it cannot drift from the code.
Why
The benchmark compares context levels. Storybook's MCP is the standard one: what a team gets by installing the addon. This server is the optimized one: the same source, shaped for an agent. Measured against Storybook's MCP on the same design system (anecdote 04):
| Storybook MCP | ds-mcp | |
|---|---|---|
| Tool definitions, sent with every request | 17,852 chars, 7 tools | 1,399 chars, 4 tools |
| Token names an agent can read | none (the page shows <SemanticTokenTable />) | all, with light, dark and job |
| Examples that compile when pasted | css is used but not imported | imports, helpers and args written out |
Maintainer advice ("add it to panda.config.ts") | included | left out: it is a protected-file violation |
The design choices behind it:
- Answers are Markdown, not JSON. The model reads them, and Markdown carries the same content in fewer tokens.
- Colors are semantic only. Palette shades are not listed: using them in app code is a violation, so there is no reason to show them.
- Examples are rewritten to stand alone. A story reads
argsfrom Storybook and imports from./button. The server writes the args out as props, adds the helpers the story uses and generates the@vektos/dsimport line. A story that only changes args is described as the change ("Default withsize="sm"") instead of repeating the JSX. check_codeis off by default. An agent that can run the grader is a different experiment from one that only reads docs. It is a separate column in the matrix.
Try it
bun run ds-mcp # stdio server, from the repo root
bun run ds-mcp --check # with check_code
cd packages/ds-mcp && bun test # 17 testsbun run --filter does not forward stdin, so start it from the root script or with
bun packages/ds-mcp/src/cli.ts. To use it from an agent, register the CLI as a stdio
server. With Claude Code:
claude mcp add vektos-ds -- bun /path/to/vektos/packages/ds-mcp/src/cli.tsThen ask "how do I show a list of invoices with a status?". The agent should call
get_component with Table and get, among the rest:
## TableCell
| Prop | Type | Default | Description |
| numeric | `boolean` | | Aligns to the end with tabular figures, so amounts line up digit by digit. |In code, the server connects to any transport. Tests use the in-memory one:
import { InMemoryTransport } from "@modelcontextprotocol/server";
import { createDsServer } from "@vektos/ds-mcp";
const [serverSide, clientSide] = InMemoryTransport.createLinkedPair();
await createDsServer({ checkTool: true }).connect(serverSide);Extend it
- A new component or story needs nothing here: the server reads
src/*.tsxandsrc/*.stories.tsxon start. The testevery example from the real stories grades cleanchecks that what agents copy follows the rules. - A new tool. Register it in
createDsServerinsrc/server.ts. Put the reading code insrc/catalog/, return Markdown, and add a test through the in-memory client. - Another design system. Pass
dsRoot. It needssrc/*.tsxcomponents with props interfaces, CSF3 stories, apanda.config.tsthat exportstokensandsemanticTokens, and the MDX pages listed inGUIDELINE_PAGES. - A rule page. Add it to
GUIDELINE_PAGESinsrc/catalog/guidelines.ts. Sections about maintaining the design system go inMAINTAINER_SECTIONSso they are left out.
Known gaps
- Stories are read only in the shapes ours use:
args, arenderarrow function with an expression body (inline or a named const) and{...args}. Other stories are skipped, not guessed. - Components that only pass Ark's props through show "Props: those of the underlying HTML element", with no list. Same limit as Storybook (see 04-storybook-mcp).
- Only semantic colors are read from
semanticTokens. A semantic spacing or radius token would be missed. - The catalog is read once per server. A long-running server does not see edits until it restarts.
- stdio only. An HTTP transport arrives if the runner needs it.
check_codechecks the design system, not the whole page. It runs the graders on one snippet. It does not runtscor oxlint, which the benchmark's page checks do. In the first results an agent withcheck_codereached zero design-system violations but kept its type and lint errors (anecdote 07). The benchmark'sds-mcp-check-fulllevel answers this with acheck_codethat also runstscand oxlint, but it lives in the runner, because it needs the agent's other files. A product version would run in the user's own project.