@actioneer/ads-mcp
v0.2.4
Published
ADS MCP server: lets an agent in Claude Code / Cursor discover and import the Actioneer Design System
Downloads
696
Readme
@actioneer/ads-mcp — the ADS MCP server
Lets a coding agent in Claude Code / Cursor discover and import the Actioneer
Design System through the same flow it already uses for shadcn — always pointing
at the canonical @actioneer/ads package, never a fork or a deep import.
It is a thin MCP layer over two pure, unit-tested cores, both declared as real
package dependencies (@actioneer/ads-manifest, @actioneer/ads-lint) so the
published package is self-contained — npx -y @actioneer/ads-mcp runs with no
repo checkout and no relative import escaping the package boundary:
- the manifest-query core (
@actioneer/ads-manifest) —(manifest, query) → results - the lint core — wraps
@actioneer/ads-lintto self-check generated code
All five tools read the L1 catalog (ads-manifest.json).
Tools
| Tool | Purpose |
|---|---|
| search_components(query, kind?, limit?) | Enumerate what exists by name or purpose → exact export names, families, kinds, descriptions. |
| get_component(name) | Full record for one EXACT export: the exact import { … } from "@actioneer/ads", props, variant/size vocabulary, showcase URL, and a copy-paste usage example. Returns an error (never invents) on an unknown name. |
| get_token(role) | The semantic token(s) for a role/utility/purpose (brand, bg-danger, muted text) so the agent references a token, not a literal ads-lint would reject. |
| get_principles(id?, enforcedByLint?) | The 9 ADS design principles (elevation = actionability, borderless surfaces, minimal-information-per-screen, square dots, stroke-only icons, container-fluid responsiveness, …). Each flags whether ads-lint auto-checks it — pair the [lint] ones with lint_snippet, self-apply the [judgment] ones. Teaches on-brand UX the catalog + linter can't. |
| lint_snippet(code) | Runs a snippet through @actioneer/ads-lint (consumer mode) and returns the verdict — deep imports, aliasing, external-UI, literals, weak motion. |
Wiring it into Claude Code / Cursor (.mcp.json)
Installed as a package (recommended for consumer repos):
{
"mcpServers": {
"ads": {
"command": "npx",
"args": ["-y", "@actioneer/ads-mcp"]
}
}
}ads-mcp is self-contained: it ships a bundled catalog snapshot, so
npx -y @actioneer/ads-mcp works standalone with nothing else installed. When
@actioneer/ads is installed alongside it, the server prefers that package's
manifest.json so the catalog matches the exact version you import. Override
either with ADS_MANIFEST:
{
"mcpServers": {
"ads": {
"command": "node",
"args": ["tools/ads-mcp/bin/ads-mcp.mjs"],
"env": { "ADS_MANIFEST": "./ads-manifest.json" }
}
}
}The second form is what the ADS repo itself uses for dogfooding (it points at the
generated repo-root ads-manifest.json). A ready-to-copy example lives at
mcp.example.json.
- Claude Code: drop the JSON in a
.mcp.jsonat your repo root (or runclaude mcp add ads -- npx -y @actioneer/ads-mcp). - Cursor: add the same
mcpServersblock to.cursor/mcp.json.
Manifest resolution order
$ADS_MANIFEST(explicit path)@actioneer/ads/manifest.json(the consumer's installed ADS version — exact match)<this package>/manifest.json(the snapshot bundled at publish — the self-contained fallback that makesnpxwork with no ADS installed)<repo>/ads-manifest.json(local dev — generated bynpm run manifest/prebuild)
Development
npm run test:mcp # from the ADS repo root — tool layer, lint_snippet, stdio round-tripThe transport is a dependency-free newline-delimited JSON-RPC 2.0 stdio loop
(src/server.mjs); all behavior lives in src/tools.mjs + the pure cores, which
are tested without ever starting the loop.
