Skip to main content
Glama

ds-mcp-starter

A contract-first Model Context Protocol server for a design system.

It reads DTCG design tokens, indexes them into a typed, deterministic manifest, and exposes the same pure core through three facades: an MCP server for LLM agents, a CLI for humans and CI, and an importable TypeScript library.

The repository ships a small fictional multi-brand system (brands aurora and nord, modes light and dark, 81 tokens per theme) so every command below runs as-is.

Contract first, MCP second

MCP is a transport. The value lives in the contract underneath it: a manifest with a schema, and a set of pure functions that answer design system questions from it.

  • The indexer turns token files into dist/manifest.json (plus its JSON Schema). No network, no clock, same input gives the same bytes.

  • The core is a set of pure functions over that manifest, each with a zod input and output schema.

  • The facades are thin. The MCP server registers the core functions as tools; the CLI prints them for people and returns exit codes for CI; the library exports them.

CI never starts an MCP server. It runs the same code through the CLI.

flowchart LR
  subgraph Sources
    T[tokens/**/*.json<br/>DTCG 2025.10]
  end
  T --> I[Indexer<br/>flatten, resolve aliases,<br/>detect cycles]
  I --> M[(Manifest<br/>dist/manifest.json<br/>+ JSON Schema)]
  M --> C[Core tools<br/>pure functions<br/>zod in / zod out]
  C --> S[MCP server<br/>stdio]
  C --> L[CLI ds<br/>humans + CI gates]
  C --> B[Library<br/>import from ds-mcp-starter]
  S --> A[Any MCP client<br/>LLM agents]

Related MCP server: Designesy

Tools

Tool

Access

Answers

search_tokens

read

Which token expresses this intent? Ranked search on paths and descriptions; semantic before primitive, deprecated last.

resolve_token

read

What does this token become in nord/dark, and through which aliases? Accepts color.fg.default, --color-fg-default or var(...).

find_token_for_value

read

Which token should replace this hard-coded #1a73e8 or 16px? Exact matches first, then perceptually nearest colors (OKLab). Optional CSS property to rank by intent.

lint_naming

read

Does this name follow category.role.variant[.state]? Returns violations and a corrected name.

audit_css

read

Where does this CSS hard-code values, use deprecated tokens or reference tokens that do not exist? With line, column and suggestions.

arbitrate_semver

read

Is this change set a major, minor or patch release, and why?

propose_token

write

What exactly would adding this token change? Returns a JSON Patch and a unified diff; writes only on explicit confirmation.

Tool descriptions are written for an LLM: when to call the tool and what it returns. Read-only and write tools are flagged with MCP annotations (readOnlyHint, destructiveHint).

Governance: AI prepares, humans decide

Agents are fast at preparing changes and bad at owning them. The server is built so that the default path is always a reviewable proposal.

  • Write tools preview by default. propose_token returns the target file, a JSON Patch and a diff. confirm: true is required to write.

  • Two keys for writes over MCP. Even with confirm: true, the MCP server refuses to write unless it was started with --allow-writes. The intended flow is: the agent previews, a person runs ds propose ... --confirm or applies the diff in a pull request.

  • Validation before preview. A proposal is rejected before any diff is produced if the name breaks the grammar, collides with an existing token or group, aliases a token that does not exist in every affected theme, or mixes types.

  • Naming lint. One grammar for people and agents. CSS property names (padding), brand or mode names (aurora, dark) and misplaced states are rejected with a suggested fix.

  • Semver arbitration. Removed or renamed tokens are majors, additions and deprecations are minors, value changes are patches unless the type changes. Removing a token that was never deprecated produces a warning: deprecate before you remove.

  • CI gate. ds audit fails the build on hard-coded values or unknown tokens; ds semver --max minor fails a change set that would require a major.

Quickstart

Requires Node.js 20 or later.

npm install
npm run build          # compile TypeScript to dist/
npm run manifest       # write dist/manifest.json and dist/manifest.schema.json
npm link               # optional: puts the ds and ds-mcp-server commands on your PATH

Without npm link, replace ds with node dist/cli/main.js below.

CLI

