@atlaskit/ads-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.
Files changed (34) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/cjs/index.js +9 -5
  3. package/dist/cjs/instructions.js +1 -1
  4. package/dist/cjs/tools/{get-icons → get-all-icons}/index.js +6 -6
  5. package/dist/cjs/tools/{get-tokens → get-all-tokens}/index.js +7 -8
  6. package/dist/cjs/tools/search-icons/index.js +138 -0
  7. package/dist/cjs/tools/search-tokens/index.js +106 -0
  8. package/dist/cjs/tools/suggest-accessibility-fixes/fixes.js +1 -1
  9. package/dist/es2019/index.js +9 -5
  10. package/dist/es2019/instructions.js +4 -0
  11. package/dist/es2019/tools/{get-icons → get-all-icons}/index.js +4 -4
  12. package/dist/es2019/tools/get-all-tokens/index.js +34 -0
  13. package/dist/es2019/tools/search-icons/index.js +126 -0
  14. package/dist/es2019/tools/search-tokens/index.js +96 -0
  15. package/dist/es2019/tools/suggest-accessibility-fixes/fixes.js +1 -1
  16. package/dist/esm/index.js +9 -5
  17. package/dist/esm/instructions.js +1 -1
  18. package/dist/esm/tools/{get-icons → get-all-icons}/index.js +5 -5
  19. package/dist/esm/tools/{get-tokens → get-all-tokens}/index.js +6 -7
  20. package/dist/esm/tools/search-icons/index.js +131 -0
  21. package/dist/esm/tools/search-tokens/index.js +99 -0
  22. package/dist/esm/tools/suggest-accessibility-fixes/fixes.js +1 -1
  23. package/dist/types/instructions.d.ts +1 -1
  24. package/dist/{types-ts4.5/tools/get-tokens → types/tools/get-all-icons}/index.d.ts +2 -2
  25. package/dist/types/tools/{get-tokens → get-all-tokens}/index.d.ts +2 -2
  26. package/dist/types/tools/search-icons/index.d.ts +38 -0
  27. package/dist/types/tools/search-tokens/index.d.ts +38 -0
  28. package/dist/types-ts4.5/instructions.d.ts +1 -1
  29. package/dist/types-ts4.5/tools/{get-icons → get-all-icons}/index.d.ts +2 -2
  30. package/dist/{types/tools/get-icons → types-ts4.5/tools/get-all-tokens}/index.d.ts +2 -2
  31. package/dist/types-ts4.5/tools/search-icons/index.d.ts +38 -0
  32. package/dist/types-ts4.5/tools/search-tokens/index.d.ts +38 -0
  33. package/package.json +4 -3
  34. package/dist/es2019/tools/get-tokens/index.js +0 -35
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @atlaskit/ads-mcp
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`b89521ec6e0ab`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b89521ec6e0ab) -
8
+ Replaced deprecated token and icon tools with new `get_all_tokens`, `search_tokens`,
9
+ `get_all_icons`, and `search_icons` (supporting multiple search terms with improved search
10
+ accuracy and optimised results), updated dependencies and instructions, refactored related files,
11
+ and enhanced search functionality and result limits for both tokens and icons.
12
+
3
13
  ## 0.3.0
4
14
 
5
15
  ### Minor Changes
package/dist/cjs/index.js CHANGED
@@ -9,10 +9,12 @@ var _types = require("@modelcontextprotocol/sdk/types.js");
9
9
  var _instructions = require("./instructions");
10
10
  var _analyzeAccessibility = require("./tools/analyze-accessibility");
11
11
  var _getAccessibilityGuidelines = require("./tools/get-accessibility-guidelines");
12
+ var _getAllIcons = require("./tools/get-all-icons");
13
+ var _getAllTokens = require("./tools/get-all-tokens");
12
14
  var _getComponentDetails = require("./tools/get-component-details");
13
15
  var _getComponents = require("./tools/get-components");
14
- var _getIcons = require("./tools/get-icons");
15
- var _getTokens = require("./tools/get-tokens");
16
+ var _searchIcons = require("./tools/search-icons");
17
+ var _searchTokens = require("./tools/search-tokens");
16
18
  var _suggestAccessibilityFixes = require("./tools/suggest-accessibility-fixes");
17
19
  /* eslint-disable import/extensions */
18
20
 
