@getflip/swirl-mcp 0.3.0 → 0.4.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 CHANGED
@@ -32,12 +32,17 @@ Add to your MCP settings:
32
32
  }
33
33
  ```
34
34
 
35
- ## Local testing
35
+ ## Local development
36
+
37
+ Inspect the server with the
38
+ [MCP Inspector](https://github.com/modelcontextprotocol/inspector) over either
39
+ transport. Prepend `SWIRL_AI_LOCAL=1` to either command to load artifacts
40
+ from the local monorepo instead of the unpkg CDN.
36
41
 
37
42
  ### stdio
38
43
 
39
44
  ```sh
40
- npx @modelcontextprotocol/inspector node dist/transports/stdio.js
45
+ SWIRL_AI_LOCAL=1 npx @modelcontextprotocol/inspector node dist/transports/stdio.js
41
46
  ```
42
47
 
43
48
  ### HTTP
@@ -46,20 +51,31 @@ Start the server, then open the Inspector and connect with transport type
46
51
  "Streamable HTTP" and URL `http://localhost:3000/mcp`:
47
52
 
48
53
  ```sh
49
- npx tsx src/transports/http.ts
54
+ SWIRL_AI_LOCAL=1 npx tsx src/transports/http.ts
50
55
  npx @modelcontextprotocol/inspector
51
56
  ```
52
57
 
58
+ ### `SWIRL_AI_LOCAL`
59
+
60
+ When set, agent artifacts are read from `packages/swirl-ai/dist/agent` and
61
+ component source (`get_component_source`) is read from
62
+ `packages/swirl-components/src/components/<tag>/<tag>.{tsx,css}`. The
63
+ `version` parameter is ignored for cache keying. Make sure swirl-ai has been
64
+ built (`pnpm --filter @getflip/swirl-ai build`).
65
+
53
66
  ## Tools
54
67
 
55
- | Tool | Description |
56
- | ------------------------- | ---------------------------------------------------------------------------- |
57
- | **list_components** | Lists all Swirl UI components with brief summaries and related components. |
58
- | **list_icons** | Lists all Swirl icon components. |
59
- | **list_symbols** | Lists all Swirl symbol components. |
60
- | **get_component_details** | Full component docs: props, events, slots, examples, and accessibility info. |
61
- | **get_component_source** | Versioned original TSX and CSS source for a specific component. |
62
- | **get_started** | Installation and setup guide for Web Components, Angular, and React. |
68
+ | Tool | Description |
69
+ | ---------------------------- | ---------------------------------------------------------------------------- |
70
+ | **list_components** | Lists all Swirl UI components with brief summaries and related components. |
71
+ | **list_icons** | Lists all Swirl icon components. |
72
+ | **list_symbols** | Lists all Swirl symbol components. |
73
+ | **get_component_details** | Full component docs: props, events, slots, examples, and accessibility info. |
74
+ | **get_component_source** | Versioned original TSX and CSS source for a specific component. |
75
+ | **list_color_tokens** | Lists Swirl color tokens (light + dark) as CSS / SCSS / Tailwind keys. |
76
+ | **list_typography_tokens** | Lists Swirl typography tokens as CSS / SCSS / Tailwind keys. |
77
+ | **list_layout_tokens** | Lists Swirl layout tokens (spacing, radius, shadow, z-index, blur). |
78
+ | **get_started** | Installation and setup guide for Web Components, Angular, and React. |
63
79
 
64
80
  All tools accept a `version` parameter matching the installed
65
81
  `@getflip/swirl-components` version.
@@ -3,8 +3,67 @@
3
3
  // src/create-server.ts
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
 
