@nysds/mcp-server 1.16.0-alpha4 → 1.16.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.
Files changed (39) hide show
  1. package/README.md +114 -63
  2. package/data/guides/fonts.md +77 -0
  3. package/data/guides/form-validation.md +169 -0
  4. package/data/guides/frameworks/angular.md +71 -0
  5. package/data/guides/frameworks/dotnet.md +42 -0
  6. package/data/guides/frameworks/drupal.md +39 -0
  7. package/data/guides/frameworks/react.md +45 -0
  8. package/data/guides/frameworks/vanilla.md +45 -0
  9. package/data/guides/installation.md +73 -0
  10. package/data/guides/page-structure.md +160 -0
  11. package/data/guides/styles.md +48 -0
  12. package/dist/lib/cem-parser.d.ts +6 -0
  13. package/dist/lib/cem-parser.d.ts.map +1 -1
  14. package/dist/lib/cem-parser.js +18 -9
  15. package/dist/lib/format.d.ts +22 -0
  16. package/dist/lib/format.d.ts.map +1 -0
  17. package/dist/lib/format.js +33 -0
  18. package/dist/prompts/nysds-mode.d.ts.map +1 -1
  19. package/dist/prompts/nysds-mode.js +17 -8
  20. package/dist/resources/guides.d.ts.map +1 -1
  21. package/dist/resources/guides.js +22 -26
  22. package/dist/tools/component-tools.d.ts +3 -5
  23. package/dist/tools/component-tools.d.ts.map +1 -1
  24. package/dist/tools/component-tools.js +51 -85
  25. package/dist/tools/guide-tools.d.ts +9 -0
  26. package/dist/tools/guide-tools.d.ts.map +1 -0
  27. package/dist/tools/guide-tools.js +78 -0
  28. package/dist/tools/index.d.ts.map +1 -1
  29. package/dist/tools/index.js +4 -0
  30. package/dist/tools/token-tools.d.ts +2 -5
  31. package/dist/tools/token-tools.d.ts.map +1 -1
  32. package/dist/tools/token-tools.js +88 -108
  33. package/dist/tools/utility-tools.d.ts +8 -0
  34. package/dist/tools/utility-tools.d.ts.map +1 -0
  35. package/dist/tools/utility-tools.js +282 -0
  36. package/dist/tools/validation-tools.d.ts +1 -2
  37. package/dist/tools/validation-tools.d.ts.map +1 -1
  38. package/dist/tools/validation-tools.js +1 -163
  39. package/package.json +5 -4
@@ -3,11 +3,9 @@
3
3
  *
4
4
  * MCP tools for working with NYSDS components.
5
5
  *
6
- * P0 Tools:
7
- * - list_components: List all NYSDS components with summaries
8
- * - get_component_docs: Full documentation for a specific component
9
- * - find_components: Search by name/description (fuzzy)
10
- * - get_usage_guide: Installation and usage patterns
6
+ * Tools:
7
+ * - find_components: Search or list all components
8
+ * - get_component: Full documentation for a specific component
11
9
  */
12
10
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
11
  export declare function registerComponentTools(server: McpServer): void;