@@ -33,7 +35,7 @@ server.setRequestHandler(_types.ListToolsRequestSchema, /*#__PURE__*/(0, _asyncT
33
35
  while (1) switch (_context.prev = _context.next) {
34
36
  case 0:
35
37
  return _context.abrupt("return", {
36
- tools: [_getTokens.listGetTokensTool, _getComponents.listGetComponentsTool, _getComponentDetails.listGetComponentDetailsTool, _getIcons.listGetIconsTool, _analyzeAccessibility.listAnalyzeAccessibilityTool, _analyzeAccessibility.listAnalyzeLocalhostAccessibilityTool, _getAccessibilityGuidelines.listGetAccessibilityGuidelinesTool, _suggestAccessibilityFixes.listSuggestAccessibilityFixesTool]
38
+ tools: [_getAllTokens.listGetAllTokensTool, _getComponents.listGetComponentsTool, _getComponentDetails.listGetComponentDetailsTool, _getAllIcons.listGetAllIconsTool, _searchIcons.listSearchIconsTool, _searchTokens.listSearchTokensTool, _analyzeAccessibility.listAnalyzeAccessibilityTool, _analyzeAccessibility.listAnalyzeLocalhostAccessibilityTool, _getAccessibilityGuidelines.listGetAccessibilityGuidelinesTool, _suggestAccessibilityFixes.listSuggestAccessibilityFixesTool]
37
39
  });
38
40
  case 1:
39
41
  case "end":
@@ -42,10 +44,12 @@ server.setRequestHandler(_types.ListToolsRequestSchema, /*#__PURE__*/(0, _asyncT
42
44
  }, _callee);
43
45
  })));
44
46
  var callTools = {
45
- get_tokens: _getTokens.getTokensTool,
47
+ get_all_tokens: _getAllTokens.getAllTokensTool,
48
+ search_tokens: _searchTokens.searchTokensTool,
46
49
  get_components: _getComponents.getComponentsTool,
47
50
  get_component_details: _getComponentDetails.getComponentDetailsTool,
48
- get_icons: _getIcons.getIconsTool,
51
+ get_all_icons: _getAllIcons.getAllIconsTool,
52
+ search_icons: _searchIcons.searchIconsTool,
49
53
  analyze_accessibility: _analyzeAccessibility.analyzeAccessibilityTool,
50
54
  analyze_localhost_accessibility: _analyzeAccessibility.analyzeLocalhostAccessibilityTool,
51
55
  get_accessibility_guidelines: _getAccessibilityGuidelines.getAccessibilityGuidelinesTool,
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.instructions = void 0;
7
- var instructions = exports.instructions = "\nYou are an expert in the Atlassian Design System (aka ADS). You are able to answer questions about the design system and provide guidance on what offerings to use when building user interfaces.\n\nYou have special expertise in accessibility and can help ensure that interfaces built with ADS components are accessible to all users. You can analyze code for accessibility violations, provide specific fix suggestions, and offer guidance on accessibility best practices.\n\nYou are able to use the provided tools to help answer your questions, but may also access https://atlassian.design/llms.txt, https://atlassian.design/llms-a11y.txt, or https://atlassian.design/ directly for deeper research and information.\n\nAccessibility Tools Available:\n- analyze_accessibility: Analyze React component code for accessibility violations\n- get_accessibility_guidelines: Get specific accessibility guidelines and best practices\n- suggest_accessibility_fixes: Get specific fix suggestions for accessibility violations\n";
7
+ var instructions = exports.instructions = "\nYou are an expert in the Atlassian Design System (aka ADS). You are able to answer questions about the design system and provide guidance on what offerings to use when building user interfaces.\n\nYou have special expertise in accessibility and can help ensure that interfaces built with ADS components are accessible to all users. You can analyze code for accessibility violations, provide specific fix suggestions, and offer guidance on accessibility best practices.\n\nYou are able to use the provided tools to help answer your questions, but may also access https://atlassian.design/llms.txt, https://atlassian.design/llms-a11y.txt, or https://atlassian.design/ directly for deeper research and information.\n\nAccessibility Tools Available:\n- analyze_accessibility: Analyze React component code for accessibility violations\n- get_accessibility_guidelines: Get specific accessibility guidelines and best practices\n- suggest_accessibility_fixes: Get specific fix suggestions for accessibility violations\n- get_all_tokens: Get all tokens and their example values\n- search_tokens: Search for token(s) and their example value(s)\n- get_all_icons: Get all icons and their usage\n- search_icons: Search for icon(s) and their usage\n";
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.listGetIconsTool = exports.getIconsTool = void 0;
7
+ exports.listGetAllIconsTool = exports.getAllIconsTool = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
10
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
@@ -25,9 +25,9 @@ var icons = Object.entries(_metadata.coreIconMetadata).map(function (_ref) {
25
25
  shouldRecommendSmallIcon: icon.shouldRecommendSmallIcon
26
26
  };
27
27
  });