ds search "secondary text"
ds resolve color.text.primary --brand aurora --mode dark
ds find "#1a73e8" --brand nord --mode light
ds lint color.fg.subtle spacing.padding.md color.dark.surface
ds audit examples/button.css examples/legacy.css
ds semver examples/changes.json --max minor
ds propose color.fg.subtle --type color --value "{color.neutral.500}" \
  --description "Placeholder text and disabled labels." --brand aurora --mode light

Every command accepts --json. Exit codes: 0 success, 1 a check failed (lint, audit, semver above --max, rejected proposal), 2 usage or data error.

$ ds resolve color.text.primary --brand aurora --mode dark
color.text.primary (aurora/dark) = #f7f8fa
  chain:   color.text.primary -> color.fg.default -> color.neutral.50
  css:     var(--color-text-primary)
  type:    color, semantic, brands/aurora/modes/dark.json
  about:   Former name of the default text color.
  status:  deprecated. Use {color.fg.default}. Scheduled for removal in 2.0.0.

$ ds audit examples/legacy.css --brand nord --mode light    # excerpt
examples/legacy.css:3:12  error   hard-coded-dimension padding: Hard-coded dimension 16px. Use var(--spacing-inset-md).
examples/legacy.css:5:21  error   hard-coded-color     border: Hard-coded color #dde1e8. Nearest token: var(--color-border-subtle).
examples/legacy.css:14:14  warning deprecated-token     color: --color-text-primary is deprecated. Use {color.fg.default}. Scheduled for removal in 2.0.0.
examples/legacy.css:22:14  error   unknown-token        color: --color-fg-subtle looks like a design token but does not exist. Did you mean --color-bg-subtle, --color-fg-muted, --color-bg-surface?
examples/legacy.css: 14 error(s), 1 warning(s)

MCP client

Any MCP client that launches stdio servers can use it. See examples/mcp-client-config.json:

{
  "mcpServers": {
    "design-system": {
      "command": "node",
      "args": ["/absolute/path/to/ds-mcp-starter/dist/server/main.js", "--tokens", "/absolute/path/to/ds-mcp-starter/tokens"]
    }
  }
}

Server options: --tokens <dir> (default tokens, or $DS_TOKENS_DIR), --manifest <file> to serve a prebuilt manifest in read-only mode, --allow-writes to let propose_token write on confirmation. Logs go to stderr.

Library

import { buildManifestFromDirectory, findTokenForValue, auditCss } from "ds-mcp-starter";

const manifest = await buildManifestFromDirectory("tokens");
findTokenForValue(manifest, { value: "#1a73e8", property: "background" }).recommendation;
auditCss(manifest, { css: ".a { padding: 16px }" }).ok; // false

Token layout