@@ -1 +1 @@
1
- {"version":3,"file":"component-tools.d.ts","sourceRoot":"","sources":["../../src/tools/component-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8I9D"}
1
+ {"version":3,"file":"component-tools.d.ts","sourceRoot":"","sources":["../../src/tools/component-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G9D"}
@@ -3,123 +3,89 @@
3
3
  *
4
4
  * MCP tools for working with NYSDS components.
5
5
  *
6
- * P0 Tools:
7
- * - list_components: List all NYSDS components with summaries
8
- * - get_component_docs: Full documentation for a specific component
9
- * - find_components: Search by name/description (fuzzy)
10
- * - get_usage_guide: Installation and usage patterns
6
+ * Tools:
7
+ * - find_components: Search or list all components
8
+ * - get_component: Full documentation for a specific component
11
9
  */
12
10
  import { z } from "zod";
13
11
  import { getComponent, getAllComponents } from "../lib/cem-parser.js";
14
12
  import { searchComponents } from "../lib/search.js";
15
13
  export function registerComponentTools(server) {
16
- // list_components - List all NYSDS components with summaries
17
- server.tool("list_components", "List all NYSDS web components with their tag names and brief descriptions", {}, async () => {
18
- const components = getAllComponents();
19
- const list = components.map((c) => ({
20
- tagName: c.tagName,
21
- name: c.name,
22
- summary: c.summary || c.description?.split("\n")[0] || "No description",
14
+ // find_components - Search or list all components
15
+ server.tool("find_components", "Search for NYSDS components by name or description. Omit query to list all components.", {
16
+ query: z
17
+ .string()
18
+ .optional()
19
+ .describe("Search query to match against component names and descriptions. Omit to list all components."),
20
+ }, async ({ query }) => {
21
+ // If no query, return all components
22
+ if (!query || query.trim() === "") {
23
+ const components = getAllComponents();
24
+ const list = components.map((c) => ({
25
+ tagName: c.tagName,
26
+ name: c.name,
27
+ summary: c.summary || c.description?.split("\n")[0] || "No description",
28
+ resourceUri: `nysds://component/${c.tagName}`,
29
+ }));
30
+ return {
31
+ content: [
32
+ {
33
+ type: "text",
34
+ text: JSON.stringify(list, null, 2),
35
+ },
36
+ ],
37
+ };
38
+ }
39
+ // Otherwise search
40
+ const results = searchComponents(query).map((r) => ({
41
+ ...r,
42
+ resourceUri: `nysds://component/${r.tagName}`,
23
43
  }));
24
44
  return {
25
45
  content: [
26
46
  {
27
47
  type: "text",
28
- text: JSON.stringify(list, null, 2),
48
+ text: JSON.stringify(results, null, 2),
29
49
  },
30
50
  ],
31
51
  };
32
52
  });
33
- // get_component_docs - Full documentation for a specific component
34
- server.tool("get_component_docs", "Get full documentation for a specific NYSDS component including properties, events, slots, and CSS custom properties", {
53
+ // get_component - Full documentation for a specific component
54
+ server.tool("get_component", "Get full documentation for a specific NYSDS component including properties, events, slots, and CSS custom properties", {
35
55
  tagName: z
36
56
  .string()
37
57
  .describe("The tag name of the component (e.g., 'nys-button')"),
38
- }, async ({ tagName }) => {
58
+ includeExamples: z
59
+ .boolean()
60
+ .default(false)
61
+ .describe("Include HTML code examples from component JSDoc. Set to true when you need usage patterns."),
62
+ }, async ({ tagName, includeExamples }) => {
39
63
  const component = getComponent(tagName);
40
64
  if (!component) {
41
65
  return {
42
66
  content: [
43
67
  {
44
68
  type: "text",
45
- text: `Component "${tagName}" not found. Use list_components to see available components.`,
69
+ text: `Component "${tagName}" not found. Use find_components to see available components.`,
46
70
  },
47
71
  ],
48
72
  isError: true,
49
73
  };
50
74
  }
75
+ // Remove members array to avoid duplication with attributes
76
+ // Attributes contains the HTML API, members duplicates this plus private methods
77
+ const { members: _members, examples, ...componentWithoutMembers } = component;
51
78
  return {
52
79
  content: [
53
80
  {
54
81
  type: "text",
55
- text: JSON.stringify(component, null, 2),
56
- },
57
- ],
58
- };
59
- });
60
- // find_components - Search by name/description
61
- server.tool("find_components", "Search for NYSDS components by name or description", {
62
- query: z
63
- .string()
64
- .describe("Search query to match against component names and descriptions"),
65
- }, async ({ query }) => {
66
- const results = searchComponents(query);
67
- return {
68
- content: [
69
- {
70
- type: "text",
71
- text: JSON.stringify(results, null, 2),
72
- },
73
- ],
74
- };
75
- });
76
- // get_usage_guide - Installation and usage patterns
77
- server.tool("get_usage_guide", "Get installation and usage guide for NYSDS components", {}, async () => {
78
- const guide = `# NYSDS Component Usage Guide
79
-
80
- ## Installation
81
-
82
- \`\`\`bash
83
- npm install @nysds/components
84
- \`\`\`
85
-
86
- ## Basic Usage
87
-
88
- Import components individually:
89
-
90
- \`\`\`javascript
91
- import '@nysds/components/nys-button';
92
- import '@nysds/components/nys-alert';
93
- \`\`\`
94
-
95
- Or import all components:
96
-
97
- \`\`\`javascript
98
- import '@nysds/components';
99
- \`\`\`
100
-
101
- ## Using Components in HTML
102
-
103
- \`\`\`html
104
- <nys-button label="Click me" variant="primary"></nys-button>
105
- <nys-alert type="info">This is an informational message.</nys-alert>
106
- \`\`\`
107
-
108
- ## CSS Custom Properties
109
-
110
- NYSDS components use CSS custom properties for theming. Import the base styles:
111
-
112
- \`\`\`css
113
- @import '@nysds/components/dist/styles.css';
114
- \`\`\`
115
-
116
- Use the get_design_tokens tool to explore available tokens.
117
- `;
118
- return {
119
- content: [
120
- {
121
- type: "text",
122
- text: guide,
82
+ text: JSON.stringify({
83
+ ...componentWithoutMembers,
84
+ examples: includeExamples && examples && examples.length > 0
85
+ ? examples
86
+ : undefined,
87
+ resourceUri: `nysds://component/${tagName}`,
88
+ }, null, 2),
123
89
  },
124
90
  ],
125
91
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Guide Tools
3
+ *
4
+ * Consolidated MCP tool for NYSDS guides and documentation.
5
+ * Loads guide content from data/guides/ markdown files.
6
+ */
7
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ export declare function registerGuideTools(server: McpServer): void;
9
+ //# sourceMappingURL=guide-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guide-tools.d.ts","sourceRoot":"","sources":["../../src/tools/guide-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6CzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyC1D"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Guide Tools
3
+ *
4
+ * Consolidated MCP tool for NYSDS guides and documentation.
5
+ * Loads guide content from data/guides/ markdown files.
6
+ */
7
+ import { z } from "zod";
8
+ import { readFileSync } from "fs";
9
+ import { join, dirname } from "path";
10
+ import { fileURLToPath } from "url";
11
+ // ESM-compatible __dirname
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ // Path to guides directory (relative to dist/tools/)
15
+ const GUIDES_DIR = join(__dirname, "../../data/guides");
16
+ /**
17
+ * Load a guide markdown file
18
+ */
19
+ function loadGuide(filename) {
20
+ try {
21
+ return readFileSync(join(GUIDES_DIR, filename), "utf-8");
22
+ }
23
+ catch {
24
+ return `Guide not found: ${filename}`;
25
+ }
26
+ }
27
+ /**
28
+ * Load a framework-specific guide
29
+ */
30
+ function loadFrameworkGuide(framework) {
31
+ try {
32
+ return readFileSync(join(GUIDES_DIR, "frameworks", `${framework}.md`), "utf-8");
33
+ }
34
+ catch {
35
+ return `Framework guide not found: ${framework}`;
36
+ }
37
+ }
38
+ const TOPIC_TO_FILE = {
39
+ installation: "installation.md",
40
+ "form-validation": "form-validation.md",
41
+ styles: "styles.md",
42
+ fonts: "fonts.md",
43
+ "page-structure": "page-structure.md",
44
+ };
45
+ export function registerGuideTools(server) {
46
+ server.tool("get_guide", "Get NYSDS guides for installation, forms, styles, fonts, page structure, or framework setup", {
47
+ topic: z
48
+ .enum([
49
+ "installation",
50
+ "form-validation",
51
+ "styles",
52
+ "fonts",
53
+ "page-structure",
54
+ ])
55
+ .describe("The guide topic to retrieve"),
56
+ framework: z
57
+ .enum(["angular", "react", "dotnet", "drupal", "vanilla"])
58
+ .optional()
59
+ .describe("When provided, returns framework-specific setup guide instead of the topic guide. Use with topic 'installation' to get framework install instructions."),
60
+ }, async ({ topic, framework }) => {
61
+ let content;
62
+ if (framework) {
63
+ content = loadFrameworkGuide(framework);
64
+ }
65
+ else {
66
+ const filename = TOPIC_TO_FILE[topic];
67
+ content = filename ? loadGuide(filename) : `Unknown topic: ${topic}`;
68
+ }
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: content,
74
+ },
75
+ ],
76
+ };
77
+ });
78
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAMrD"}
@@ -6,8 +6,12 @@
6
6
  import { registerComponentTools } from "./component-tools.js";
7
7
  import { registerTokenTools } from "./token-tools.js";
8
8
  import { registerValidationTools } from "./validation-tools.js";
9
+ import { registerUtilityTools } from "./utility-tools.js";
10
+ import { registerGuideTools } from "./guide-tools.js";
9
11
  export function registerTools(server) {
10
12
  registerComponentTools(server);
11
13
  registerTokenTools(server);
12
14
  registerValidationTools(server);
15
+ registerUtilityTools(server);
16
+ registerGuideTools(server);
13
17
  }
@@ -4,12 +4,9 @@
4
4
  * MCP tools for working with NYSDS design tokens.
5
5
  *
6
6
  * Tools:
7
- * - get_design_tokens: Get tokens with filtering and options
7
+ * - get_tokens: Get tokens, categories, or themes
8
8
  * - find_tokens: Search tokens by CSS variable, value, or description
9
- * - list_themes: List all 8 agency themes
10
- * - get_token_value: Get detailed info for a specific token
11
- * - validate_token_usage: Validate token usage in context
12
- * - list_token_categories: List categories with token counts
9
+ * - get_token_info: Get detailed token info with optional context validation
13
10
  * - get_token_graph: Get token dependency graph
14
11
  */
15
12
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -1 +1 @@
1
- {"version":3,"file":"token-tools.d.ts","sourceRoot":"","sources":["../../src/tools/token-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoOzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4a1D"}
1
+ {"version":3,"file":"token-tools.d.ts","sourceRoot":"","sources":["../../src/tools/token-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqOzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwX1D"}
@@ -4,16 +4,14 @@
4
4
  * MCP tools for working with NYSDS design tokens.
5
5
  *
6
6
  * Tools:
7
- * - get_design_tokens: Get tokens with filtering and options
7
+ * - get_tokens: Get tokens, categories, or themes
8
8
  * - find_tokens: Search tokens by CSS variable, value, or description
9
- * - list_themes: List all 8 agency themes
10
- * - get_token_value: Get detailed info for a specific token
11
- * - validate_token_usage: Validate token usage in context
12
- * - list_token_categories: List categories with token counts
9
+ * - get_token_info: Get detailed token info with optional context validation
13
10
  * - get_token_graph: Get token dependency graph
14
11
  */
15
12
  import { z } from "zod";
16
13
  import { getCSSTokens, getCSSTokensByCategory, getCSSTokensByLayer, searchCSSTokens, getCSSTokenByVariable, getCSSTokenCategories, buildTokenGraph, } from "../lib/token-parser.js";
14
+ import { formatResponse } from "../lib/format.js";
17
15
  const AGENCY_THEMES = [
18
16
  {
19
17
  id: "default",
@@ -181,9 +179,13 @@ function validateTokenInContext(token, context) {
181
179
  // ============================================================================
182
180
  export function registerTokenTools(server) {
183
181
  // -------------------------------------------------------------------------
184
- // get_design_tokens - Enhanced token retrieval
182
+ // get_tokens - Consolidated token retrieval (tokens, categories, or themes)
185
183
  // -------------------------------------------------------------------------
186
- server.tool("get_design_tokens", "Get NYSDS design tokens with optional filtering by category or layer. Returns CSS variable names and values.", {
184
+ server.tool("get_tokens", "Get NYSDS design tokens, token categories, or agency themes", {
185
+ output: z
186
+ .enum(["tokens", "categories", "themes"])
187
+ .default("tokens")
188
+ .describe("What to return: 'tokens' for CSS variables, 'categories' for category list with counts, 'themes' for agency themes"),
187
189
  category: z
188
190
  .enum([
189
191
  "color",
@@ -198,20 +200,53 @@ export function registerTokenTools(server) {
198
200
  "icon",
199
201
  ])
200
202
  .optional()
201
- .describe("Filter by token category"),
203
+ .describe("Filter tokens by category (only applies when output='tokens')"),
202
204
  layer: z
203
205
  .enum(["primitive", "applied", "theme", "appearance"])
204
206
  .optional()
205
- .describe("Filter by token layer (primitive = raw values, applied = semantic tokens, theme = agency theme tokens, appearance = light/dark mode)"),
207
+ .describe("Filter tokens by layer (only applies when output='tokens'). primitive = raw values, applied = semantic tokens, theme = agency theme tokens, appearance = light/dark mode"),
206
208
  includeResolvedValues: z
207
209
  .boolean()
208
210
  .default(false)
209
- .describe("Include resolved hex/rem values for previews"),
211
+ .describe("Include resolved hex/rem values (only applies when output='tokens')"),
210
212
  includeDescriptions: z
211
213
  .boolean()
212
214
  .default(true)
213
- .describe("Include token descriptions"),
214
- }, async ({ category, layer, includeResolvedValues, includeDescriptions }) => {
215
+ .describe("Include token descriptions (only applies when output='tokens')"),
216
+ }, async ({ output, category, layer, includeResolvedValues, includeDescriptions, }) => {
217
+ // Return categories
218
+ if (output === "categories") {
219
+ const categories = getCSSTokenCategories();
220
+ const total = categories.reduce((sum, c) => sum + c.count, 0);
221
+ return {
222
+ content: [
223
+ {
224
+ type: "text",
225
+ text: formatResponse({ categories, totalTokens: total }),
226
+ },
227
+ ],
228
+ };
229
+ }
230
+ // Return themes
231
+ if (output === "themes") {
232
+ return {
233
+ content: [
234
+ {
235
+ type: "text",
236
+ text: formatResponse({
237
+ themes: AGENCY_THEMES,
238
+ usage: {
239
+ htmlAttribute: '<html data-theme="admin">',
240
+ cssClass: '<body class="nys-theme-admin">',
241
+ cssCustomProperty: "Themes modify --nys-color-theme-* tokens",
242
+ },
243
+ totalThemes: AGENCY_THEMES.length,
244
+ }),
245
+ },
246
+ ],
247
+ };
248
+ }
249
+ // Return tokens (default)
215
250
  let tokens;
216
251
  if (category) {
217
252
  tokens = getCSSTokensByCategory(category);
@@ -240,10 +275,7 @@ export function registerTokenTools(server) {
240
275
  content: [
241
276
  {
242
277
  type: "text",
243
- text: JSON.stringify({
244
- count: tokens.length,
245
- tokens: formatted,
246
- }, null, 2),
278
+ text: formatResponse({ count: tokens.length, tokens: formatted }),
247
279
  },
248
280
  ],
249
281
  };
@@ -285,54 +317,37 @@ export function registerTokenTools(server) {
285
317
  content: [
286
318
  {
287
319
  type: "text",
288
- text: JSON.stringify({
320
+ text: formatResponse({
289
321
  query,
290
322
  count: results.length,
291
323
  results: formatted,
292
- }, null, 2),
324
+ }),
293
325
  },
294
326
  ],
295
327
  };
296
328
  });
297
329
  // -------------------------------------------------------------------------
298
- // list_themes - List agency themes
330
+ // get_token_info - Get detailed token info with optional context validation
299
331
  // -------------------------------------------------------------------------
300
- server.tool("list_themes", "List all NYSDS agency themes with their selectors and primary colors", {}, async () => {
301
- return {
302
- content: [
303
- {
304
- type: "text",
305
- text: JSON.stringify({
306
- themes: AGENCY_THEMES,
307
- usage: {
308
- htmlAttribute: '<html data-theme="admin">',
309
- cssClass: '<body class="nys-theme-admin">',
310
- cssCustomProperty: "Themes modify --nys-color-theme-* tokens",
311
- },
312
- totalThemes: AGENCY_THEMES.length,
313
- }, null, 2),
314
- },
315
- ],
316
- };
317
- });
318
- // -------------------------------------------------------------------------
319
- // get_token_value - Get detailed token info
320
- // -------------------------------------------------------------------------
321
- server.tool("get_token_value", "Get detailed information about a specific design token including its value, description, and which tokens use it", {
332
+ server.tool("get_token_info", "Get detailed information about a specific design token. Optionally validate usage in a specific context (text, background, border, icon).", {
322
333
  token: z
323
334
  .string()
324
335
  .describe('CSS variable name (e.g., "--nys-color-text" or "color-text")'),
325
- }, async ({ token }) => {
336
+ context: z
337
+ .enum(["text", "background", "border", "icon"])
338
+ .optional()
339
+ .describe("Optional: validate token usage for a specific context. When provided, includes recommendations and warnings."),
340
+ }, async ({ token, context }) => {
326
341
  const tokenInfo = getCSSTokenByVariable(token);
327
342
  if (!tokenInfo) {
328
343
  return {
329
344
  content: [
330
345
  {
331
346
  type: "text",
332
- text: JSON.stringify({
347
+ text: formatResponse({
333
348
  error: `Token not found: ${token}`,
334
349
  suggestion: "Try searching with find_tokens to discover available tokens",
335
- }, null, 2),
350
+ }),
336
351
  },
337
352
  ],
338
353
  };
@@ -341,73 +356,38 @@ export function registerTokenTools(server) {
341
356
  const graph = buildTokenGraph();
342
357
  const node = graph.get(tokenInfo.cssVariable);
343
358
  const usedBy = node?.usedBy || [];
344
- return {
345
- content: [
346
- {
347
- type: "text",
348
- text: JSON.stringify({
349
- cssVariable: tokenInfo.cssVariable,
350
- cssValue: tokenInfo.cssValue,
351
- resolvedValue: tokenInfo.resolvedValue,
352
- description: tokenInfo.description,
353
- category: tokenInfo.category,
354
- layer: tokenInfo.layer,
355
- usedBy: usedBy.length > 0 ? usedBy : undefined,
356
- usage: `var(${tokenInfo.cssVariable})`,
357
- }, null, 2),
358
- },
359
- ],
359
+ // Base token info
360
+ const result = {
361
+ cssVariable: tokenInfo.cssVariable,
362
+ cssValue: tokenInfo.cssValue,
363
+ resolvedValue: tokenInfo.resolvedValue,
364
+ description: tokenInfo.description,
365
+ category: tokenInfo.category,
366
+ layer: tokenInfo.layer,
367
+ usedBy: usedBy.length > 0 ? usedBy : undefined,
368
+ usage: `var(${tokenInfo.cssVariable})`,
369
+ resourceUri: "nysds://tokens",
360
370
  };
361
- });
362
- // -------------------------------------------------------------------------
363
- // validate_token_usage - Validate token in context
364
- // -------------------------------------------------------------------------
365
- server.tool("validate_token_usage", "Validate whether a token is appropriate for a specific usage context (text, background, border, icon)", {
366
- token: z
367
- .string()
368
- .describe('CSS variable name (e.g., "--nys-color-text" or "color-text")'),
369
- context: z
370
- .enum(["text", "background", "border", "icon"])
371
- .describe("How the token will be used"),
372
- }, async ({ token, context }) => {
373
- const tokenInfo = getCSSTokenByVariable(token);
374
- if (!tokenInfo) {
375
- return {
376
- content: [
377
- {
378
- type: "text",
379
- text: JSON.stringify({
380
- error: `Token not found: ${token}`,
381
- suggestion: "Try searching with find_tokens to discover available tokens",
382
- }, null, 2),
383
- },
384
- ],
371
+ // If context provided, add validation info
372
+ if (context) {
373
+ const validation = validateTokenInContext(tokenInfo, context);
374
+ result.validation = {
375
+ context,
376
+ valid: validation.valid,
377
+ recommendations: validation.recommendations.length > 0
378
+ ? validation.recommendations
379
+ : undefined,
380
+ warnings: validation.warnings,
381
+ alternatives: validation.alternatives.length > 0
382
+ ? validation.alternatives
383
+ : undefined,
385
384
  };
386
385
  }
387
- const validation = validateTokenInContext(tokenInfo, context);
388
- return {
389
- content: [
390
- {
391
- type: "text",
392
- text: JSON.stringify(validation, null, 2),
393
- },
394
- ],
395
- };
396
- });
397
- // -------------------------------------------------------------------------
398
- // list_token_categories - List categories with counts
399
- // -------------------------------------------------------------------------
400
- server.tool("list_token_categories", "List all token categories with the number of tokens in each", {}, async () => {
401
- const categories = getCSSTokenCategories();
402
- const total = categories.reduce((sum, c) => sum + c.count, 0);
403
386
  return {
404
387
  content: [
405
388
  {
406
389
  type: "text",
407
- text: JSON.stringify({
408
- categories,
409
- totalTokens: total,
410
- }, null, 2),
390
+ text: formatResponse(result),
411
391
  },
412
392
  ],
413
393
  };
@@ -440,8 +420,8 @@ export function registerTokenTools(server) {
440
420
  .int()
441
421
  .min(1)
442
422
  .max(100)
443
- .default(50)
444
- .describe("Maximum number of tokens to return"),
423
+ .default(20)
424
+ .describe("Maximum number of tokens to return (default: 20)"),
445
425
  }, async ({ filter, category, limit }) => {
446
426
  const graph = buildTokenGraph();
447
427
  const tokens = getCSSTokens();
@@ -487,7 +467,7 @@ export function registerTokenTools(server) {
487
467
  content: [
488
468
  {
489
469
  type: "text",
490
- text: JSON.stringify({
470
+ text: formatResponse({
491
471
  filter,
492
472
  category: category || "all",
493
473
  nodes: nodes.map((n) => ({
@@ -496,7 +476,7 @@ export function registerTokenTools(server) {
496
476
  usedBy: n.usedBy.length > 0 ? n.usedBy : undefined,
497
477
  })),
498
478
  stats,
499
- }, null, 2),
479
+ }),
500
480
  },
501
481
  ],
502
482
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Utility Tools
3
+ *
4
+ * MCP tools for NYSDS utility classes.
5
+ */
6
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ export declare function registerUtilityTools(server: McpServer): void;
8
+ //# sourceMappingURL=utility-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utility-tools.d.ts","sourceRoot":"","sources":["../../src/tools/utility-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwOzE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8D5D"}