28
- var listGetIconsTool = exports.listGetIconsTool = {
29
- name: 'get_icons',
30
- description: "You MUST use this to fetch all Atlassian Design System icons and parse their names, package, and understand how they're used (provided in JSON format) before working with iconography.\nThese are the only icons to be used in modern code, though other legacy icons may still be found, these are not to be used by you, but you can keep them if you see them in existing code.\nThe resulting icon name and package is often like this:\n```tsx\nimport AddIcon from '@atlaskit/icon/core/add';\n\n// Usage in isolation\n<AddIcon label=\"Add\" />\n\n// Usage with a button\nimport Button from '@atlaskit/button/new';\n<Button iconAfter={AddIcon}>Create</Button>\n```\n",
28
+ var listGetAllIconsTool = exports.listGetAllIconsTool = {
29
+ name: 'get_all_icons',
30
+ description: "You SHOULD call this when you need complete guidance on what icons to use, but you SHOULD use the `search_icons` tool to find specific icons instead.\nThese are the only icons to be used in modern code, though other legacy icons may still be found, these are not to be used by you, but you can keep them if you see them in existing code.\nThe resulting icon name and package is often like this:\n```tsx\nimport AddIcon from '@atlaskit/icon/core/add';\n\n// Usage in isolation\n<AddIcon label=\"Add\" />\n\n// Usage with a button\nimport Button from '@atlaskit/button/new';\n<Button iconAfter={AddIcon}>Create</Button>\n```\n",
31
31
  annotations: {
32
32
  title: 'Get ADS icons',
33
33
  readOnlyHint: true,
@@ -37,7 +37,7 @@ var listGetIconsTool = exports.listGetIconsTool = {
37
37
  },
38
38
  inputSchema: _schema.emptyInputSchema
39
39
  };
40
- var getIconsTool = exports.getIconsTool = /*#__PURE__*/function () {
40
+ var getAllIconsTool = exports.getAllIconsTool = /*#__PURE__*/function () {
41
41
  var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
42
42
  return _regenerator.default.wrap(function _callee$(_context) {
43
43
  while (1) switch (_context.prev = _context.next) {
@@ -58,7 +58,7 @@ var getIconsTool = exports.getIconsTool = /*#__PURE__*/function () {
58
58
  }
59
59
  }, _callee);
60
60
  }));
61
- return function getIconsTool() {
61
+ return function getAllIconsTool() {
62
62
  return _ref3.apply(this, arguments);
63
63
  };
64
64
  }();
@@ -4,18 +4,18 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.listGetTokensTool = exports.getTokensTool = void 0;
7
+ exports.listGetAllTokensTool = exports.getAllTokensTool = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
10
  var _zod = require("zod");
11
11
  var _zodToJsonSchema = require("zod-to-json-schema");
12
12
  var _tokenMetadata = require("@atlaskit/tokens/token-metadata");
13
13
  var inputSchema = _zod.z.object({});
14
- var listGetTokensTool = exports.listGetTokensTool = {
15
- name: 'get_tokens',
16
- description: "You MUST use this to fetch all Atlassian Design System tokens and parse their names and descriptions (provided in JSON format) before working with tokens.\nThese tokens are used in place of hardcoded values; you should never use a hardcoded value where a token value is appropriate.\nThe resulting token name is used inside of the `token()` function, eg.:\n```tsx\nimport { token } from '@atlaskit/tokens';\nconst styles = css({ color: token('color.text') });\n```\n",
14
+ var listGetAllTokensTool = exports.listGetAllTokensTool = {
15
+ name: 'get_all_tokens',
16
+ description: "You SHOULD call this when you need complete guidance on what tokens to use, but you SHOULD use the `search_tokens` tool to find specific tokens instead.\n\tThese tokens are used in place of hardcoded values; you should never use a hardcoded value where a token value is appropriate.\n\tThe resulting token name is used inside of the `token()` function, eg.:\n\t```tsx\n\timport { token } from '@atlaskit/tokens';\n\tconst styles = css({ color: token('color.text') });\n\t```\n\t",
17
17
  annotations: {
18
- title: 'Get ADS tokens',
18
+ title: 'Get all ADS tokens',
19
19
  readOnlyHint: true,
20
20
  destructiveHint: false,
21
21
  idempotentHint: true,
@@ -23,7 +23,7 @@ var listGetTokensTool = exports.listGetTokensTool = {
23
23
  },
24
24
  inputSchema: (0, _zodToJsonSchema.zodToJsonSchema)(inputSchema)
25
25
  };
26
- var getTokensTool = exports.getTokensTool = /*#__PURE__*/function () {
26
+ var getAllTokensTool = exports.getAllTokensTool = /*#__PURE__*/function () {
27
27
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
28
28
  return _regenerator.default.wrap(function _callee$(_context) {
29
29
  while (1) switch (_context.prev = _context.next) {
@@ -36,7 +36,6 @@ var getTokensTool = exports.getTokensTool = /*#__PURE__*/function () {
36
36
  type: 'text',
37
37
  text: JSON.stringify({
38
38
  name: token.name,
39
- description: token.description,
40
39
  exampleValue: token.exampleValue
41
40
  }, null, 2)
42
41
  };
@@ -48,7 +47,7 @@ var getTokensTool = exports.getTokensTool = /*#__PURE__*/function () {
48
47
  }
49
48
  }, _callee);
50
49
  }));
51
- return function getTokensTool() {
50
+ return function getAllTokensTool() {
52
51
  return _ref.apply(this, arguments);
53
52
  };
54
53
  }();
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.searchIconsTool = exports.listSearchIconsTool = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
+ var _fuse = _interopRequireDefault(require("fuse.js"));
12
+ var _zod = require("zod");
13
+ var _zodToJsonSchema = require("zod-to-json-schema");
14
+ var _metadata = require("@atlaskit/icon/metadata");
15
+ var inputSchema = _zod.z.object({
16
+ terms: _zod.z.array(_zod.z.string()).describe('Search term(s) to find icons by name, keywords, or categorization'),
17
+ limit: _zod.z.number().optional().default(1).describe('Maximum number of results per term to return (default: 1)'),
18
+ exactName: _zod.z.boolean().optional().default(false).describe('Whether to search for exact match only for the icon name')
19
+ });
20
+ var icons = Object.entries(_metadata.coreIconMetadata).map(function (_ref) {
21
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
22
+ _key = _ref2[0],
23
+ icon = _ref2[1];
24
+ return {
25
+ componentName: icon.componentName,
26
+ package: icon.package,
27
+ categorization: icon.categorization,
28
+ keywords: icon.keywords,
29
+ status: icon.status,
30
+ usage: icon.usage,
31
+ type: icon.type,
32
+ shouldRecommendSmallIcon: icon.shouldRecommendSmallIcon
33
+ };
34
+ }).filter(function (icon) {
35
+ return icon.status === 'published';
36
+ });
37
+ var listSearchIconsTool = exports.listSearchIconsTool = {
38
+ name: 'search_icons',
39
+ description: "You SHOULD Search for Atlassian Design System icons based on multiple query strings (if there's multiple candidates of icon names, categorization or keywords, you SHOULD pass them in a single call). You SHOULD use default `limit` value of 1 first and only set a higher limit like 5 or 10 if you can't find the icon you need). Fallback to `get_all_icons` if nothing is found). This tool searches through component names, icon names, keywords, categorization, type and usage to find the most relevant design icons.\n\n\tThe search will match against:\n\t- Icon component names (e.g., \"AddIcon\", \"DeleteIcon\", \"EditIcon\")\n\t- Icon keywords (descriptive terms associated with icons)\n\t- Icon categorization (e.g., \"single-purpose\", \"multi-purpose\", \"utility\")\n\t- Icon usage descriptions (usage guidelines for the icon)\n\n\tThe results include the icon's component name, package path, and usage guidelines.\n\n\tUsage pattern for found icons:\n\t```tsx\n\timport AddIcon from '@atlaskit/icon/core/add';\n\n\t// Usage in isolation\n\t<AddIcon label=\"Add\" size=\"small\" />\n\n\t// Usage with a button\n\timport Button from '@atlaskit/button/new';\n\t<Button iconAfter={AddIcon}>Create</Button>\n\t```\n\n\tYou SHOULD check proper usage (props, example usage, etc.) of the icon component using `get_component_details` tool before using this tool.\n\t",
40
+ annotations: {
41
+ title: 'Search ADS icons',
42
+ readOnlyHint: true,
43
+ destructiveHint: false,
44
+ idempotentHint: true,
45
+ openWorldHint: true
46
+ },
47
+ inputSchema: (0, _zodToJsonSchema.zodToJsonSchema)(inputSchema)
48
+ };
49
+ var cleanQuery = function cleanQuery(query) {
50
+ return query.trim().toLowerCase().replace(/\s+/g, '');
51
+ };
52
+ var searchIconsTool = exports.searchIconsTool = /*#__PURE__*/function () {
53
+ var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(params) {
54
+ var terms, _params$limit, limit, _params$exactName, exactName, searchTerms, exactNameMatches, fuse, results, matchedIcons;
55
+ return _regenerator.default.wrap(function _callee$(_context) {
56
+ while (1) switch (_context.prev = _context.next) {
57
+ case 0:
58
+ terms = params.terms, _params$limit = params.limit, limit = _params$limit === void 0 ? 1 : _params$limit, _params$exactName = params.exactName, exactName = _params$exactName === void 0 ? false : _params$exactName;
59
+ searchTerms = terms.filter(Boolean).map(cleanQuery);
60
+ if (!exactName) {
61
+ _context.next = 6;
62
+ break;
63
+ }
64
+ // for each search term, search for the exact match
65
+ exactNameMatches = searchTerms.map(function (term) {
66
+ return icons.find(function (icon) {
67
+ return icon.componentName.toLowerCase() === term.toLowerCase();
68
+ });
69
+ }).filter(Boolean);
70
+ if (!(exactNameMatches.length > 0)) {
71
+ _context.next = 6;
72
+ break;
73
+ }
74
+ return _context.abrupt("return", {
75
+ content: [{
76
+ type: 'text',
77
+ text: JSON.stringify(exactNameMatches)
78
+ }]
79
+ });
80
+ case 6:
81
+ // use Fuse.js to fuzzy-search through the icons
82
+ fuse = new _fuse.default(icons, {
83
+ keys: [{
84
+ name: 'componentName',
85
+ weight: 3
86
+ }, {
87
+ name: 'iconName',
88
+ weight: 3
89
+ }, {
90
+ name: 'keywords',
91
+ weight: 2
92
+ }, {
93
+ name: 'categorization',
94
+ weight: 1
95
+ }, {
96
+ name: 'type',
97
+ weight: 1
98
+ }, {
99
+ name: 'usage',
100
+ weight: 1
101
+ }],
102
+ threshold: 0.4
103
+ }); // every search term, search for the results
104
+ results = searchTerms.map(function (term) {
105
+ // always search exact match from the icons
106
+ var exactNameMatch = icons.find(function (icon) {
107
+ return icon.componentName.toLowerCase() === term.toLowerCase();
108
+ });
109
+ if (exactNameMatch) {
110
+ return [{
111
+ item: exactNameMatch
112
+ }];
113
+ }
114
+ return fuse.search(term).slice(0, limit);
115
+ }).flat();
116
+ matchedIcons = results.map(function (result) {
117
+ return {
118
+ componentName: result.item.componentName,
119
+ package: result.item.package,
120
+ usage: result.item.usage
121
+ };
122
+ });
123
+ return _context.abrupt("return", {
124
+ content: [{
125
+ type: 'text',
126
+ text: JSON.stringify(matchedIcons)
127
+ }]
128
+ });
129
+ case 10:
130
+ case "end":
131
+ return _context.stop();
132
+ }
133
+ }, _callee);
134
+ }));
135
+ return function searchIconsTool(_x) {
136
+ return _ref3.apply(this, arguments);
137
+ };
138
+ }();
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.searchTokensTool = exports.listSearchTokensTool = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _fuse = _interopRequireDefault(require("fuse.js"));
11
+ var _zod = require("zod");
12
+ var _zodToJsonSchema = require("zod-to-json-schema");
13
+ var _tokenMetadata = require("@atlaskit/tokens/token-metadata");
14
+ var inputSchema = _zod.z.object({
15
+ terms: _zod.z.array(_zod.z.string()).describe('Search term(s) to find tokens by name or description'),
16
+ limit: _zod.z.number().optional().default(1).describe('Maximum number of results per term to return (default: 1)'),
17
+ exactName: _zod.z.boolean().optional().default(false).describe('Whether to search for exact match only for the token name')
18
+ });
19
+ var cleanQuery = function cleanQuery(query) {
20
+ return query.trim().toLowerCase().replace(/\s+/g, '');
21
+ };
22
+ var listSearchTokensTool = exports.listSearchTokensTool = {
23
+ name: 'search_tokens',
24
+ description: "You SHOULD Search for Atlassian Design System tokens based on multiple query strings (if there's multiple candidates of token names, descriptions or example values, you SHOULD pass them in a single call). You SHOULD use default `limit` value of 1 first and only set a higher limit like 5 or 10 if you can't find the token you need). Fallback to `get_all_tokens` if nothing is found). This tool searches through token names, descriptions, and example values to find the most relevant design tokens.\n\nThe search will match against:\n- Token names (e.g., \"color.text\", \"space.100\", \"border.radius\")\n- Token descriptions\n- Token example values (eg. \"#2898BD\" -> \"color.icon.accent.teal\")\n\nThe results include the token's name and example value.\n\nUsage pattern for found tokens:\n```tsx\nimport { token } from '@atlaskit/tokens';\n\nconst styles = css({\ncolor: token('color.text'),\npadding: token('space.100'),\nborderRadius: token('border.radius'),\n});\n```\n",
25
+ annotations: {
26
+ title: 'Search ADS tokens',
27
+ readOnlyHint: true,
28
+ destructiveHint: false,
29
+ idempotentHint: true,
30
+ openWorldHint: true
31
+ },
32
+ inputSchema: (0, _zodToJsonSchema.zodToJsonSchema)(inputSchema)
33
+ };
34
+ var searchTokensTool = exports.searchTokensTool = /*#__PURE__*/function () {
35
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(params) {
36
+ var terms, _params$limit, limit, _params$exactName, exactName, searchTerms, exactNameMatches, fuse, results, matchedTokens;
37
+ return _regenerator.default.wrap(function _callee$(_context) {
38
+ while (1) switch (_context.prev = _context.next) {
39
+ case 0:
40
+ terms = params.terms, _params$limit = params.limit, limit = _params$limit === void 0 ? 1 : _params$limit, _params$exactName = params.exactName, exactName = _params$exactName === void 0 ? false : _params$exactName;
41
+ searchTerms = terms.filter(Boolean).map(cleanQuery);
42
+ if (!exactName) {
43
+ _context.next = 6;
44
+ break;
45
+ }
46
+ // for each search term, search for the exact match
47
+ exactNameMatches = searchTerms.map(function (term) {
48
+ return _tokenMetadata.tokens.find(function (token) {
49
+ return token.name.toLowerCase() === term.toLowerCase();
50
+ });
51
+ }).filter(Boolean);
52
+ if (!(exactNameMatches.length > 0)) {
53
+ _context.next = 6;
54
+ break;
55
+ }
56
+ return _context.abrupt("return", {
57
+ content: [{
58
+ type: 'text',
59
+ text: JSON.stringify(exactNameMatches.map(function (token) {
60
+ return {
61
+ name: token.name,
62
+ exampleValue: token.exampleValue
63
+ };
64
+ }))
65
+ }]
66
+ });
67
+ case 6:
68
+ // use Fuse.js to fuzzy-search for the tokens
69
+ fuse = new _fuse.default(_tokenMetadata.tokens, {
70
+ keys: [{
71
+ name: 'name',
72
+ weight: 3
73
+ }, {
74
+ name: 'description',
75
+ weight: 2
76
+ }, {
77
+ name: 'exampleValue',
78
+ weight: 1
79
+ }],
80
+ threshold: 0.4
81
+ });
82
+ results = searchTerms.map(function (term) {
83
+ return fuse.search(term).slice(0, limit);
84
+ }).flat();
85
+ matchedTokens = results.map(function (result) {
86
+ return {
87
+ name: result.item.name,
88
+ exampleValue: result.item.exampleValue
89
+ };
90
+ });
91
+ return _context.abrupt("return", {
92
+ content: [{
93
+ type: 'text',
94
+ text: JSON.stringify(matchedTokens)
95
+ }]
96
+ });
97
+ case 10:
98
+ case "end":
99
+ return _context.stop();
100
+ }
101
+ }, _callee);
102
+ }));
103
+ return function searchTokensTool(_x) {
104
+ return _ref.apply(this, arguments);
105
+ };
106
+ }();
@@ -254,7 +254,7 @@ var accessibilityFixes = exports.accessibilityFixes = {
254
254
  description: 'Provide table caption for complex tables',
255
255
  before: "<table>\n <thead>...</thead>\n</table>",
256
256
  after: "<table>\n <caption>User account information by department</caption>\n <thead>...</thead>\n</table>",
257
- explanation: 'Captions provide context about the table\'s purpose and structure.'
257
+ explanation: "Captions provide context about the table's purpose and structure."
258
258
  }],
