@staffbase/design-mcp 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/dist/data/components.json +1118 -0
- package/dist/data/docs.json +226 -0
- package/dist/data/icons.json +2344 -0
- package/dist/data/meta.json +4 -0
- package/dist/data/package_instructions.md +187 -0
- package/dist/data/tokens.json +4449 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +451 -0
- package/dist/server.js.map +1 -0
- package/package.json +48 -0
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/server.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
|
|
7
|
+
// src/data/load.ts
|
|
8
|
+
import { readFileSync } from "fs";
|
|
9
|
+
import { dirname, join } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
function resolveDataDir() {
|
|
13
|
+
const candidates = [
|
|
14
|
+
join(here, "data"),
|
|
15
|
+
// dist/server.js → dist/data
|
|
16
|
+
join(here, "..", "..", "dist", "data")
|
|
17
|
+
// src/data/load.ts → packages/design-mcp/dist/data
|
|
18
|
+
];
|
|
19
|
+
for (const candidate of candidates) {
|
|
20
|
+
try {
|
|
21
|
+
readFileSync(join(candidate, "meta.json"), "utf8");
|
|
22
|
+
return candidate;
|
|
23
|
+
} catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`Could not locate @staffbase/design-mcp data directory. Tried: ${candidates.join(", ")}`);
|
|
28
|
+
}
|
|
29
|
+
var dataDir = resolveDataDir();
|
|
30
|
+
var cache;
|
|
31
|
+
function read(filename) {
|
|
32
|
+
return JSON.parse(readFileSync(join(dataDir, filename), "utf8"));
|
|
33
|
+
}
|
|
34
|
+
function loadManifest() {
|
|
35
|
+
if (cache) return cache;
|
|
36
|
+
const components = read("components.json");
|
|
37
|
+
const tokens = read("tokens.json");
|
|
38
|
+
const icons = read("icons.json");
|
|
39
|
+
const docs = read("docs.json");
|
|
40
|
+
const meta = read("meta.json");
|
|
41
|
+
const guide = readFileSync(join(dataDir, "package_instructions.md"), "utf8");
|
|
42
|
+
cache = {
|
|
43
|
+
components,
|
|
44
|
+
tokens,
|
|
45
|
+
icons,
|
|
46
|
+
docs,
|
|
47
|
+
guide,
|
|
48
|
+
generatedAt: meta.generatedAt,
|
|
49
|
+
designVersion: meta.designVersion
|
|
50
|
+
};
|
|
51
|
+
return cache;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/tools/components.ts
|
|
55
|
+
import { z } from "zod";
|
|
56
|
+
|
|
57
|
+
// src/util/json.ts
|
|
58
|
+
function jsonResult(data) {
|
|
59
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
60
|
+
}
|
|
61
|
+
function textResult(text) {
|
|
62
|
+
return { content: [{ type: "text", text }] };
|
|
63
|
+
}
|
|
64
|
+
function errorResult(message) {
|
|
65
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/util/match.ts
|
|
69
|
+
function ciIncludes(haystack, needle) {
|
|
70
|
+
return haystack.toLowerCase().includes(needle.toLowerCase());
|
|
71
|
+
}
|
|
72
|
+
function ciEquals(a, b) {
|
|
73
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/tools/components.ts
|
|
77
|
+
function registerComponentTools(server) {
|
|
78
|
+
server.tool(
|
|
79
|
+
"list_components",
|
|
80
|
+
"List every component published by @staffbase/design. Returns name, category, short description, deprecation flag, compound subcomponent names, and whether a published doc page exists. Always use this before fabricating a component name.",
|
|
81
|
+
{},
|
|
82
|
+
() => {
|
|
83
|
+
const { components } = loadManifest();
|
|
84
|
+
const summary = components.map((c) => ({
|
|
85
|
+
name: c.name,
|
|
86
|
+
category: c.category,
|
|
87
|
+
description: c.description,
|
|
88
|
+
deprecated: c.deprecated,
|
|
89
|
+
replacement: c.replacement,
|
|
90
|
+
subcomponents: c.compoundMembers.map((m) => m.name),
|
|
91
|
+
hasDocPage: Boolean(c.docPage)
|
|
92
|
+
}));
|
|
93
|
+
return jsonResult(summary);
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
server.tool(
|
|
97
|
+
"get_component",
|
|
98
|
+
"Get the full record for one component: TypeScript props interface, compound anatomy (Dialog.Root / Dialog.Trigger / ...), the published anatomy snippet, available example variant labels, deprecation status with suggested replacement, source path, and Figma URL. Use to confirm prop names and required a11y attributes before generating code.",
|
|
99
|
+
{
|
|
100
|
+
name: z.string().describe('Component name as exported from @staffbase/design (case sensitive, e.g. "Button", "Dialog").')
|
|
101
|
+
},
|
|
102
|
+
({ name }) => {
|
|
103
|
+
const { components } = loadManifest();
|
|
104
|
+
const match = components.find((c) => ciEquals(c.name, name));
|
|
105
|
+
if (!match) {
|
|
106
|
+
return errorResult(`Unknown component "${name}". Call list_components to see available names.`);
|
|
107
|
+
}
|
|
108
|
+
const { examples, ...rest } = match;
|
|
109
|
+
return jsonResult({
|
|
110
|
+
...rest,
|
|
111
|
+
availableVariants: examples.map((e) => e.variant)
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/tools/docs.ts
|
|
118
|
+
import { z as z2 } from "zod";
|
|
119
|
+
function registerDocTools(server) {
|
|
120
|
+
server.tool(
|
|
121
|
+
"get_doc_page",
|
|
122
|
+
"Return the rendered markdown of one Astro docs page (the same content published at design.staffbase.rocks). Use for prose context that doesn't fit the structured per-component / per-token tools: getting-started, foundation overviews, future patterns pages.",
|
|
123
|
+
{
|
|
124
|
+
slug: z2.string().describe(
|
|
125
|
+
'Page slug without leading slash and without .mdx extension. Examples: "getting-started", "components/button", "foundation/tokens/colors".'
|
|
126
|
+
)
|
|
127
|
+
},
|
|
128
|
+
({ slug }) => {
|
|
129
|
+
const { docs } = loadManifest();
|
|
130
|
+
const normalized = slug.replace(/^\/+/, "").replace(/\.mdx$/, "");
|
|
131
|
+
const match = docs.find((d) => ciEquals(d.slug, normalized));
|
|
132
|
+
if (!match) {
|
|
133
|
+
return errorResult(`Unknown doc slug "${slug}". Examples: "components/button", "foundation/tokens/colors".`);
|
|
134
|
+
}
|
|
135
|
+
const header = `# ${match.title}
|
|
136
|
+
|
|
137
|
+
${match.description ?? ""}`.trim();
|
|
138
|
+
return textResult(`${header}
|
|
139
|
+
|
|
140
|
+
${match.body}`);
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
server.tool(
|
|
144
|
+
"get_guide",
|
|
145
|
+
"Return the Staffbase Design System AI-agent guide (docs/package_instructions.md): deprecation map, compound anatomy patterns, form-error Pattern A vs B, icon and token conventions, common mistakes to avoid. Read this once before generating non-trivial design-system code.",
|
|
146
|
+
{},
|
|
147
|
+
() => {
|
|
148
|
+
const { guide } = loadManifest();
|
|
149
|
+
return textResult(guide);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/tools/examples.ts
|
|
155
|
+
import { z as z3 } from "zod";
|
|
156
|
+
function registerExampleTool(server) {
|
|
157
|
+
server.tool(
|
|
158
|
+
"get_component_example",
|
|
159
|
+
"Return one curated code example for a component, copied verbatim from the published docs (apps/astro/src/pages). Without `variant` returns the canonical preview at the top of the page; with `variant` returns the example under the matching `### Heading` in the Examples section. Call get_component first to see availableVariants.",
|
|
160
|
+
{
|
|
161
|
+
name: z3.string().describe("Component name as exported from @staffbase/design."),
|
|
162
|
+
variant: z3.string().optional().describe("Variant label from availableVariants. Omit for the default example.")
|
|
163
|
+
},
|
|
164
|
+
({ name, variant }) => {
|
|
165
|
+
const { components } = loadManifest();
|
|
166
|
+
const match = components.find((c) => ciEquals(c.name, name));
|
|
167
|
+
if (!match) {
|
|
168
|
+
return errorResult(`Unknown component "${name}". Call list_components to see available names.`);
|
|
169
|
+
}
|
|
170
|
+
if (match.examples.length === 0) {
|
|
171
|
+
return errorResult(
|
|
172
|
+
`Component "${match.name}" has no published examples. Try get_component for prop info, or get_doc_page("components/${match.docPage ?? ""}") for prose.`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
const wanted = variant ? match.examples.find((e) => ciEquals(e.variant, variant)) : match.examples[0];
|
|
176
|
+
if (!wanted) {
|
|
177
|
+
const labels = match.examples.map((e) => e.variant).join(", ");
|
|
178
|
+
return errorResult(`No example variant "${variant}" for ${match.name}. Available: ${labels}.`);
|
|
179
|
+
}
|
|
180
|
+
return textResult(wanted.code);
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/tools/icons.ts
|
|
186
|
+
import { z as z4 } from "zod";
|
|
187
|
+
function registerIconTools(server) {
|
|
188
|
+
server.tool(
|
|
189
|
+
"list_icons",
|
|
190
|
+
"List the icon catalog. Filter by `search` which matches the icon name or any tag. Use this before importing an icon to confirm it exists and to find its React component name (e.g. ChevronDownIcon).",
|
|
191
|
+
{
|
|
192
|
+
search: z4.string().optional()
|
|
193
|
+
},
|
|
194
|
+
({ search }) => {
|
|
195
|
+
const { icons } = loadManifest();
|
|
196
|
+
const filtered = icons.filter((i) => {
|
|
197
|
+
if (search) {
|
|
198
|
+
const needle = search.toLowerCase();
|
|
199
|
+
const inName = i.name.toLowerCase().includes(needle);
|
|
200
|
+
const inTags = i.tags.some((t) => t.toLowerCase().includes(needle));
|
|
201
|
+
if (!inName && !inTags) return false;
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
});
|
|
205
|
+
return jsonResult(
|
|
206
|
+
filtered.map((i) => ({
|
|
207
|
+
name: i.name,
|
|
208
|
+
componentName: i.componentName,
|
|
209
|
+
tags: i.tags
|
|
210
|
+
}))
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
server.tool(
|
|
215
|
+
"get_icon",
|
|
216
|
+
'Get one icon by its kebab-case name (e.g. "chevron-down") or PascalCase component name (e.g. "ChevronDownIcon"). Returns the React component name and tags.',
|
|
217
|
+
{ name: z4.string() },
|
|
218
|
+
({ name }) => {
|
|
219
|
+
const { icons } = loadManifest();
|
|
220
|
+
const match = icons.find((i) => ciEquals(i.name, name) || ciEquals(i.componentName, name));
|
|
221
|
+
if (!match) {
|
|
222
|
+
return errorResult(`Unknown icon "${name}". Use list_icons with a search filter to find one.`);
|
|
223
|
+
}
|
|
224
|
+
return jsonResult(match);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/tools/search.ts
|
|
230
|
+
import { z as z5 } from "zod";
|
|
231
|
+
function scoreText(text, needle) {
|
|
232
|
+
if (!text) return 0;
|
|
233
|
+
const lower = text.toLowerCase();
|
|
234
|
+
if (lower === needle) return 100;
|
|
235
|
+
if (lower.startsWith(needle)) return 60;
|
|
236
|
+
if (lower.includes(needle)) return 30;
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
function registerSearchTool(server) {
|
|
240
|
+
server.tool(
|
|
241
|
+
"search_design_system",
|
|
242
|
+
"Fuzzy search across components, tokens, icons (name + tags), and the full text of every published doc page. Returns ranked hits with their kind (component/token/icon/doc) so the agent can pick a follow-up tool to call.",
|
|
243
|
+
{ query: z5.string() },
|
|
244
|
+
({ query }) => {
|
|
245
|
+
const needle = query.trim().toLowerCase();
|
|
246
|
+
if (!needle) return jsonResult([]);
|
|
247
|
+
const { components, tokens, icons, docs, guide } = loadManifest();
|
|
248
|
+
const hits = [];
|
|
249
|
+
for (const c of components) {
|
|
250
|
+
const score = Math.max(scoreText(c.name, needle) * 2, scoreText(c.description, needle));
|
|
251
|
+
if (score > 0) {
|
|
252
|
+
hits.push({
|
|
253
|
+
kind: "component",
|
|
254
|
+
title: c.name,
|
|
255
|
+
detail: c.description,
|
|
256
|
+
href: c.docPage,
|
|
257
|
+
score
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
for (const t of tokens) {
|
|
262
|
+
const score = scoreText(t.name, needle);
|
|
263
|
+
if (score > 0) {
|
|
264
|
+
hits.push({
|
|
265
|
+
kind: "token",
|
|
266
|
+
title: t.name,
|
|
267
|
+
detail: `${t.layer} \xB7 ${t.value}`,
|
|
268
|
+
href: t.docPage,
|
|
269
|
+
score
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
for (const i of icons) {
|
|
274
|
+
const nameScore = scoreText(i.name, needle) * 1.5;
|
|
275
|
+
const tagScore = i.tags.reduce((acc, tag) => Math.max(acc, scoreText(tag, needle)), 0);
|
|
276
|
+
const score = Math.max(nameScore, tagScore);
|
|
277
|
+
if (score > 0) {
|
|
278
|
+
hits.push({
|
|
279
|
+
kind: "icon",
|
|
280
|
+
title: i.name,
|
|
281
|
+
detail: i.componentName,
|
|
282
|
+
score
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (const d of docs) {
|
|
287
|
+
const score = Math.max(
|
|
288
|
+
scoreText(d.title, needle) * 1.5,
|
|
289
|
+
scoreText(d.description, needle),
|
|
290
|
+
d.body.toLowerCase().includes(needle) ? 20 : 0
|
|
291
|
+
);
|
|
292
|
+
if (score > 0) {
|
|
293
|
+
hits.push({
|
|
294
|
+
kind: "doc",
|
|
295
|
+
title: d.title,
|
|
296
|
+
detail: d.description,
|
|
297
|
+
href: d.slug,
|
|
298
|
+
score
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (guide.toLowerCase().includes(needle)) {
|
|
303
|
+
hits.push({
|
|
304
|
+
kind: "doc",
|
|
305
|
+
title: "package_instructions.md (AI-agent guide)",
|
|
306
|
+
detail: "Read with get_guide",
|
|
307
|
+
score: 25
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
hits.sort((a, b) => b.score - a.score);
|
|
311
|
+
return jsonResult(hits.slice(0, 40));
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/tools/tokens.ts
|
|
317
|
+
import { z as z6 } from "zod";
|
|
318
|
+
function resolveChain(tokens, start) {
|
|
319
|
+
const chain = [start];
|
|
320
|
+
const seen = /* @__PURE__ */ new Set([start.name]);
|
|
321
|
+
let cursor = start;
|
|
322
|
+
for (; ; ) {
|
|
323
|
+
const ref = cursor.value.match(/^\{(.+)\}$/);
|
|
324
|
+
if (!ref) break;
|
|
325
|
+
const refName = ref[1] ?? "";
|
|
326
|
+
const next = tokens.find((t) => t.name === refName);
|
|
327
|
+
if (!next || seen.has(next.name)) break;
|
|
328
|
+
chain.push(next);
|
|
329
|
+
seen.add(next.name);
|
|
330
|
+
cursor = next;
|
|
331
|
+
}
|
|
332
|
+
return chain;
|
|
333
|
+
}
|
|
334
|
+
function registerTokenTools(server) {
|
|
335
|
+
server.tool(
|
|
336
|
+
"list_tokens",
|
|
337
|
+
'List design tokens. Filter by `layer` (primitive | semantic | component) and/or `category` (e.g. "color", "background", "border", "text", "button"). Prefer the most semantic layer that does the job; use primitive tokens only for raw values.',
|
|
338
|
+
{
|
|
339
|
+
layer: z6.enum(["primitive", "semantic", "component"]).optional(),
|
|
340
|
+
category: z6.string().optional()
|
|
341
|
+
},
|
|
342
|
+
({ layer, category }) => {
|
|
343
|
+
const { tokens } = loadManifest();
|
|
344
|
+
const filtered = tokens.filter(
|
|
345
|
+
(t) => (!layer || t.layer === layer) && (!category || ciIncludes(t.category, category))
|
|
346
|
+
);
|
|
347
|
+
return jsonResult(filtered);
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
server.tool(
|
|
351
|
+
"get_token",
|
|
352
|
+
"Resolve one token by name. Returns the token plus its resolution chain (e.g. a semantic token resolves to a primitive). Use to verify a token exists before referencing it in CSS or component code.",
|
|
353
|
+
{
|
|
354
|
+
name: z6.string().describe('Dot-separated token name, e.g. "text.color.critical.strong" or "color.blue.500".')
|
|
355
|
+
},
|
|
356
|
+
({ name }) => {
|
|
357
|
+
const { tokens } = loadManifest();
|
|
358
|
+
const start = tokens.find((t) => ciEquals(t.name, name));
|
|
359
|
+
if (!start) {
|
|
360
|
+
return errorResult(`Unknown token "${name}". Call list_tokens to discover available names.`);
|
|
361
|
+
}
|
|
362
|
+
const chain = resolveChain(tokens, start);
|
|
363
|
+
return jsonResult({ token: start, chain });
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/server.ts
|
|
369
|
+
function registerAll(server) {
|
|
370
|
+
registerComponentTools(server);
|
|
371
|
+
registerExampleTool(server);
|
|
372
|
+
registerTokenTools(server);
|
|
373
|
+
registerIconTools(server);
|
|
374
|
+
registerDocTools(server);
|
|
375
|
+
registerSearchTool(server);
|
|
376
|
+
registerResources(server);
|
|
377
|
+
}
|
|
378
|
+
function createServer() {
|
|
379
|
+
const server = new McpServer(
|
|
380
|
+
{ name: "staffbase-design", version: "18.0.0" },
|
|
381
|
+
{
|
|
382
|
+
instructions: "MCP server for the Staffbase Design System (@staffbase/design). Tools expose components, props, tokens, icons, and the published docs site. Call `get_guide` once at the start of non-trivial work for the deprecation map and compound-component patterns. Use `list_components` / `list_tokens` / `list_icons` before assuming a name exists."
|
|
383
|
+
}
|
|
384
|
+
);
|
|
385
|
+
registerAll(server);
|
|
386
|
+
return server;
|
|
387
|
+
}
|
|
388
|
+
function registerResources(server) {
|
|
389
|
+
server.resource(
|
|
390
|
+
"staffbase-design-guide",
|
|
391
|
+
"staffbase-design://guide",
|
|
392
|
+
{
|
|
393
|
+
description: "docs/package_instructions.md verbatim. Mirrors the get_guide tool for clients that surface MCP resources.",
|
|
394
|
+
mimeType: "text/markdown"
|
|
395
|
+
},
|
|
396
|
+
() => {
|
|
397
|
+
const { guide } = loadManifest();
|
|
398
|
+
return {
|
|
399
|
+
contents: [
|
|
400
|
+
{
|
|
401
|
+
uri: "staffbase-design://guide",
|
|
402
|
+
mimeType: "text/markdown",
|
|
403
|
+
text: guide
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
const { docs } = loadManifest();
|
|
410
|
+
for (const doc of docs) {
|
|
411
|
+
const uri = `staffbase-design://docs/${doc.slug}`;
|
|
412
|
+
server.resource(
|
|
413
|
+
`staffbase-design-doc-${doc.slug.replace(/\//g, "-")}`,
|
|
414
|
+
uri,
|
|
415
|
+
{
|
|
416
|
+
description: `${doc.title}${doc.description ? ` \u2014 ${doc.description}` : ""}`,
|
|
417
|
+
mimeType: "text/markdown"
|
|
418
|
+
},
|
|
419
|
+
() => ({
|
|
420
|
+
contents: [
|
|
421
|
+
{
|
|
422
|
+
uri,
|
|
423
|
+
mimeType: "text/markdown",
|
|
424
|
+
text: `# ${doc.title}
|
|
425
|
+
|
|
426
|
+
${doc.description ?? ""}
|
|
427
|
+
|
|
428
|
+
${doc.body}`.trim()
|
|
429
|
+
}
|
|
430
|
+
]
|
|
431
|
+
})
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
async function main() {
|
|
436
|
+
const server = createServer();
|
|
437
|
+
const transport = new StdioServerTransport();
|
|
438
|
+
await server.connect(transport);
|
|
439
|
+
}
|
|
440
|
+
var invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
|
|
441
|
+
if (invokedDirectly) {
|
|
442
|
+
main().catch((err) => {
|
|
443
|
+
console.error("staffbase-design-mcp failed to start:", err);
|
|
444
|
+
process.exit(1);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
export {
|
|
448
|
+
createServer,
|
|
449
|
+
registerAll
|
|
450
|
+
};
|
|
451
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/data/load.ts","../src/tools/components.ts","../src/util/json.ts","../src/util/match.ts","../src/tools/docs.ts","../src/tools/examples.ts","../src/tools/icons.ts","../src/tools/search.ts","../src/tools/tokens.ts"],"sourcesContent":["import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport {loadManifest} from './data/load.js';\nimport {registerComponentTools} from './tools/components.js';\nimport {registerDocTools} from './tools/docs.js';\nimport {registerExampleTool} from './tools/examples.js';\nimport {registerIconTools} from './tools/icons.js';\nimport {registerSearchTool} from './tools/search.js';\nimport {registerTokenTools} from './tools/tokens.js';\n\nexport function registerAll(server: McpServer): void {\n registerComponentTools(server);\n registerExampleTool(server);\n registerTokenTools(server);\n registerIconTools(server);\n registerDocTools(server);\n registerSearchTool(server);\n registerResources(server);\n}\n\nexport function createServer(): McpServer {\n const server = new McpServer(\n {name: 'staffbase-design', version: '18.0.0'},\n {\n instructions:\n 'MCP server for the Staffbase Design System (@staffbase/design). Tools expose components, props, tokens, icons, and the published docs site. Call `get_guide` once at the start of non-trivial work for the deprecation map and compound-component patterns. Use `list_components` / `list_tokens` / `list_icons` before assuming a name exists.',\n },\n );\n registerAll(server);\n return server;\n}\n\nfunction registerResources(server: McpServer): void {\n server.resource(\n 'staffbase-design-guide',\n 'staffbase-design://guide',\n {\n description:\n 'docs/package_instructions.md verbatim. Mirrors the get_guide tool for clients that surface MCP resources.',\n mimeType: 'text/markdown',\n },\n () => {\n const {guide} = loadManifest();\n return {\n contents: [\n {\n uri: 'staffbase-design://guide',\n mimeType: 'text/markdown',\n text: guide,\n },\n ],\n };\n },\n );\n\n const {docs} = loadManifest();\n for (const doc of docs) {\n const uri = `staffbase-design://docs/${doc.slug}`;\n server.resource(\n `staffbase-design-doc-${doc.slug.replace(/\\//g, '-')}`,\n uri,\n {\n description: `${doc.title}${doc.description ? ` — ${doc.description}` : ''}`,\n mimeType: 'text/markdown',\n },\n () => ({\n contents: [\n {\n uri,\n mimeType: 'text/markdown',\n text: `# ${doc.title}\\n\\n${doc.description ?? ''}\\n\\n${doc.body}`.trim(),\n },\n ],\n }),\n );\n }\n}\n\nasync function main(): Promise<void> {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nconst invokedDirectly = import.meta.url === `file://${process.argv[1]}`;\nif (invokedDirectly) {\n main().catch((err) => {\n console.error('staffbase-design-mcp failed to start:', err);\n process.exit(1);\n });\n}\n","import {readFileSync} from 'node:fs';\nimport {dirname, join} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nimport type {DocPage, IconRecord, ManifestData, TokenRecord} from './types.js';\nimport type {ComponentRecord} from './types.js';\n\nconst here = dirname(fileURLToPath(import.meta.url));\n// `here` is `dist/` when running the bundled server, and `src/data/` when\n// running from sources via tsx. In both cases data lives under `dist/data/`.\nfunction resolveDataDir(): string {\n const candidates = [\n join(here, 'data'), // dist/server.js → dist/data\n join(here, '..', '..', 'dist', 'data'), // src/data/load.ts → packages/design-mcp/dist/data\n ];\n for (const candidate of candidates) {\n try {\n readFileSync(join(candidate, 'meta.json'), 'utf8');\n return candidate;\n } catch {\n continue;\n }\n }\n throw new Error(`Could not locate @staffbase/design-mcp data directory. Tried: ${candidates.join(', ')}`);\n}\n\nconst dataDir = resolveDataDir();\n\nlet cache: ManifestData | undefined;\n\nfunction read<T>(filename: string): T {\n return JSON.parse(readFileSync(join(dataDir, filename), 'utf8')) as T;\n}\n\nexport function loadManifest(): ManifestData {\n if (cache) return cache;\n const components = read<ComponentRecord[]>('components.json');\n const tokens = read<TokenRecord[]>('tokens.json');\n const icons = read<IconRecord[]>('icons.json');\n const docs = read<DocPage[]>('docs.json');\n const meta = read<{generatedAt: string; designVersion: string}>('meta.json');\n const guide = readFileSync(join(dataDir, 'package_instructions.md'), 'utf8');\n cache = {\n components,\n tokens,\n icons,\n docs,\n guide,\n generatedAt: meta.generatedAt,\n designVersion: meta.designVersion,\n };\n return cache;\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport {errorResult, jsonResult} from '../util/json.js';\nimport {ciEquals} from '../util/match.js';\n\nexport function registerComponentTools(server: McpServer): void {\n server.tool(\n 'list_components',\n 'List every component published by @staffbase/design. Returns name, category, short description, deprecation flag, compound subcomponent names, and whether a published doc page exists. Always use this before fabricating a component name.',\n {},\n () => {\n const {components} = loadManifest();\n const summary = components.map((c) => ({\n name: c.name,\n category: c.category,\n description: c.description,\n deprecated: c.deprecated,\n replacement: c.replacement,\n subcomponents: c.compoundMembers.map((m) => m.name),\n hasDocPage: Boolean(c.docPage),\n }));\n return jsonResult(summary);\n },\n );\n\n server.tool(\n 'get_component',\n 'Get the full record for one component: TypeScript props interface, compound anatomy (Dialog.Root / Dialog.Trigger / ...), the published anatomy snippet, available example variant labels, deprecation status with suggested replacement, source path, and Figma URL. Use to confirm prop names and required a11y attributes before generating code.',\n {\n name: z\n .string()\n .describe('Component name as exported from @staffbase/design (case sensitive, e.g. \"Button\", \"Dialog\").'),\n },\n ({name}) => {\n const {components} = loadManifest();\n const match = components.find((c) => ciEquals(c.name, name));\n if (!match) {\n return errorResult(`Unknown component \"${name}\". Call list_components to see available names.`);\n }\n const {examples, ...rest} = match;\n return jsonResult({\n ...rest,\n availableVariants: examples.map((e) => e.variant),\n });\n },\n );\n}\n","export function jsonResult(data: unknown): {\n content: [{type: 'text'; text: string}];\n} {\n return {content: [{type: 'text', text: JSON.stringify(data, null, 2)}]};\n}\n\nexport function textResult(text: string): {\n content: [{type: 'text'; text: string}];\n} {\n return {content: [{type: 'text', text}]};\n}\n\nexport function errorResult(message: string): {\n content: [{type: 'text'; text: string}];\n isError: true;\n} {\n return {content: [{type: 'text', text: message}], isError: true};\n}\n","export function ciIncludes(haystack: string, needle: string): boolean {\n return haystack.toLowerCase().includes(needle.toLowerCase());\n}\n\nexport function ciEquals(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport {errorResult, textResult} from '../util/json.js';\nimport {ciEquals} from '../util/match.js';\n\nexport function registerDocTools(server: McpServer): void {\n server.tool(\n 'get_doc_page',\n \"Return the rendered markdown of one Astro docs page (the same content published at design.staffbase.rocks). Use for prose context that doesn't fit the structured per-component / per-token tools: getting-started, foundation overviews, future patterns pages.\",\n {\n slug: z\n .string()\n .describe(\n 'Page slug without leading slash and without .mdx extension. Examples: \"getting-started\", \"components/button\", \"foundation/tokens/colors\".',\n ),\n },\n ({slug}) => {\n const {docs} = loadManifest();\n const normalized = slug.replace(/^\\/+/, '').replace(/\\.mdx$/, '');\n const match = docs.find((d) => ciEquals(d.slug, normalized));\n if (!match) {\n return errorResult(`Unknown doc slug \"${slug}\". Examples: \"components/button\", \"foundation/tokens/colors\".`);\n }\n const header = `# ${match.title}\\n\\n${match.description ?? ''}`.trim();\n return textResult(`${header}\\n\\n${match.body}`);\n },\n );\n\n server.tool(\n 'get_guide',\n 'Return the Staffbase Design System AI-agent guide (docs/package_instructions.md): deprecation map, compound anatomy patterns, form-error Pattern A vs B, icon and token conventions, common mistakes to avoid. Read this once before generating non-trivial design-system code.',\n {},\n () => {\n const {guide} = loadManifest();\n return textResult(guide);\n },\n );\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport {errorResult, textResult} from '../util/json.js';\nimport {ciEquals} from '../util/match.js';\n\nexport function registerExampleTool(server: McpServer): void {\n server.tool(\n 'get_component_example',\n 'Return one curated code example for a component, copied verbatim from the published docs (apps/astro/src/pages). Without `variant` returns the canonical preview at the top of the page; with `variant` returns the example under the matching `### Heading` in the Examples section. Call get_component first to see availableVariants.',\n {\n name: z.string().describe('Component name as exported from @staffbase/design.'),\n variant: z.string().optional().describe('Variant label from availableVariants. Omit for the default example.'),\n },\n ({name, variant}) => {\n const {components} = loadManifest();\n const match = components.find((c) => ciEquals(c.name, name));\n if (!match) {\n return errorResult(`Unknown component \"${name}\". Call list_components to see available names.`);\n }\n if (match.examples.length === 0) {\n return errorResult(\n `Component \"${match.name}\" has no published examples. Try get_component for prop info, or get_doc_page(\"components/${match.docPage ?? ''}\") for prose.`,\n );\n }\n const wanted = variant ? match.examples.find((e) => ciEquals(e.variant, variant)) : match.examples[0];\n if (!wanted) {\n const labels = match.examples.map((e) => e.variant).join(', ');\n return errorResult(`No example variant \"${variant}\" for ${match.name}. Available: ${labels}.`);\n }\n return textResult(wanted.code);\n },\n );\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport {errorResult, jsonResult} from '../util/json.js';\nimport {ciEquals} from '../util/match.js';\n\nexport function registerIconTools(server: McpServer): void {\n server.tool(\n 'list_icons',\n 'List the icon catalog. Filter by `search` which matches the icon name or any tag. Use this before importing an icon to confirm it exists and to find its React component name (e.g. ChevronDownIcon).',\n {\n search: z.string().optional(),\n },\n ({search}) => {\n const {icons} = loadManifest();\n const filtered = icons.filter((i) => {\n if (search) {\n const needle = search.toLowerCase();\n const inName = i.name.toLowerCase().includes(needle);\n const inTags = i.tags.some((t) => t.toLowerCase().includes(needle));\n if (!inName && !inTags) return false;\n }\n return true;\n });\n return jsonResult(\n filtered.map((i) => ({\n name: i.name,\n componentName: i.componentName,\n tags: i.tags,\n })),\n );\n },\n );\n\n server.tool(\n 'get_icon',\n 'Get one icon by its kebab-case name (e.g. \"chevron-down\") or PascalCase component name (e.g. \"ChevronDownIcon\"). Returns the React component name and tags.',\n {name: z.string()},\n ({name}) => {\n const {icons} = loadManifest();\n const match = icons.find((i) => ciEquals(i.name, name) || ciEquals(i.componentName, name));\n if (!match) {\n return errorResult(`Unknown icon \"${name}\". Use list_icons with a search filter to find one.`);\n }\n return jsonResult(match);\n },\n );\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport {jsonResult} from '../util/json.js';\n\ninterface SearchHit {\n kind: 'component' | 'token' | 'icon' | 'doc';\n title: string;\n detail?: string;\n href?: string;\n score: number;\n}\n\nfunction scoreText(text: string | undefined, needle: string): number {\n if (!text) return 0;\n const lower = text.toLowerCase();\n if (lower === needle) return 100;\n if (lower.startsWith(needle)) return 60;\n if (lower.includes(needle)) return 30;\n return 0;\n}\n\nexport function registerSearchTool(server: McpServer): void {\n server.tool(\n 'search_design_system',\n 'Fuzzy search across components, tokens, icons (name + tags), and the full text of every published doc page. Returns ranked hits with their kind (component/token/icon/doc) so the agent can pick a follow-up tool to call.',\n {query: z.string()},\n ({query}) => {\n const needle = query.trim().toLowerCase();\n if (!needle) return jsonResult([]);\n\n const {components, tokens, icons, docs, guide} = loadManifest();\n const hits: SearchHit[] = [];\n\n for (const c of components) {\n const score = Math.max(scoreText(c.name, needle) * 2, scoreText(c.description, needle));\n if (score > 0) {\n hits.push({\n kind: 'component',\n title: c.name,\n detail: c.description,\n href: c.docPage,\n score,\n });\n }\n }\n\n for (const t of tokens) {\n const score = scoreText(t.name, needle);\n if (score > 0) {\n hits.push({\n kind: 'token',\n title: t.name,\n detail: `${t.layer} · ${t.value}`,\n href: t.docPage,\n score,\n });\n }\n }\n\n for (const i of icons) {\n const nameScore = scoreText(i.name, needle) * 1.5;\n const tagScore = i.tags.reduce((acc, tag) => Math.max(acc, scoreText(tag, needle)), 0);\n const score = Math.max(nameScore, tagScore);\n if (score > 0) {\n hits.push({\n kind: 'icon',\n title: i.name,\n detail: i.componentName,\n score,\n });\n }\n }\n\n for (const d of docs) {\n const score = Math.max(\n scoreText(d.title, needle) * 1.5,\n scoreText(d.description, needle),\n d.body.toLowerCase().includes(needle) ? 20 : 0,\n );\n if (score > 0) {\n hits.push({\n kind: 'doc',\n title: d.title,\n detail: d.description,\n href: d.slug,\n score,\n });\n }\n }\n\n if (guide.toLowerCase().includes(needle)) {\n hits.push({\n kind: 'doc',\n title: 'package_instructions.md (AI-agent guide)',\n detail: 'Read with get_guide',\n score: 25,\n });\n }\n\n hits.sort((a, b) => b.score - a.score);\n return jsonResult(hits.slice(0, 40));\n },\n );\n}\n","import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {z} from 'zod';\n\nimport {loadManifest} from '../data/load.js';\nimport type {TokenRecord} from '../data/types.js';\nimport {errorResult, jsonResult} from '../util/json.js';\nimport {ciEquals, ciIncludes} from '../util/match.js';\n\nfunction resolveChain(tokens: TokenRecord[], start: TokenRecord): TokenRecord[] {\n const chain: TokenRecord[] = [start];\n const seen = new Set<string>([start.name]);\n let cursor: TokenRecord = start;\n for (;;) {\n const ref: RegExpMatchArray | null = cursor.value.match(/^\\{(.+)\\}$/);\n if (!ref) break;\n const refName: string = ref[1] ?? '';\n const next: TokenRecord | undefined = tokens.find((t) => t.name === refName);\n if (!next || seen.has(next.name)) break;\n chain.push(next);\n seen.add(next.name);\n cursor = next;\n }\n return chain;\n}\n\nexport function registerTokenTools(server: McpServer): void {\n server.tool(\n 'list_tokens',\n 'List design tokens. Filter by `layer` (primitive | semantic | component) and/or `category` (e.g. \"color\", \"background\", \"border\", \"text\", \"button\"). Prefer the most semantic layer that does the job; use primitive tokens only for raw values.',\n {\n layer: z.enum(['primitive', 'semantic', 'component']).optional(),\n category: z.string().optional(),\n },\n ({layer, category}) => {\n const {tokens} = loadManifest();\n const filtered = tokens.filter(\n (t) => (!layer || t.layer === layer) && (!category || ciIncludes(t.category, category)),\n );\n return jsonResult(filtered);\n },\n );\n\n server.tool(\n 'get_token',\n 'Resolve one token by name. Returns the token plus its resolution chain (e.g. a semantic token resolves to a primitive). Use to verify a token exists before referencing it in CSS or component code.',\n {\n name: z.string().describe('Dot-separated token name, e.g. \"text.color.critical.strong\" or \"color.blue.500\".'),\n },\n ({name}) => {\n const {tokens} = loadManifest();\n const start = tokens.find((t) => ciEquals(t.name, name));\n if (!start) {\n return errorResult(`Unknown token \"${name}\". Call list_tokens to discover available names.`);\n }\n const chain = resolveChain(tokens, start);\n return jsonResult({token: start, chain});\n },\n );\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@staffbase/design-mcp",
|
|
3
|
+
"version": "19.0.0",
|
|
4
|
+
"description": "Model Context Protocol server for the Staffbase Design System: exposes components, tokens, icons, and docs to AI coding agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsup && pnpm run build:data",
|
|
8
|
+
"build:data": "tsx scripts/build-data.ts",
|
|
9
|
+
"dev": "pnpm run build:data && tsx src/server.ts",
|
|
10
|
+
"lint": "eslint --cache .",
|
|
11
|
+
"pretest": "pnpm run build:data",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"type:check": "tsc -p tsconfig.json"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"staffbase-design-mcp": "./dist/server.js"
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/server.js",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/server.d.ts",
|
|
22
|
+
"import": "./dist/server.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/**",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
31
|
+
"gray-matter": "^4.0.3",
|
|
32
|
+
"ts-morph": "^24.0.0",
|
|
33
|
+
"zod": "^4.4.3"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@repo/eslint-config": "workspace:*",
|
|
37
|
+
"@staffbase/design": "workspace:*",
|
|
38
|
+
"@types/node": "^25.9.2",
|
|
39
|
+
"eslint": "^10.4.1",
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"tsx": "^4.22.4",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.1.8"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
}
|
|
48
|
+
}
|