6
+ // package.json
7
+ var package_default = {
8
+ name: "@getflip/swirl-mcp",
9
+ version: "0.4.0",
10
+ description: "MCP server for Swirl Design System \u2014 lets AI agents discover and use Swirl components",
11
+ author: "Flip GmbH",
12
+ repository: {
13
+ type: "git",
14
+ url: "https://github.com/getflip/swirl"
15
+ },
16
+ license: "SEE LICENSE IN LICENSE.md",
17
+ bugs: {
18
+ url: "https://github.com/getflip/swirl/issues"
19
+ },
20
+ type: "module",
21
+ bin: {
22
+ "swirl-mcp": "dist/transports/stdio.js"
23
+ },
24
+ files: [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ scripts: {
29
+ build: "tsup",
30
+ start: "node dist/transports/http.js",
31
+ dev: "tsx src/transports/stdio.ts",
32
+ "dev:server": "tsx src/transports/http.ts",
33
+ lint: "tsc --noEmit"
34
+ },
35
+ tsup: {
36
+ entry: {
37
+ "transports/stdio": "src/transports/stdio.ts",
38
+ "transports/http": "src/transports/http.ts"
39
+ },
40
+ format: [
41
+ "esm"
42
+ ],
43
+ target: "node18",
44
+ outDir: "dist",
45
+ clean: true,
46
+ banner: {
47
+ js: "#!/usr/bin/env node"
48
+ }
49
+ },
50
+ dependencies: {
51
+ "@modelcontextprotocol/sdk": "1.27.1",
52
+ zod: "3.24.0"
53
+ },
54
+ devDependencies: {
55
+ "@types/node": "25.3.0",
56
+ tsup: "^8.0.0",
57
+ tsx: "^4.7.0",
58
+ typescript: "5.9.3"
59
+ }
60
+ };
61
+
6
62
  // src/data-source.ts
7
- var DataSource = class {
63
+ import { readFileSync } from "fs";
64
+ import { dirname, join, resolve } from "path";
65
+ import { fileURLToPath } from "url";
66
+ var RemoteDataSource = class {
8
67
  constructor(version) {
9
68
  this.version = version;
10
69
  }
@@ -48,14 +107,43 @@ var DataSource = class {
48
107
  return `https://raw.githubusercontent.com/getflip/swirl/@getflip/swirl-components@${this.version}`;
49
108
  }
50
109
  };
110
+ var LocalDataSource = class {
111
+ async readJson(relativePath) {
112
+ return JSON.parse(readFileSync(this.agentPath(relativePath), "utf8"));
113
+ }
114
+ async readText(relativePath) {
115
+ try {
116
+ return readFileSync(this.agentPath(relativePath), "utf8");
117
+ } catch {
118
+ return void 0;
119
+ }
120
+ }
121
+ async readComponentSource(tag) {
122
+ const componentDir = join(packagesDir, "swirl-components", "src", "components", tag);
123
+ const read = (ext) => {
124
+ try {
125
+ return readFileSync(join(componentDir, `${tag}.${ext}`), "utf8");
126
+ } catch {
127
+ return void 0;
128
+ }
129
+ };
130
+ return { tsx: read("tsx"), css: read("css") };
131
+ }
132
+ agentPath(relativePath) {
133
+ return join(packagesDir, "swirl-ai", "dist", "agent", relativePath);
134
+ }
135
+ };
136
+ var packagesDir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
51
137
 
52
138
  // src/artifact-library.ts
53
139
  var ArtifactLibrary = class _ArtifactLibrary {
54
140
  catalog;
55
141
  tagIndex;
142
+ tokens;
56
143
  dataSource;
57
- constructor(catalog, dataSource) {
144
+ constructor(catalog, tokens, dataSource) {
58
145
  this.catalog = catalog;
146
+ this.tokens = tokens;
59
147
  this.dataSource = dataSource;
60
148
  this.tagIndex = /* @__PURE__ */ new Map();
61
149
  for (const entry of this.catalog) {
@@ -66,11 +154,15 @@ var ArtifactLibrary = class _ArtifactLibrary {
66
154
  * Load artifacts from a remote base URL (CDN).
67
155
  */
68
156
  static async fromRemote(version) {
69
- const ds = new DataSource(version);
70
- const json = await ds.readJson(
71
- "components-index.json"
72
- );
73
- return new _ArtifactLibrary(json.components, ds);
157
+ return _ArtifactLibrary.fromDataSource(new RemoteDataSource(version));
158
+ }
159
+ /**
160
+ * Load artifacts from the local monorepo (`packages/swirl-ai/dist` and
161
+ * `packages/swirl-components/src`) for development against an unpublished
162
+ * swirl-ai build.
163
+ */
164
+ static async fromLocal() {
165
+ return _ArtifactLibrary.fromDataSource(new LocalDataSource());
74
166
  }
75
167
  getByCategory(category) {
76
168
  return this.catalog.filter((c) => categorize(c.tag) === category);
@@ -87,6 +179,16 @@ var ArtifactLibrary = class _ArtifactLibrary {
87
179
  async getGuide(name) {
88
180
  return this.dataSource.readText(`${name}.md`);
89
181
  }
182
+ getTokensByCategory(category) {
183
+ return this.tokens[category];
184
+ }
185
+ static async fromDataSource(dataSource) {
186
+ const [components, tokens] = await Promise.all([
187
+ dataSource.readJson("components-index.json"),
188
+ dataSource.readJson("tokens.json")
189
+ ]);
190
+ return new _ArtifactLibrary(components.components, tokens, dataSource);
191
+ }
90
192
  };
91
193
  function categorize(tag) {
92
194
  if (tag.startsWith("swirl-icon-")) {
@@ -307,19 +409,108 @@ function registerListTool(server, loadLibrary2, name, description, category) {
307
409
  );
308
410
  }
309
411
 
412
+ // src/tools/list-tokens.ts
413
+ import { z as z5 } from "zod";
414
+ var VERSION_DESCRIPTION5 = "The @getflip/swirl-components version installed in the project. Read the user's package.json or node_modules/@getflip/swirl-components/package.json to find this.";
415
+ var FORMAT_DESCRIPTION = "Output format for the token key. 'css' - CSS custom property. 'scss' - SCSS variable. 'tailwind' - returns `key: '{name}'` + `namespace` (e.g. 'colors', 'fontSize', 'spacing') so the agent can build the right utility class. Pick the format that matches the project's styling stack.";
416
+ function registerListColorTokens(server, loadLibrary2) {
417
+ registerListTokensTool(
418
+ server,
419
+ loadLibrary2,
420
+ "list_color_tokens",
421
+ "List Swirl color tokens with light + dark values. Pass 'format' to choose css / scss / tailwind output. For tailwind, all colors use the 'colors' namespace (e.g. `text-{name}`, `bg-{name}`, `border-{name}`). Prefer these over hard-coded hex/rgb values.",
422
+ "colors"
423
+ );
424
+ }
425
+ function registerListTypographyTokens(server, loadLibrary2) {
426
+ registerListTokensTool(
427
+ server,
428
+ loadLibrary2,
429
+ "list_typography_tokens",
430
+ "List Swirl typography tokens. Pass 'format' to choose css / scss / tailwind output. Prefer these over ad-hoc font sizes/weights.",
431
+ "typography"
432
+ );
433
+ }
434
+ function registerListLayoutTokens(server, loadLibrary2) {
435
+ registerListTokensTool(
436
+ server,
437
+ loadLibrary2,
438
+ "list_layout_tokens",
439
+ "List Swirl layout tokens (spacing, border radius, border width, box shadows, z-index, blur). Pass 'format' to choose css / scss / tailwind output. Prefer these over arbitrary px/rem values.",
440
+ "layout"
441
+ );
442
+ }
443
+ function registerListTokensTool(server, loadLibrary2, name, description, category) {
444
+ server.registerTool(
445
+ name,
446
+ {
447
+ description,
448
+ inputSchema: {
449
+ version: z5.string().describe(VERSION_DESCRIPTION5),
450
+ format: z5.enum(["css", "scss", "tailwind"]).describe(FORMAT_DESCRIPTION)
451
+ }
452
+ },
453
+ // @ts-ignore - MCP SDK + zod 3.x causes excessively deep type instantiation
454
+ async ({ version, format }) => {
455
+ const lib = await loadLibrary2(version);
456
+ const tokens = lib.getTokensByCategory(category);
457
+ const formatted = tokens.map((t) => formatToken(t, format)).filter((t) => t !== null);
458
+ return {
459
+ content: [{ type: "text", text: JSON.stringify(formatted) }]
460
+ };
461
+ }
462
+ );
463
+ }
464
+ function formatToken(token, format) {
465
+ if (format === "tailwind" && !token.tailwindNamespace) {
466
+ return null;
467
+ }
468
+ const out = { key: tokenKey(token, format) };
469
+ if (format === "tailwind") {
470
+ out.namespace = token.tailwindNamespace;
471
+ }
472
+ if (token.valueLight !== void 0) {
473
+ out.valueLight = token.valueLight;
474
+ out.valueDark = token.valueDark;
475
+ } else if (token.value !== void 0) {
476
+ out.value = token.value;
477
+ }
478
+ if (token.description) {
479
+ out.description = token.description;
480
+ }
481
+ return out;
482
+ }
483
+ function tokenKey(token, format) {
484
+ switch (format) {
485
+ case "css":
486
+ return `--s-${token.name}`;
487
+ case "scss":
488
+ return `$s-${token.name}`;
489
+ case "tailwind":
490
+ return token.name;
491
+ }
492
+ }
493
+
310
494
  // src/create-server.ts
311
495
  var cache = new LibraryCache();
496
+ var useLocal = Boolean(process.env.SWIRL_AI_LOCAL);
312
497
  async function loadLibrary(version) {
313
- const cached = cache.get(version);
498
+ const cacheKey = useLocal ? "__local__" : version;
499
+ const cached = cache.get(cacheKey);
314
500
  if (cached) {
315
501
  return cached;
316
502
  }
317
503
  try {
318
- const lib = await ArtifactLibrary.fromRemote(version);
319
- cache.set(version, lib);
504
+ const lib = useLocal ? await ArtifactLibrary.fromLocal() : await ArtifactLibrary.fromRemote(version);
505
+ cache.set(cacheKey, lib);
320
506
  return lib;
321
507
  } catch (error) {
322
508
  const message = error instanceof Error ? error.message : String(error);
509
+ if (useLocal) {
510
+ throw new Error(
511
+ `Failed to load local swirl-ai artifacts. Make sure swirl-ai has been built (\`pnpm --filter @getflip/swirl-ai build\`). Details: ${message}`
512
+ );
513
+ }
323
514
  throw new Error(
324
515
  `Version "${version}" not found or failed to load. Make sure the version matches your installed @getflip/swirl-components version. Details: ${message}`
325
516
  );
@@ -350,7 +541,7 @@ function createMcpServer() {
350
541
  const server = new McpServer(
351
542
  {
352
543
  name: "swirl-mcp",
353
- version: "0.1.0"
544
+ version: package_default.version
354
545
  },
355
546
  {
356
547
  instructions: INSTRUCTIONS
@@ -362,6 +553,9 @@ function createMcpServer() {
362
553
  registerGetComponentDetails(server, loadLibrary);
363
554
  registerGetComponentSource(server, loadLibrary);
364
555
  registerGetStarted(server, loadLibrary);
556
+ registerListColorTokens(server, loadLibrary);
557
+ registerListTypographyTokens(server, loadLibrary);
558
+ registerListLayoutTokens(server, loadLibrary);
365
559
  return server;
366
560
  }
367
561
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createMcpServer
4
- } from "../chunk-HWC76PLD.js";
4
+ } from "../chunk-QVNIVXYL.js";
5
5
 
6
6
  // src/transports/http.ts
7
7
  import { createServer } from "http";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createMcpServer
4
- } from "../chunk-HWC76PLD.js";
4
+ } from "../chunk-QVNIVXYL.js";
5
5
 
6
6
  // src/transports/stdio.ts
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getflip/swirl-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for Swirl Design System — lets AI agents discover and use Swirl components",
5
5
  "author": "Flip GmbH",
6
6
  "repository": {