01What this is and why you want it#
smart-ui-mcp-server is a Model Context Protocol server that gives any MCP-aware coding assistant (Claude Code, Claude Desktop, Cursor, GitHub Copilot Chat in agent mode, Continue, Windsurf, Zed…) deep, accurate knowledge of the Smart UI Web Components library.
It exposes:
- 110+ Smart UI components with the full API surface — every property, method, event, CSS variable, and allowed-value enum, sourced from the official component metadata.
- The exact module import and theme stylesheet stack for any component — no more guessing whether the property is
editingoreditable, or which theme files to load and in what order. - Demo browsing — the assistant can list and read every demo your repo ships, per framework (Web Components, React, Angular, Vue).
- Documentation browsing — the same for
/documentationtopics (overview.htm,api.htm,accessibility.htm, plus framework-specific guides for Angular, Blazor, React, Vue). - A code generator that emits a complete runnable file for Web Components, React, Angular, Vue, and Blazor, with the right imports, theme stylesheet, attribute markup, and post-mount property assignments for complex options.
Why this beats freehand prompting
Without the MCP, an assistant has to guess Smart UI API names from training data. With the MCP, the assistant queries the actual schema before writing code. Concretely:
- It writes
editing(the real property name) instead of hallucinatingeditable. - It emits the exact paths that exist in your
node_modules—smart.default.css+fluent/light/smart.fluent.cssfor the theme stack, and a singlesmart.grid.jsimport that already bundles every sub-module — not a guess. - It can crib a working pattern from
demos/grid/grouping/instead of inventing one.
0260-second quick start#
# 1. Install Claude Code (skip if you already have it)
npm install -g @anthropic-ai/claude-code
# 2. Register the Smart UI MCP server
claude mcp add smart-ui npx smart-ui-mcp-server
# 3. Open any project and ask:
claude
> Use the smart-ui MCP. Generate a Web Components page with a smart-grid
> bound to a 10-row JSON array of employees (id, name, position, salary),
> with sorting and paging enabled. Theme fluent.
You'll get a complete runnable index.html with the right tag, imports, and config.
03Installation#
From npm (recommended)
# global install
npm install -g smart-ui-mcp-server
# or call directly with npx (no global install needed)
npx smart-ui-mcp-server
The package bundles a snapshot of the Smart UI API metadata (110 components, ~4 MB unpacked) so it works zero-config straight after install. No live Smart UI checkout is required for the core tools.
From a tarball
If you received smart-ui-mcp-server-1.0.0.tgz directly:
npm install -g ./smart-ui-mcp-server-1.0.0.tgz
From source
git clone <repo-url>
cd smart-ui-mcp-server
npm install
npm test # 45 smoke tests should pass
npm start # run the server over stdio (for manual probing)
Requirements
- Node.js 18 or newer (uses ESM and the modern
fspromises API). - Any MCP-capable assistant. Each one has its own config format — see the next section.
04Connecting your assistant#
The Smart UI MCP server speaks MCP over stdio. Every assistant below uses the same underlying command (npx smart-ui-mcp-server) — only the config file differs.
Claude Code (CLI)
The cleanest path. From any directory:
claude mcp add smart-ui npx smart-ui-mcp-server
To verify: claude mcp list. To remove later: claude mcp remove smart-ui.
Add it project-locally instead by passing --scope project, which writes to .mcp.json in the project root and is auto-picked-up by anyone who clones the repo.
Claude Desktop
Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"smart-ui": {
"command": "npx",
"args": ["smart-ui-mcp-server"]
}
}
}
Restart Claude Desktop. The tools should appear under the 🔨 hammer icon in the message input.
VS Code — GitHub Copilot Chat (agent mode)
Create .vscode/mcp.json in your workspace root:
{
"servers": {
"smart-ui": {
"type": "stdio",
"command": "npx",
"args": ["smart-ui-mcp-server"]
}
}
}
Open Copilot Chat, switch to agent mode, and ask a Smart UI question. The tools appear automatically.
Cursor
Cursor uses ~/.cursor/mcp.json (or <workspace>/.cursor/mcp.json for project scope):
{
"mcpServers": {
"smart-ui": {
"command": "npx",
"args": ["smart-ui-mcp-server"]
}
}
}
Continue
Edit ~/.continue/config.json:
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "npx",
"args": ["smart-ui-mcp-server"]
}
}
]
}
}
Windsurf
Edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"smart-ui": {
"command": "npx",
"args": ["smart-ui-mcp-server"]
}
}
}
Zed
Add to ~/.config/zed/settings.json:
{
"context_servers": {
"smart-ui": {
"command": {
"path": "npx",
"args": ["smart-ui-mcp-server"]
}
}
}
}
05Verifying the connection#
After restarting your assistant, ask:
A working setup will respond with a list of 100+ smart-* tags. If it says “I don't have access to that information” or makes up tag names that don't start with smart-, the MCP isn't wired in — check your config file path and restart the assistant.
You can also test directly from a shell:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | npx smart-ui-mcp-server
(Press Ctrl+C after a second.) You should see a JSON response listing all 13 tools.
06The 13 tools at a glance#
| Tool | When the assistant calls it |
|---|---|
list_widgets | “What components are there?” / fuzzy lookup by keyword. |
get_widget | First call for any new component — gets counts, tag, class, module file, features. |
get_widget_properties | Before writing config — finds the exact property name and its allowed values. |
get_widget_methods | When the prompt mentions an imperative action (export, addRow, refresh). |
get_widget_events | When wiring event handlers (onChange, onClick, onCellEditEnd). |
get_widget_css_variables | Custom theming / CSS variable overrides. |
get_widget_types | When a property has an enum type and the assistant needs the legal values. |
get_required_scripts | Always called before generating code — gives the exact module URLs and the theme link. |
list_demos | “What demos do you ship for X?” — returns folder names. |
get_demo_code | Read a specific demo folder (returns every source file in it). |
list_documentation | Lists /documentation/<topic>/*.htm files for a component. |
get_documentation | Read a specific doc file (overview.htm, api.htm, accessibility.htm). |
generate_example | Emits the final runnable file for the chosen framework. |
07How to refer to a component#
Every Smart UI component has three equivalent identifiers; the MCP accepts any of them in every tool call:
- bare slug —
button,dropdownlist,ganttchart - custom-element tag —
smart-button,smart-drop-down-list,smart-gantt-chart - class name —
Button,DropDownList,GanttChart
All three resolve to the same component record. The generator always emits the canonical Smart UI form in the output code — <smart-grid> for HTML / Vue, <Grid> for React / Blazor, and <smart-grid> with GridComponent for Angular.
08Worked tutorial — Grid (Web Components)#
smart-grid of employees (id, name, position, salary). Enable sorting, paging, and filtering. Theme fluent.What happens under the hood
- The assistant calls
get_widget("grid"). It learns the tag issmart-grid, the class isGrid, the available feature modules includesort,filter,pager,edit,group,export,reorder,select,tree, and the shorthand attributes includesortable,filterable,pageable,editable,groupable,selectable,columnResize,columnReorder. - Because the prompt only asks to switch features on, the assistant picks the shorthand attributes (cleaner config) over the configurable object properties.
- It calls
get_required_scripts("grid", { theme: "fluent" })and gets two stylesheet links —smart.default.css(base) plusfluent/light/smart.fluent.css(overlay) — and exactly one module URL:smart.grid.js. That single file already imports every sub-module (sort, filter, pager, edit, …); no extra script tags needed. - It calls
generate_examplewith the merged options.
What you get
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Grid example</title>
<!-- smart.default.css is the base; smart.fluent.css overlays it -->
<link rel="stylesheet" type="text/css" href="../../../source/styles/smart.default.css" />
<link rel="stylesheet" type="text/css" href="../../../source/styles/fluent/light/smart.fluent.css" />
<!-- smart.grid.js already bundles sort/filter/pager/edit/group/… -->
<script type="module" src="../../../source/modules/smart.grid.js"></script>
</head>
<body>
<div id="grid"></div>
<script type="module">
window.addEventListener('load', () => {
new Smart.Grid({
dataSource: new Smart.DataAdapter({
dataSource: [
{ id: 1, name: 'Nancy Davolio', position: 'Sales Rep', salary: 60000 },
{ id: 2, name: 'Andrew Fuller', position: 'VP Sales', salary: 95000 },
],
dataFields: [
'id: number',
'name: string',
'position: string',
'salary: number',
],
}),
sortable: true,
filterable: true,
pageable: true,
columns: [
{ label: 'ID', dataField: 'id' },
{ label: 'Name', dataField: 'name' },
{ label: 'Position', dataField: 'position' },
{ label: 'Salary', dataField: 'salary', cellsFormat: 'c0' },
],
appendTo: '#grid',
});
});
</script>
</body>
</html>
Theme application — always layer the overlay on the default base
smart.default.css. It carries the shared variables, layout primitives, and base component styles that all themes build on. Any non-default theme is layered on top, in this order:<link rel="stylesheet" href="…/source/styles/smart.default.css" /> <!-- base -->
<link rel="stylesheet" href="…/source/styles/fluent/light/smart.fluent.css" /> <!-- overlay -->
Theme paths in the source repo are nested. Each non-default theme has its own subfolder under source/styles/<theme>/ with separate light/ and dark/ variants:
| Stylesheet | Source-repo path |
|---|---|
| Base (required) | source/styles/smart.default.css |
| Fluent light | source/styles/fluent/light/smart.fluent.css |
| Fluent dark | source/styles/fluent/dark/smart.fluent-dark.css |
| Material light | source/styles/material/light/smart.material.css |
| Material dark | source/styles/material/dark/smart.material-dark.css |
| Bootstrap | source/styles/bootstrap/light/smart.bootstrap.css |
| Strata / Tabula | source/styles/<theme>/light/smart.<theme>.css |
get_required_scripts(..., { theme: 'fluent' }) returns both URLs already ordered correctly. For dark mode pass dark: true and the overlay flips to the corresponding *-dark.css variant.
The npm-packaged React and Angular distributions flatten the most common themes to the top level (so React's generated code uses smart-webcomponents-react/source/styles/smart.fluent.css directly), but the Vue (smart-webcomponents) package and the source repo both keep the nested layout.
theme="fluent" as an attribute on the component — themes are applied via the CSS stack, not via element attributes. The theme property on a component exists for runtime color-variant switching only.One script tag per component — sub-modules are bundled
Smart UI's top-level smart.<component>.js ES module already imports every sub-module the component needs. For example, smart.grid.js imports smart.grid.sort.js, smart.grid.filter.js, smart.grid.edit.js, smart.grid.pager.js, smart.grid.group.js, and 20+ others — you load the grid with a single <script type="module"> tag.
bundledSubmodules field on get_required_scripts and features field on get_widget show what's included; they're for documentation, not for additional <script> tags.Shorthand attributes vs full configuration
Smart Grid (and many other components) accepts two parallel ways of toggling behaviour. Prefer the shorthand attributes whenever you only need to switch a feature on or off. They produce cleaner, more declarative HTML.
| Shorthand boolean attr | Full-config property |
|---|---|
sortable | sorting = { enabled, mode, … } |
filterable | filtering = { enabled, filterRow, … } |
pageable | paging = { enabled, pageSize, … } |
editable | editing = { enabled, mode, … } |
groupable | grouping = { enabled, mode, … } |
selectable | selection = { enabled, mode, … } |
columnResize | per-column allowResize plus options |
columnReorder | per-column allowReorder plus options |
Switch to the object-form property only when you need to configure how the feature behaves (filter mode, page size, batch-edit, multi-sort, etc.). The MCP surfaces the available shorthand attrs for each component via get_widget (the shorthandAttributes field) — so a prompt like “add sorting and filtering to the grid” reliably produces sortable filterable rather than the longer object form.
SMART_UI_SCRIPTS_PREFIX="/assets/smart-webcomponents/" npx smart-ui-mcp-server
Or pass prefix: "/assets/..." directly in the generate_example call when you're prompting.09Worked tutorial — Scheduler (React)#
<Scheduler> showing Day, Week, and Month views. Use the fluent theme.Behind the scenes
get_widget("scheduler")→ tagsmart-scheduler, classScheduler.get_widget_properties("scheduler", { nameFilter: "view" })→ confirmsview,viewType,views, plus an enum of allowed view-type strings.get_widget_types("scheduler")→ returns theViewenum (day,week,month,agenda,timelineDay…).generate_examplewithframework: "react".
Result
import React from 'react';
import { createRoot } from 'react-dom/client';
// Theme stack: base first, overlay second.
import 'smart-webcomponents-react/source/styles/smart.default.css';
import 'smart-webcomponents-react/source/styles/smart.fluent.css';
import { Scheduler } from 'smart-webcomponents-react/scheduler';
function App() {
return (
<Scheduler
view="week"
views={['day', 'week', 'month']}
/>
);
}
const root = createRoot(document.getElementById('root'));
root.render(<App />);
Grid-family components — use Smart.DataAdapter
For data-driven components (Grid, Chart, Scheduler, CardView, Kanban, GanttChart, PivotTable, QueryBuilder), the React import becomes { Smart, <Component> } and the data source is wrapped in new Smart.DataAdapter({ dataSource, dataFields }):
import { Smart, Grid } from 'smart-webcomponents-react/grid';
function App() {
const dataSource = new Smart.DataAdapter({
dataSource: [
{ id: 1, name: 'Alice', salary: 60000 },
{ id: 2, name: 'Bob', salary: 75000 },
],
dataFields: ['id: number', 'name: string', 'salary: number'],
});
return (
<Grid
dataSource={dataSource}
sortable
filterable
pageable
columns={[
{ label: 'ID', dataField: 'id' },
{ label: 'Name', dataField: 'name' },
{ label: 'Salary', dataField: 'salary', cellsFormat: 'c0' },
]}
/>
);
}
get_widget_properties("scheduler", { nameFilter: "data" }) to find dataSource, then get_demo_code("scheduler", "recurring") to see the recurring-event shape your repo ships, and update the code accordingly.10Worked tutorial — Chart with annotations (Angular)#
The MCP path
get_widget("chart")→ features includeannotations.get_required_scripts("chart", { features: ["annotations"], theme: "fluent" })addssmart.chart.annotations.jsto the module list.get_widget_properties("chart", { nameFilter: "annotation" })→ confirms theannotationsproperty and its shape.generate_examplewithframework: "angular".
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChartComponent, ChartModule } from '@smart-webcomponents-angular/chart';
// angular.json -> "styles": [
// "./node_modules/@smart-webcomponents-angular/chart/styles/smart.base.css",
// "./node_modules/@smart-webcomponents-angular/chart/styles/smart.chart.css",
// "./node_modules/@smart-webcomponents-angular/chart/styles/smart.common.css",
// "./node_modules/@smart-webcomponents-angular/chart/styles/smart.fluent.css" // theme overlay
// ]
@Component({
selector: 'app-root',
standalone: true,
imports: [ChartModule],
template: `<smart-chart #chart></smart-chart>`,
})
export class AppComponent implements AfterViewInit {
@ViewChild('chart', { read: ChartComponent, static: false })
chart!: ChartComponent;
ngAfterViewInit(): void {
this.chart.caption = 'Monthly Sales';
this.chart.seriesGroups = [{
type: 'line',
series: [{ dataField: 'sales', displayText: 'Sales' }],
}];
this.chart.annotations = [{
type: 'line',
xAxis: { value: 0 }, yAxis: { value: 5000 },
xAxisEnd: { value: 11 }, yAxisEnd: { value: 5000 },
lineColor: '#d33', lineWidth: 2,
}];
}
}
<smart-*> element with a template-ref, then configure imperatively in ngAfterViewInit(). This matches every shipped Angular demo and avoids two-way binding pitfalls with object properties.@smart-webcomponents-angular/grid, @smart-webcomponents-angular/chart, etc. Each per-component package ships its own self-contained styles/ folder (smart.base.css + smart.<component>.css + smart.common.css); add all three to angular.json "styles", plus optionally smart.<theme>.css from the same folder for the theme overlay.11Worked tutorial — Tree + context menu (composition)#
This is the most ambitious type of prompt — the assistant composes two components.
smart-tree showing folders. Wire a smart-menu as a right-click context menu with Add / Rename / Delete actions.The MCP path
get_widget("tree")— confirmssmart-treewithallowDrag,filterable,selectionMode.get_widget("menu")— confirmssmart-menuwithmode="dropDown"and aselectevent.get_widget_events("tree", { nameFilter: "context" })— finds an event the assistant can use to position the menu, or falls back to the nativecontextmenuDOM event.list_demos("tree")— looks for any shipped right-click pattern; if one exists,get_demo_codereads it.generate_exampleis called twice — once fortree, once formenu— and the assistant manually composes them in one HTML file.
The output combines the two generated stubs with a contextmenu listener on the tree that opens the menu at the click coordinates and dispatches the selected action.
12Prompt patterns — a cheat sheet#
The MCP works best when your prompt includes:
- An explicit “Use the smart-ui MCP” — primes the assistant to call the tools instead of guessing.
- A target framework —
webcomponents,react,angular,vue, orblazor. - A theme name if you care —
default,fluent,material,bootstrap,strata,tabula. - The features you want by name — e.g. “sorting, paging, filtering, row grouping”. The assistant will resolve these to the right feature modules via
get_required_scripts.
Templates
Generate from scratch
Adapt a shipped demo
API exploration
Migration / fix
13Configuration reference#
All env vars are optional.
| Variable | Default | Purpose |
|---|---|---|
SMART_UI_REPO_ROOT | unset | Path to a local Smart UI checkout. Enables list_demos, get_demo_code, list_documentation, get_documentation, and live feature/theme discovery. |
SMART_UI_SCRIPTS_PREFIX | ../../../source/ | Prefix injected into generated <script> / <link> URLs. |
SMART_UI_REACT_PACKAGE | smart-webcomponents-react | npm package name used in React imports. |
SMART_UI_ANGULAR_PACKAGE | smart-webcomponents-angular | npm package name used in Angular imports. |
SMART_UI_VUE_PACKAGE | smart-webcomponents | npm package name used in Vue imports. |
Setting env vars per-client
Most MCP clients pass through env vars from your shell. To set them per-server (instead of globally), use the env field in the client config:
{
"mcpServers": {
"smart-ui": {
"command": "npx",
"args": ["smart-ui-mcp-server"],
"env": {
"SMART_UI_REPO_ROOT": "/Users/me/code/smart-ui-repo",
"SMART_UI_SCRIPTS_PREFIX": "/assets/smart/"
}
}
}
}
14Local development & contributing#
git clone <repo>
cd smart-ui-mcp-server
npm install
# rebuild the bundled snapshot from a Smart UI checkout
SMART_UI_REPO_ROOT=/path/to/Team npm run build-data
# run the 45-test smoke suite
SMART_UI_REPO_ROOT=/path/to/Team npm test
# run the server interactively (for hand-rolled JSON-RPC probing)
npm start
Adding a new tool
- Implement the logic in
src/<area>.js(or a new module). - Register it in
src/server.jswithserver.registerTool(...). Use Zod to declare the input schema. - Add a smoke test in
test/smoke.js. - Update
README.mdand this tutorial's tools table.
Updating the bundled API metadata
Whenever Smart UI ships new components or new properties:
SMART_UI_REPO_ROOT=/path/to/Team npm run build-data
This refreshes data/api/*.json, data/features.json, data/themes.json, data/widget-scripts.json, and data/snapshot.json.
15Troubleshooting#
“Tool not found” / the assistant doesn't see Smart UI
- Restart the assistant after editing the MCP config.
- Confirm the config file path is the one your assistant actually reads (Claude Desktop on Windows is
%APPDATA%\Claude\, not%LOCALAPPDATA%). - Run
npx smart-ui-mcp-serverfrom a terminal — if it starts without errors, the binary is fine and the issue is in your client config.
“Smart UI API metadata not found”
The bundled snapshot lives in data/api/. If you installed via npm install and still see this, your install was incomplete. Reinstall:
npm uninstall -g smart-ui-mcp-server
npm install -g smart-ui-mcp-server
If you're running from source, run npm run build-data once.
Generated examples reference modules that don't exist on disk
The default SMART_UI_SCRIPTS_PREFIX (../../../source/) assumes a folder layout like <repo>/demos/<widget>/<example>/index.html with Smart UI sources at <repo>/source/. If your project layout differs, override the prefix — see Configuration reference.
list_demos returns an empty array
The demos browser only works against a local Smart UI checkout. Set SMART_UI_REPO_ROOT to a folder that contains a demos/ (and optionally react/demos/, smart-angular/demos/, vue/vue-3/demos/) subfolder.
The assistant emits the wrong tag name
If the generated code uses an unfamiliar prefix or a tag that doesn't start with smart-, the assistant is guessing instead of calling the MCP. Re-prompt with:
get_widget for each component you reference and use the exact tag field it returns.“Unknown widget” errors
Smart UI uses kebab-case multi-word tags. If you call getWidget("dropdown-list") or "DropDownList" it resolves fine; if you misspell ("dropdownllist") it returns an error. Run list_widgets({ filter: "drop" }) to find the right id.
16FAQ#
Does this require an Anthropic API key / Claude subscription?
No. The MCP server itself is plain Node.js with no API calls. It only provides knowledge to whatever assistant you've connected — that assistant provides its own model.
Does it work offline?
Yes. After npm install, all metadata is on disk. No network calls at runtime.
Can I use it with my own private Smart UI fork?
Yes. Set SMART_UI_REPO_ROOT to your fork's root, and either run npm run build-data to refresh the bundled snapshot, or leave it pointed at the live fork — the server reads JSON / source / demos / docs directly. You can also override the npm package names emitted in generated React / Angular / Vue code via SMART_UI_REACT_PACKAGE etc.
Does it cover Smart UI for Blazor too?
Yes — generate_example with framework: "blazor" emits Razor markup using @using Smart.Blazor and PascalCased element tags (<Button Value="…" />).
Can I add my own custom-component metadata?
Yes. Drop additional <slug>.json files into the data folder your SMART_UI_REPO_ROOT points at and rerun npm run build-data. The server picks them up alongside the official components — they're available through every tool just like the built-ins.
How big is the bundled snapshot?
~4 MB unpacked, ~720 KB packed. The bulk is the per-component API JSON.
How do I report a bug?
Open an issue at github.com/HTMLElements/smart-webcomponents/issues with: the prompt you used, the tool call(s) the assistant made, the actual vs expected output, and your assistant + MCP server versions.