@muraldevkit/ui-toolkit-mcp
v1.0.1
Published
Offline local MCP server for the Mural UI Toolkit design system
Readme
@muraldevkit/ui-toolkit-mcp
An MCP server for the Mural UI Toolkit. It gives your IDE agent one grounded source for how
to use a component correctly — design intent from Zeroheight, props and examples from
Storybook, and token values from foundation — merged into a single queryable record.
Ask get-component MrlButton and get everything needed to write on-spec code.
Setup
Configure the server once per project, and commit both the dependency and the MCP config — every contributor then gets the same server at the same version.
1. Install the package
npm install --save-dev @muraldevkit/ui-toolkit-mcpThe local install is what pins the version, via your lockfile. Skipping it also works — the launcher below then fetches the latest release on demand — but the version is no longer pinned or reproducible, so prefer the devDependency.
2. Configure the project
Add a ui-toolkit entry to mcpServers, alongside any MCP servers you already have. Claude
Code reads .mcp.json at the repo root; Cursor reads .cursor/mcp.json. Both take the same
block, and both belong in version control:
{
"mcpServers": {
"ui-toolkit": { "command": "npx", "args": ["-y", "@muraldevkit/ui-toolkit-mcp"] }
}
}The launcher is npx rather than the bare ui-toolkit-mcp bin because IDEs spawn stdio servers
with the inherited PATH, which does not include node_modules/.bin — the bin would ENOENT.
npx resolves the locally installed (lockfile-pinned) package first and falls back to fetching it
(-y) when the project has no local install.
Restart the IDE — or reload the window — after adding the entry. Nothing here is generated, so you
are free to add env (see Overrides); no tooling will rewrite your entry.
3. Verify
- Claude Code — project-scoped servers need a one-time approval; accept the prompt, then run
/mcpand confirmui-toolkitis connected with its six tools listed. From a shell,claude mcp listreports the same. - Cursor — Settings → MCP:
ui-toolkitshould be listed as running, with its tools. - End to end — ask the agent to call
list-components, thenget-component MrlButton. A full record back means the bundle resolved.
To debug a server that will not start, run it directly: npx -y @muraldevkit/ui-toolkit-mcp. It
loads the bundle, then waits on stdin — silence means healthy (Ctrl+C to quit); a failed load
prints the reason and exits non-zero.
4. Disable it
To turn the server off for yourself without touching the project's committed config:
- Claude Code — in
.claude/settings.local.json(git-ignored, personal):{ "disabledMcpjsonServers": ["ui-toolkit"] } - Cursor — toggle
ui-toolkitoff in Settings → MCP.
To turn it off for everyone, remove the ui-toolkit entry from the committed config (and the
devDependency). Nothing else is left behind: the server writes nothing outside its own install.
5. Upgrade the pinned version
npm install --save-dev @muraldevkit/ui-toolkit-mcp@latestCommit the resulting lockfile change and restart the IDE; every contributor picks the new version up on their next install. This upgrades both halves at once: the server (new tools or fixes) and the content, which ships inside the package — so upgrading is how you get current component docs.
Tools
All six are deterministic and name-based — no fuzzy search, no network.
| Tool | Arguments | Returns |
| ----------------- | ----------------------------------- | ------------------------------------------------------------------------------------- |
| list-components | — | Every documented component with a one-line summary. |
| get-component | name (e.g. MrlButton) | Full record: design intent, usage/do-don't, props, examples, import, links. |
| get-type | name (e.g. MrlSmartTableColumn) | The source definition (with JSDoc) of a named type referenced by component props. |
| get-tokens | group? (e.g. radii) | Design token values, optionally filtered by group. |
| list-pages | — | Every styleguide page with its sidebar path and documented components. |
| get-page | page (numeric id or exact title) | A full styleguide page including all tab content (Overview, Usage, Accessibility, …). |
Unknown names return an actionable error pointing at list-components / list-pages (or, for
get-tokens, listing the valid groups); an ambiguous get-page title lists the candidate ids.
Where the content comes from
The content lives in a mcp-data.json produced by this package's own generator
(npm run generate, source in src/bundle) and shipped inside the
published package at dist/mcp-data.json. Zeroheight credentials exist only in CI and on
maintainer machines; consumers never need them.
The server is fully offline: at startup it reads that one file, validates it against the shared schema, and serves every query from memory. There is no fetch, no cache and no network at any point — a failed load prints an actionable error and exits non-zero.
Overrides
| Name | Meaning |
| ---------------------------- | ----------------------------------------------------------------- |
| UI_TOOLKIT_MCP_BUNDLE_PATH | Serve this bundle file instead of the one shipped in the package. |
Versioning (latest-only)
The bundle is always generated from the latest @muraldevkit/ui-toolkit on main — older
toolkit/token versions are not supported; the bundle's sourceToolkitVersion stamp is for
traceability only. Content therefore travels with the package version: a release carries the
bundle generated when it was built.
Development
The package holds both halves — the published server (src/server, plus the Bundle contract
in src/schema.ts) and the maintainer-only bundle generator (src/bundle). They share one
Bundle type, imported directly, so the contract cannot fork.
npm run build # tsc → dist/, then stages data/mcp-data.json into dist/
npm test # vitest — server and generator suites together
npm run typecheck # tsc --noEmit (covers src/bundle too)
npm run start:dev # run the server from source over stdio against data/mcp-data.json
npm run inspect # MCP inspector against data/mcp-data.json
npm run generate # regenerate data/mcp-data.json (see below)npm run inspect is the quick maintainer loop — running from source there is no dist/ to read, so both pass
UI_TOOLKIT_MCP_BUNDLE_PATH.
src/bundle never ships: tsconfig.build.json excludes it, and it runs from source via tsx.
files publishes dist only — the compiled server, the Bundle schema exported at
@muraldevkit/ui-toolkit-mcp/schema (types + loadBundle/isBundle), and mcp-data.json when
one was generated before the build (postbuild copies it in; a missing bundle only warns, so a
plain checkout still builds — but the published server needs it, since that file is the content
it serves). Runtime dependencies: @modelcontextprotocol/sdk and zod. The package participates
in the root turbo run build / turbo run test.
Generating the bundle
npm run generate merges four sources into data/mcp-data.json:
- Zeroheight — every styleguide page with its tab content (the documentation spine).
- Storybook — its components manifest: imports, props and story code examples.
- Types — named TypeScript types referenced by component props, verbatim from source.
- Tokens —
packages/foundation/zeroheight/tokens.json, verbatim.
Build the prerequisite manifest first, from the repo root:
npm run compile --workspace=@muraldevkit/ui-toolkit # storybook-static/manifests/components.jsonThe manifest comes from features.componentsManifest in packages/ui-toolkit/.storybook/main.ts;
generate fails with a pointer to it if the file is missing.
Put Zeroheight credentials in the repo-root .env (loaded by the generate script):
ZEROHEIGHT_API_KEY=... # sent as the X-API-KEY header
ZEROHEIGHT_CLIENT_ID=... # sent as the X-API-CLIENT headerThen:
npm run generate # writes data/mcp-data.json (+ refreshes data/zh-cache.json)Generation validates the merged bundle against the shared schema and writes nothing on failure.
Re-run it whenever the toolkit, tokens or the Zeroheight styleguide change, and re-run
npm run build afterwards to refresh dist/mcp-data.json.
Data files
Both live in the gitignored data/, created by generate:
| File | Role |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| data/mcp-data.json | The generated output. Copied into dist/ by postbuild. |
| data/zh-cache.json | Raw Zeroheight responses: the sidebar nav tree plus page bodies keyed by updated_at, so generate only re-fetches changed pages. |