259
259
  bestPractices: ['Use th elements for headers', 'Add scope attributes (col, row)', 'Provide table captions when helpful', 'Use thead, tbody, tfoot for structure']
260
260
  },
@@ -5,10 +5,12 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprot
5
5
  import { instructions } from './instructions';
6
6
  import { analyzeAccessibilityTool, analyzeLocalhostAccessibilityTool, listAnalyzeAccessibilityTool, listAnalyzeLocalhostAccessibilityTool } from './tools/analyze-accessibility';
7
7
  import { getAccessibilityGuidelinesTool, listGetAccessibilityGuidelinesTool } from './tools/get-accessibility-guidelines';
8
+ import { getAllIconsTool, listGetAllIconsTool } from './tools/get-all-icons';
9
+ import { getAllTokensTool, listGetAllTokensTool } from './tools/get-all-tokens';
8
10
  import { getComponentDetailsTool, listGetComponentDetailsTool } from './tools/get-component-details';
9
11
  import { getComponentsTool, listGetComponentsTool } from './tools/get-components';
10
- import { getIconsTool, listGetIconsTool } from './tools/get-icons';
11
- import { getTokensTool, listGetTokensTool } from './tools/get-tokens';
12
+ import { listSearchIconsTool, searchIconsTool } from './tools/search-icons';
13
+ import { listSearchTokensTool, searchTokensTool } from './tools/search-tokens';
12
14
  import { listSuggestAccessibilityFixesTool, suggestAccessibilityFixesTool } from './tools/suggest-accessibility-fixes';