tokens/
  core/*.json                      primitives shared by every theme (color scales, spacing, radius, font, border)
  semantic/*.json                  semantic tokens shared by every brand (spacing.inset.md -> spacing.4)
  brands/<brand>/brand.json        semantic tokens of one brand (radius.control, font.family.brand)
  brands/<brand>/modes/<mode>.json semantic colors of one brand in one mode

A theme is one brand in one mode: core + semantic + brand + mode, merged in that order. A path may be defined only once per theme. Values follow DTCG 2025.10 ({ "colorSpace": "srgb", "components": [...], "hex": ... } for colors, { "value": 16, "unit": "px" } for dimensions), aliases use {path} and $deprecated names its replacement. In code, paths are dot-separated (color.fg.default); in CSS they become --color-fg-default.

Project structure

src/
  core/            pure: DTCG parsing, alias resolution, manifest schema, and the 7 tools
    tools/         one file per tool: zod input, zod output, pure function
  node/            the only file system code: discover token files, build/read/write the manifest, apply proposals
  tools/           facade-agnostic tool registry (name, LLM-facing description, schemas, read/write)
  server/          MCP facade: registers the registry on an McpServer, stdio entry point
  cli/             CLI facade: argument parsing, human formatting, exit codes
  index.ts         library facade
tokens/            demo DTCG tokens (2 brands x 2 modes)
examples/          MCP client config, clean and legacy CSS, a semver change set
scripts/           stdio smoke test of the built server
test/              Vitest suites, including an in-memory MCP end-to-end test

Testing

npm test            # 63 tests
npm run typecheck
npm run lint        # Biome
npm run smoke       # starts dist/server/main.js over stdio and calls a tool
npm run check       # everything CI runs, in order

The suites cover alias resolution (multi-level chains, cycles, unknown references, type mismatches, duplicates), value serialization, search ranking, nearest-color matching, every naming rule, CSS audit positions and suggestions, semver rules, proposal preview versus confirmation, and an end-to-end MCP session through the SDK client over an in-memory transport. Two repository guards run with them: no stdout writes in server-side modules, and token files kept in the canonical format the tools write. The demo tokens are also linted with the naming grammar, so the example system follows its own rules.

Design decisions

  • Contract first. The manifest has a zod schema, published as JSON Schema next to it. Consumers validate what they read. The MCP tools publish input and output schemas and return structuredContent validated against them.

  • One core, three facades. Business rules live in src/core only. The MCP server and the CLI only parse input and format output, so behavior is tested once, without starting a server.

  • No network in the indexer. Token sources are local files; the indexer is a pure function from sources to manifest. Deterministic output (sorted, no timestamps) keeps the manifest diffable in code review.

  • stdout belongs to the protocol. The server logs to stderr only. A Biome rule (noConsole outside the CLI), a test scanning server-side modules and a stdio smoke test protect the stream.

  • Deprecate before you remove. Deprecations name their replacement ($deprecated: "Use {color.fg.default}."). The audit reports usages with the replacement, search ranks deprecated tokens last, and semver arbitration warns when a token disappears without a deprecation period.

  • Intent over value. Matching a value is not enough: 16px is both a padding and a radius. find_token_for_value and audit_css rank tokens by the intent of the CSS property and prefer semantic tokens over primitives.

  • Small on purpose. Two runtime dependencies (@modelcontextprotocol/sdk, zod), exact versions, no bundler.

Roadmap

  • Figma variables export: map brands and modes to variable collections and modes from the same manifest.

  • Code Connect hints: link components to the tokens they consume, so agents can answer "which token does this component use".

  • Streamable HTTP transport, for a shared read-only server in front of a published manifest.

  • Manifest diff: compute arbitrate_semver input from two manifests instead of a hand-written change set.

  • Composite types (typography, shadow, gradient) and partial references.

License

MIT, Florian Cazé.

Available Tools

7 tools
arbitrate_semverArbitrate the semver bump of token changesA
Read-onlyIdempotent

Given the token changes of a release (added, removed, renamed, value-changed, deprecated), return the required version bump (major, minor, patch) with a reason per change, and warnings when a token is removed without having been deprecated first. Use it to prepare a release or review a change set.

NameRequiredDescriptionDefault
changesYesToken changes included in the release

Output Schema

NameRequiredDescription
bumpYes
changesYes
warningsYes
principleYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds real behavioral detail beyond that: a reason is returned per change, and a warning is emitted when a token is removed without prior deprecation — information an agent could not infer from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, and the output contract is front-loaded before the usage hint. Every clause carries new information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't restate return values, yet it still summarizes the bump, per-change reasons and warnings. Combined with a fully documented single parameter, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by enumerating the five change kinds (added, removed, renamed, value-changed, deprecated) that the `changes` array accepts, giving the agent the semantic vocabulary of the required input.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — take token changes and return the required semver bump (major/minor/patch) with per-change reasons and warnings. That output shape makes it clearly distinct from siblings like lint_naming or audit_css, though it never names an alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear context for use: 'Use it to prepare a release or review a change set.' That is enough for an agent to know when it applies, but there are no exclusions or named alternative tools for adjacent tasks such as linting or proposing changes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit_cssAudit CSS for token usageA
Read-onlyIdempotent

Audit a CSS snippet: reports hard-coded colors and dimensions (with the token to use instead), usages of deprecated tokens (with their replacement) and references to tokens that do not exist. Returns ok=false when there is at least one error. Use it to review generated or legacy CSS.

NameRequiredDescriptionDefault
cssYesCSS source to audit
modeNoRestrict suggestions to one mode
allowNoLiteral values that are accepted as-is
brandNoRestrict suggestions to one brand

Output Schema

NameRequiredDescription
okYesFalse when at least one error was found
findingsYes
errorCountYes
warningCountYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuine behavioral context beyond that: the categories of findings it emits and the ok=false contract when at least one error is present. It does not describe pagination or result ordering, but for a non-destructive, idempotent audit that is minor.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, front-loaded with the action and the enumerated findings, then the usage cue. Every clause carries information an agent needs for selection.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a 100% covered schema and an output schema present, the description only needs to cover purpose and behavior, which it does. It could be slightly stronger by clarifying how suggestions are scoped by mode/brand, but nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so css, mode, brand, and allow are already documented in the schema. The description adds no semantics for mode/brand scoping or the allow-list behavior beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (audit) and resource (CSS snippet) and enumerates exactly what it reports: hard-coded colors/dimensions with replacement tokens, deprecated token usage, and nonexistent token references. This distinguishes it clearly from siblings such as lint_naming, search_tokens, and find_token_for_value.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use it to review generated or legacy CSS" gives clear when-to-use context. It does not name alternatives or state when-not to use it (e.g., versus lint_naming), so it falls just short of explicit routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_token_for_valueFind the token for a hard-coded valueA
Read-onlyIdempotent

Given a hard-coded value (#1a73e8, rgb(...), 16px, 1rem), return the tokens that carry it: exact matches first (semantic before primitive), then the perceptually nearest colors or nearest dimensions. Use it whenever code or a design contains a literal value, to replace it with a token.

NameRequiredDescriptionDefault
modeNoColor mode, for example light or dark
typeNoInferred from the value when omitted
brandNoBrand name, for example aurora or nord
limitNo
valueYesA hard-coded value, for example #1a73e8, rgb(26 115 232), 16px or 1rem
propertyNoCSS property where the value is used (padding, color, border-radius...). Ranks tokens by intent

Output Schema

NameRequiredDescription
typeYes
exactYes
valueYes
nearestYes
normalizedYesCanonical form of the input used for comparison
recommendationYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish the read-only, idempotent, closed-world safety profile, and the description adds real behavioral detail beyond them: the result ordering (exact → semantic → primitive) and the fuzzy fallback to perceptually nearest colors or dimensions. It never states implied limits on the fallback (e.g. how distant a match can be) or whether approximate results are flagged.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero waste, with the matching strategy front-loaded ahead of the usage cue. The parenthetical format examples mildly duplicate the schema's value description but are defensible as quick-scannable input hints.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return shape needn't be explained, and the description covers the input formats and result ranking that matter for correct invocation. Gaps remain around how brand/mode/property constrain matching and how the limit interacts with the fuzzy fallback tier.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so the schema already documents mode, type, brand, property and limit. The description only reinforces the value formats, which are also examples in the schema, and its ranking language hints at property-as-intent without making that explicit. It adds little beyond the baseline for the five optional parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource pair: given a hard-coded literal, return the tokens carrying it, with an explicit match strategy (exact first, semantic before primitive, then nearest). Input formats are enumerated. It doesn't name sibling tools like search_tokens or resolve_token, so an agent must infer the boundary itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use it whenever code or a design contains a literal value, to replace it with a token" gives a clear activating condition. There are no exclusions and no named alternatives, so it stops short of the when/when-not/alternative guidance that would earn a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lint_namingLint token namesA
Read-onlyIdempotent

Check proposed token names against the naming grammar category.role.variant[.state]: lowercase kebab segments, known category, intent words instead of CSS properties (inset, not padding), state last, no brand or mode in the name. Returns violations and a corrected name when one can be derived. Call it before proposing a token.

NameRequiredDescriptionDefault
namesYesProposed token names as dot paths, for example ['color.fg.subtle', 'spacing.padding.md']

Output Schema

NameRequiredDescription
validYes
resultsYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower. The description adds real behavioral value beyond that: it discloses the rule set being enforced and that the result is a violation list plus a derived corrected name 'when one can be derived', which is a meaningful caveat about non-determinism of the output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the tool's purpose, then packs the grammar rules densely without filler. The rule enumeration is long but each clause (kebab case, intent words, state last, no brand/mode) carries distinct enforcement information, so nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be re-explained, and annotations cover the safety profile. Combined with 100% parameter schema coverage, the description supplies everything an agent needs about intent, rules, timing, and result shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter, and schema description coverage is 100% — the schema already documents 'names' as dot-path strings with examples. The description's grammar text implies what valid input looks like but adds no parameter-specific syntax or formatting detail. Baseline 3 applies when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Check proposed token names') and enumerates the exact grammar being enforced (category.role.variant[.state], lowercase kebab, state last, no brand/mode). It does not explicitly name or contrast the other siblings such as audit_css or find_token_for_value, though 'Call it before proposing a token' does implicitly position it against propose_token.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear timing guidance: 'Call it before proposing a token.' That tells the agent when in the workflow to invoke it. It omits when-not-to-use and doesn't address the other siblings (e.g., when to lint vs. audit_css), so it falls short of a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

propose_tokenPropose a new tokenA
Destructive

Prepare the addition of a token. Validates the name (lint_naming), collisions, the scope and the value (aliases must exist and have the same type), then returns a preview: the target file, a JSON Patch and a unified diff. Nothing is written unless confirm is true AND the server was started with writes allowed. Default to a preview and let a human review it.

NameRequiredDescriptionDefault
modeNoScope the token to one mode of the brand. Requires brand
pathYesDot path of the new token, for example color.fg.subtle
typeYes
brandNoScope the token to one brand. Omit for a token shared by all brands
valueYesAn alias such as {color.neutral.500} (preferred for semantic tokens) or a literal: #1a73e8, 16px, 1.5
confirmNofalse (default) returns a preview and writes nothing. true writes the file, only after human review
descriptionNoIntent of the token: when to use it. Search and agents rely on it

Output Schema

NameRequiredDescription
diffYesUnified diff of the target file
pathYes
patchYesRFC 6902 JSON Patch applied to the target file
statusYes
targetYesToken file that receives the change, relative to the tokens directory
messageYes
warningsYes
violationsYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations mark this destructive (readOnlyHint=false, destructiveHint=true, idempotentHint=false), and the description adds the crucial guardrail context beyond them: nothing is written unless confirm is true and the server was launched with writes enabled, plus the exact validation sequence and what the preview contains. It also tells the agent the intended workflow (preview, then human review), which annotations alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight sentences, front-loaded with the purpose, then the validation pipeline, then the write gate, then the recommended workflow. Every sentence carries information an agent needs and none repeats the schema or title verbatim.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having 7 parameters, an output schema and rich annotations, the description still covers the gaps that matter: alias typing rules, the confirm/writes-allowed gate, and how to treat the preview. Nothing needed to invoke it correctly is missing; return-shape detail is rightly left to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 86%, so baseline is 3, but the description adds real meaning: value must be an alias that exists and shares the same type, and confirm is the hard gate for the write. It stays silent on brand/mode/description semantics, which the schema already covers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Prepare the addition of a token') plus the resource and the exact scope of work: lint_naming validation, collision/scope/value checks, and a preview return of target file, JSON Patch and unified diff. This clearly distinguishes it from siblings like lint_naming (a validation used internally) and search_tokens/resolve_token (read-side tools).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operating context ('Default to a preview and let a human review it') and explains the condition that turns it into a write (confirm true AND server started with writes allowed). It does not explicitly name a sibling alternative or spell out when-not-to-use, so it falls short of the top tier but leaves little to infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_tokenResolve a tokenA
Read-onlyIdempotent

Get the final value of one token for a given brand and mode, with the alias chain that produced it (for example color.fg.default -> color.neutral.900). Accepts a dot path, a CSS custom property or var(). Use it to explain a value or to check what a token becomes in dark mode.

NameRequiredDescriptionDefault
modeYesColor mode, for example light or dark
pathYesToken reference: dot path (color.fg.default), custom property (--color-fg-default) or var(--color-fg-default)
brandYesBrand name, for example aurora or nord

Output Schema

NameRequiredDescription
modeYes
pathYesDot path, for example color.fg.default
typeYes
brandYes
layerYescore = primitive values, semantic = intent-based tokens that alias core tokens
valueYesResolved value, serialized for CSS
cssVarYesCSS custom property name, for example --color-fg-default
sourceYesSource file, relative to the tokens directory
rawValueYesThe $value exactly as authored (literal or {alias})
aliasChainYesPaths followed to resolve the value, nearest first. Empty for literal values
deprecatedYesfalse, true, or a message naming the replacement (DTCG $deprecated)
descriptionNo
replacementNoToken to use instead, when this one is deprecated

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so safety and side-effect behavior are covered. The description adds meaningful context beyond annotations by disclosing that the result includes the alias chain that produced the final value, which helps an agent understand the return shape without relying solely on the output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action and scoped by brand and mode, with a compact inline example. No wasted text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Inputs are fully described in the schema, an output schema exists, and the description explains the resolution result including the alias chain. An agent has enough to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents accepted token reference forms (dot path, custom property, var()) and example brand/mode values. The description largely repeats what the schema states, adding only the dark-mode use case, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Get the final value of one token for a given brand and mode, with the alias chain.' The example (color.fg.default -> color.neutral.900) makes the output concrete and clearly distinguishes it from sibling search_tokens or find_token_for_value.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear contexts for use: 'to explain a value' and 'to check what a token becomes in dark mode.' It does not explicitly name alternatives or exclusions, but the stated scenarios are sufficient to guide selection among siblings for most cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_tokensSearch design tokensA
Read-onlyIdempotent

Find design tokens by intent or name, for example 'muted text', 'control radius' or 'danger'. Use it before writing any color, spacing, radius or font value. Returns ranked tokens with their CSS custom property, description, deprecation status and resolved value per brand and mode. Semantic tokens rank above primitives; deprecated tokens rank last.

NameRequiredDescriptionDefault
modeNoColor mode, for example light or dark
brandNoBrand name, for example aurora or nord
limitNo
queryYesWords to look for in token paths and descriptions, for example 'muted text' or 'radius control'

Output Schema

NameRequiredDescription
queryYes
totalYes
resultsYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavior: ranking rules (semantic above primitives, deprecated last) and the returned fields per brand and mode, which an agent cannot infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with purpose then the usage imperative, then return/ranking behavior. No filler, though the ranking clause and return-field list are slightly dense for one sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, yet the description adds ranking semantics that matter for interpreting results. Only the undocumented 'limit' parameter and pagination/truncation behavior are left unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%; query, brand and mode are documented in the schema, though 'limit' has no description at all. The description reinforces the query style and implies brand/mode shape the resolved value, but adds no format or defaulting detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find design tokens by intent or name') with three concrete example queries, which makes the search semantics unambiguous. It does not name a sibling to contrast with, so the boundary with find_token_for_value (reverse value lookup) or resolve_token is left implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it before writing any color, spacing, radius or font value' gives a clear trigger condition tied to the agent's task. There are no explicit exclusions or named alternatives for cases like exact-name resolution, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.1.0
    • First observedarbitrate_semver
    • First observedaudit_css
    • First observedfind_token_for_value
    • First observedlint_naming
    • First observedpropose_token
    • First observedresolve_token
    • First observedsearch_tokens

TDQS

A4.3/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct operation: intent/name search (search_tokens), single-token resolution (resolve_token), reverse lookup from a literal value (find_token_for_value), naming validation, CSS auditing, semver arbitration, and token proposal. The three token-lookup tools could superficially look similar, but their descriptions make the input types (intent phrase vs dot path vs literal value) unambiguous.

Naming Consistency5/5

All seven tools follow a strict snake_case verb_noun pattern (search_tokens, resolve_token, find_token_for_value, lint_naming, audit_css, arbitrate_semver, propose_token). Verbs are meaningful and consistently chosen, with no camelCase or stylistic mixing.

Tool Count5/5

Seven tools is well-scoped for a design-token governance server; each covers a distinct phase (discover, resolve, validate, audit, version, propose). No tool feels redundant or like padding.

Completeness4/5

The surface covers discovery, resolution, reverse lookup, validation, auditing, semver, and additive proposals well. Gaps remain around modifying or deleting existing tokens (rename/remove are only analyzed, not executed), but agents can work around this via propose_token and arbitrate_semver.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Design contract layer for AI agents. Scans Figma, code, Storybook, and token files, reconciles conflicts, and serves a single machine-readable source of truth so every agent gets the same authoritative design rules before it builds. Local-first.
    9
    69 npm
    21
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to score live URLs against a deterministic design contract, validate DTCG tokens and Lottie animations, audit accessibility, and retrieve design-system contracts, catalogs, and review rubrics.
    17
    3 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables coding agents to query a workspace's design system before writing UI and validate generated code against the same system afterward, using configurable token and component sources.
    4 npm
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI coding agents to inspect a project's design tokens and component catalog, audit React/Tailwind files against seven static UI quality rules, score overall UI health, and apply auto-fixes that are re-audited and reverted on regression. It works both locally over filesystem access and remotely on raw TSX/JSX or CSS snippets passed directly as strings.
    -