Skip to Content
Vektos
Guides

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:

ToolReturns
get_guidelinesThe rules in Markdown: tokens only, colors by meaning, which component for what
list_componentsEvery 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 MCPds-mcp
Tool definitions, sent with every request17,852 chars, 7 tools1,399 chars, 4 tools
Token names an agent can readnone (the page shows <SemanticTokenTable />)all, with light, dark and job
Examples that compile when pastedcss is used but not importedimports, helpers and args written out
Maintainer advice ("add it to panda.config.ts")includedleft 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 args from Storybook and imports from ./button. The server writes the args out as props, adds the helpers the story uses and generates the @vektos/ds import line. A story that only changes args is described as the change ("Default with size="sm"") instead of repeating the JSX.
  • check_code is 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 tests

bun 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.ts

Then 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/*.tsx and src/*.stories.tsx on start. The test every example from the real stories grades clean checks that what agents copy follows the rules.
  • A new tool. Register it in createDsServer in src/server.ts. Put the reading code in src/catalog/, return Markdown, and add a test through the in-memory client.
  • Another design system. Pass dsRoot. It needs src/*.tsx components with props interfaces, CSF3 stories, a panda.config.ts that exports tokens and semanticTokens, and the MDX pages listed in GUIDELINE_PAGES.
  • A rule page. Add it to GUIDELINE_PAGES in src/catalog/guidelines.ts. Sections about maintaining the design system go in MAINTAINER_SECTIONS so they are left out.

Known gaps

  • Stories are read only in the shapes ours use: args, a render arrow 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_code checks the design system, not the whole page. It runs the graders on one snippet. It does not run tsc or oxlint, which the benchmark's page checks do. In the first results an agent with check_code reached zero design-system violations but kept its type and lint errors (anecdote 07). The benchmark's ds-mcp-check-full level answers this with a check_code that also runs tsc and 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.

On this page