13
15
 
14
16
  // eslint-disable-next-line import/no-extraneous-dependencies -- this uses require because not all node versions this package supports use the same import assertions/attributes
@@ -25,14 +27,16 @@ const server = new Server({
25
27
  });
26
28
  server.setRequestHandler(ListToolsRequestSchema, async () => {
27
29
  return {
28
- tools: [listGetTokensTool, listGetComponentsTool, listGetComponentDetailsTool, listGetIconsTool, listAnalyzeAccessibilityTool, listAnalyzeLocalhostAccessibilityTool, listGetAccessibilityGuidelinesTool, listSuggestAccessibilityFixesTool]
30
+ tools: [listGetAllTokensTool, listGetComponentsTool, listGetComponentDetailsTool, listGetAllIconsTool, listSearchIconsTool, listSearchTokensTool, listAnalyzeAccessibilityTool, listAnalyzeLocalhostAccessibilityTool, listGetAccessibilityGuidelinesTool, listSuggestAccessibilityFixesTool]
29
31
  };
30
32
  });
31
33
  const callTools = {
32
- get_tokens: getTokensTool,
34
+ get_all_tokens: getAllTokensTool,
35
+ search_tokens: searchTokensTool,
33
36
  get_components: getComponentsTool,
34
37
  get_component_details: getComponentDetailsTool,
35
- get_icons: getIconsTool,
38
+ get_all_icons: getAllIconsTool,
39
+ search_icons: searchIconsTool,
36
40
  analyze_accessibility: analyzeAccessibilityTool,
37
41
  analyze_localhost_accessibility: analyzeLocalhostAccessibilityTool,
38
42
  get_accessibility_guidelines: getAccessibilityGuidelinesTool,
@@ -9,4 +9,8 @@ Accessibility Tools Available:
9
9
  - analyze_accessibility: Analyze React component code for accessibility violations
10
10
  - get_accessibility_guidelines: Get specific accessibility guidelines and best practices
11
11
  - suggest_accessibility_fixes: Get specific fix suggestions for accessibility violations
12
+ - get_all_tokens: Get all tokens and their example values
13
+ - search_tokens: Search for token(s) and their example value(s)
14
+ - get_all_icons: Get all icons and their usage
15
+ - search_icons: Search for icon(s) and their usage
12
16
  `;
@@ -10,9 +10,9 @@ const icons = Object.entries(coreIconMetadata).map(([_key, icon]) => ({
10
10
  type: icon.type,
11
11
  shouldRecommendSmallIcon: icon.shouldRecommendSmallIcon
12
12
  }));
13
- export const listGetIconsTool = {
14
- name: 'get_icons',
15
- description: `You MUST use this to fetch all Atlassian Design System icons and parse their names, package, and understand how they're used (provided in JSON format) before working with iconography.
13
+ export const listGetAllIconsTool = {
14
+ name: 'get_all_icons',
15
+ description: `You SHOULD call this when you need complete guidance on what icons to use, but you SHOULD use the \`search_icons\` tool to find specific icons instead.
16
16
  These are the only icons to be used in modern code, though other legacy icons may still be found, these are not to be used by you, but you can keep them if you see them in existing code.
17
17
  The resulting icon name and package is often like this:
18
18
  \`\`\`tsx
@@ -35,7 +35,7 @@ import Button from '@atlaskit/button/new';
35
35
  },
36
36
  inputSchema: emptyInputSchema
37
37
  };
38
- export const getIconsTool = async () => ({
38
+ export const getAllIconsTool = async () => ({
39
39
  content: icons.map(icon => ({
40
40
  // NOTE: Ideally one day the MCP would support structured content…
41
41
  // eg. `type: 'object', data: icon`
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import { tokens } from '@atlaskit/tokens/token-metadata';
4
+ const inputSchema = z.object({});
5
+ export const listGetAllTokensTool = {
6
+ name: 'get_all_tokens',
7
+ description: `You SHOULD call this when you need complete guidance on what tokens to use, but you SHOULD use the \`search_tokens\` tool to find specific tokens instead.
8
+ These tokens are used in place of hardcoded values; you should never use a hardcoded value where a token value is appropriate.
9
+ The resulting token name is used inside of the \`token()\` function, eg.:
10
+ \`\`\`tsx
11
+ import { token } from '@atlaskit/tokens';
12
+ const styles = css({ color: token('color.text') });
13
+ \`\`\`
14
+ `,
15
+ annotations: {
16
+ title: 'Get all ADS tokens',
17
+ readOnlyHint: true,
18
+ destructiveHint: false,
19
+ idempotentHint: true,
20
+ openWorldHint: true
21
+ },
22
+ inputSchema: zodToJsonSchema(inputSchema)
23
+ };
24
+ export const getAllTokensTool = async () => ({
25
+ content: tokens.map(token => ({
26
+ // NOTE: Ideally one day the MCP would support structured content…
27
+ // eg. `type: 'object', data: token`
28
+ type: 'text',
29
+ text: JSON.stringify({
30
+ name: token.name,
31
+ exampleValue: token.exampleValue
32
+ }, null, 2)
33
+ }))
34
+ });
@@ -0,0 +1,126 @@
1
+ import Fuse from 'fuse.js';
2
+ import { z } from 'zod';
3
+ import { zodToJsonSchema } from 'zod-to-json-schema';
4
+ import { coreIconMetadata } from '@atlaskit/icon/metadata';
5
+ const inputSchema = z.object({
6
+ terms: z.array(z.string()).describe('Search term(s) to find icons by name, keywords, or categorization'),
7
+ limit: z.number().optional().default(1).describe('Maximum number of results per term to return (default: 1)'),
8
+ exactName: z.boolean().optional().default(false).describe('Whether to search for exact match only for the icon name')
9
+ });
10
+ const icons = Object.entries(coreIconMetadata).map(([_key, icon]) => ({
11
+ componentName: icon.componentName,
12
+ package: icon.package,
13
+ categorization: icon.categorization,
14
+ keywords: icon.keywords,
15
+ status: icon.status,
16
+ usage: icon.usage,
17
+ type: icon.type,
18
+ shouldRecommendSmallIcon: icon.shouldRecommendSmallIcon
19
+ })).filter(icon => icon.status === 'published');
20
+ export const listSearchIconsTool = {
21
+ name: 'search_icons',
22
+ description: `You SHOULD Search for Atlassian Design System icons based on multiple query strings (if there's multiple candidates of icon names, categorization or keywords, you SHOULD pass them in a single call). You SHOULD use default \`limit\` value of 1 first and only set a higher limit like 5 or 10 if you can't find the icon you need). Fallback to \`get_all_icons\` if nothing is found). This tool searches through component names, icon names, keywords, categorization, type and usage to find the most relevant design icons.
23
+
24
+ The search will match against:
25
+ - Icon component names (e.g., "AddIcon", "DeleteIcon", "EditIcon")
26
+ - Icon keywords (descriptive terms associated with icons)
27
+ - Icon categorization (e.g., "single-purpose", "multi-purpose", "utility")
28
+ - Icon usage descriptions (usage guidelines for the icon)
29
+
30
+ The results include the icon's component name, package path, and usage guidelines.
31
+
32
+ Usage pattern for found icons:
33
+ \`\`\`tsx
34
+ import AddIcon from '@atlaskit/icon/core/add';
35
+
36
+ // Usage in isolation
37
+ <AddIcon label="Add" size="small" />
38
+
39
+ // Usage with a button
40
+ import Button from '@atlaskit/button/new';
41
+ <Button iconAfter={AddIcon}>Create</Button>
42
+ \`\`\`
43
+
44
+ You SHOULD check proper usage (props, example usage, etc.) of the icon component using \`get_component_details\` tool before using this tool.
45
+ `,
46
+ annotations: {
47
+ title: 'Search ADS icons',
48
+ readOnlyHint: true,
49
+ destructiveHint: false,
50
+ idempotentHint: true,
51
+ openWorldHint: true
52
+ },
53
+ inputSchema: zodToJsonSchema(inputSchema)
54
+ };
55
+ const cleanQuery = query => query.trim().toLowerCase().replace(/\s+/g, '');
56
+ export const searchIconsTool = async params => {
57
+ const {
58
+ terms,
59
+ limit = 1,
60
+ exactName = false
61
+ } = params;
62
+ const searchTerms = terms.filter(Boolean).map(cleanQuery);
63
+ if (exactName) {
64
+ // for each search term, search for the exact match
65
+ const exactNameMatches = searchTerms.map(term => {
66
+ return icons.find(icon => icon.componentName.toLowerCase() === term.toLowerCase());
67
+ }).filter(Boolean);
68
+ if (exactNameMatches.length > 0) {
69
+ return {
70
+ content: [{
71
+ type: 'text',
72
+ text: JSON.stringify(exactNameMatches)
73
+ }]
74
+ };
75
+ }
76
+ }
77
+
78
+ // use Fuse.js to fuzzy-search through the icons
79
+ const fuse = new Fuse(icons, {
80
+ keys: [{
81
+ name: 'componentName',
82
+ weight: 3
83
+ }, {
84
+ name: 'iconName',
85
+ weight: 3
86
+ }, {
87
+ name: 'keywords',
88
+ weight: 2
89
+ }, {
90
+ name: 'categorization',
91
+ weight: 1
92
+ }, {
93
+ name: 'type',
94
+ weight: 1
95
+ }, {
96
+ name: 'usage',
97
+ weight: 1
98
+ }],
99
+ threshold: 0.4
100
+ });
101
+
102
+ // every search term, search for the results
103
+ const results = searchTerms.map(term => {
104
+ // always search exact match from the icons
105
+ const exactNameMatch = icons.find(icon => icon.componentName.toLowerCase() === term.toLowerCase());
106
+ if (exactNameMatch) {
107
+ return [{
108
+ item: exactNameMatch
109
+ }];
110
+ }
111
+ return fuse.search(term).slice(0, limit);
112
+ }).flat();
113
+ const matchedIcons = results.map(result => {
114
+ return {
115
+ componentName: result.item.componentName,
116
+ package: result.item.package,
117
+ usage: result.item.usage
118
+ };
119
+ });
120
+ return {
121
+ content: [{
122
+ type: 'text',
123
+ text: JSON.stringify(matchedIcons)
124
+ }]
125
+ };
126
+ };