@atlaskit/ads-mcp 0.18.0 → 0.19.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 (96) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -2
  3. package/dist/cjs/helpers/fuse-multi-term.js +130 -0
  4. package/dist/cjs/helpers/index.js +15 -1
  5. package/dist/cjs/index.js +28 -14
  6. package/dist/cjs/instructions.js +1 -1
  7. package/dist/cjs/tools/analyze-a11y/index.js +12 -12
  8. package/dist/cjs/tools/get-a11y-guidelines/index.js +3 -3
  9. package/dist/cjs/tools/{get-components → get-all-components}/index.js +6 -6
  10. package/dist/cjs/tools/get-all-components/load-all-components.js +10 -0
  11. package/dist/cjs/tools/get-all-icons/index.js +1 -1
  12. package/dist/cjs/tools/get-all-tokens/index.js +1 -1
  13. package/dist/cjs/tools/get-guidelines/index.js +4 -4
  14. package/dist/cjs/tools/get-lint-rules/index.js +5 -5
  15. package/dist/cjs/tools/i18n-conversion/index.js +3 -3
  16. package/dist/cjs/tools/migration-guides/index.js +3 -3
  17. package/dist/cjs/tools/plan/index.js +13 -17
  18. package/dist/cjs/tools/search-components/index.js +44 -65
  19. package/dist/cjs/tools/search-icons/index.js +42 -68
  20. package/dist/cjs/tools/search-tokens/index.js +56 -43
  21. package/dist/cjs/tools/suggest-a11y-fixes/index.js +7 -7
  22. package/dist/es2019/helpers/fuse-multi-term.js +98 -0
  23. package/dist/es2019/helpers/index.js +1 -0
  24. package/dist/es2019/index.js +81 -83
  25. package/dist/es2019/instructions.js +2 -1
  26. package/dist/es2019/tools/analyze-a11y/index.js +28 -12
  27. package/dist/es2019/tools/get-a11y-guidelines/index.js +10 -3
  28. package/dist/es2019/tools/{get-components → get-all-components}/index.js +9 -4
  29. package/dist/es2019/tools/get-all-components/load-all-components.js +4 -0
  30. package/dist/es2019/tools/get-all-icons/index.js +6 -1
  31. package/dist/es2019/tools/get-all-tokens/index.js +6 -1
  32. package/dist/es2019/tools/get-guidelines/index.js +20 -7
  33. package/dist/es2019/tools/get-lint-rules/index.js +12 -8
  34. package/dist/es2019/tools/i18n-conversion/index.js +10 -13
  35. package/dist/es2019/tools/migration-guides/index.js +10 -4
  36. package/dist/es2019/tools/plan/index.js +25 -25
  37. package/dist/es2019/tools/search-components/index.js +42 -56
  38. package/dist/es2019/tools/search-icons/index.js +37 -62
  39. package/dist/es2019/tools/search-tokens/index.js +54 -45
  40. package/dist/es2019/tools/suggest-a11y-fixes/index.js +16 -7
  41. package/dist/esm/helpers/fuse-multi-term.js +122 -0
  42. package/dist/esm/helpers/index.js +1 -0
  43. package/dist/esm/index.js +28 -14
  44. package/dist/esm/instructions.js +1 -1
  45. package/dist/esm/tools/analyze-a11y/index.js +12 -12
  46. package/dist/esm/tools/get-a11y-guidelines/index.js +3 -3
  47. package/dist/esm/tools/{get-components → get-all-components}/index.js +5 -5
  48. package/dist/esm/tools/get-all-components/load-all-components.js +4 -0
  49. package/dist/esm/tools/get-all-icons/index.js +1 -1
  50. package/dist/esm/tools/get-all-tokens/index.js +1 -1
  51. package/dist/esm/tools/get-guidelines/index.js +4 -4
  52. package/dist/esm/tools/get-lint-rules/index.js +5 -5
  53. package/dist/esm/tools/i18n-conversion/index.js +3 -3
  54. package/dist/esm/tools/migration-guides/index.js +3 -3
  55. package/dist/esm/tools/plan/index.js +13 -17
  56. package/dist/esm/tools/search-components/index.js +45 -66
  57. package/dist/esm/tools/search-icons/index.js +43 -69
  58. package/dist/esm/tools/search-tokens/index.js +57 -44
  59. package/dist/esm/tools/suggest-a11y-fixes/index.js +7 -7
  60. package/dist/types/helpers/fuse-multi-term.d.ts +45 -0
  61. package/dist/types/helpers/index.d.ts +1 -0
  62. package/dist/types/instructions.d.ts +1 -1
  63. package/dist/types/tools/{get-components → get-all-components}/index.d.ts +2 -2
  64. package/dist/types/tools/plan/index.d.ts +1 -4
  65. package/dist/types/tools/search-components/index.d.ts +1 -4
  66. package/dist/types/tools/search-icons/index.d.ts +1 -4
  67. package/dist/types/tools/search-tokens/index.d.ts +1 -4
  68. package/dist/types-ts4.5/helpers/fuse-multi-term.d.ts +45 -0
  69. package/dist/types-ts4.5/helpers/index.d.ts +1 -0
  70. package/dist/types-ts4.5/instructions.d.ts +1 -1
  71. package/dist/types-ts4.5/tools/{get-components → get-all-components}/index.d.ts +2 -2
  72. package/dist/types-ts4.5/tools/plan/index.d.ts +1 -4
  73. package/dist/types-ts4.5/tools/search-components/index.d.ts +1 -4
  74. package/dist/types-ts4.5/tools/search-icons/index.d.ts +1 -4
  75. package/dist/types-ts4.5/tools/search-tokens/index.d.ts +1 -4
  76. package/package.json +5 -5
  77. package/dist/cjs/tools/get-components/load-all-components.js +0 -16
  78. package/dist/es2019/tools/get-components/load-all-components.js +0 -10
  79. package/dist/esm/tools/get-components/load-all-components.js +0 -10
  80. /package/dist/cjs/tools/{get-components → get-all-components}/components.codegen.js +0 -0
  81. /package/dist/cjs/tools/{get-components → get-all-components}/components.js +0 -0
  82. /package/dist/cjs/tools/{get-components → get-all-components}/types.js +0 -0
  83. /package/dist/es2019/tools/{get-components → get-all-components}/components.codegen.js +0 -0
  84. /package/dist/es2019/tools/{get-components → get-all-components}/components.js +0 -0
  85. /package/dist/es2019/tools/{get-components → get-all-components}/types.js +0 -0
  86. /package/dist/esm/tools/{get-components → get-all-components}/components.codegen.js +0 -0
  87. /package/dist/esm/tools/{get-components → get-all-components}/components.js +0 -0
  88. /package/dist/esm/tools/{get-components → get-all-components}/types.js +0 -0
  89. /package/dist/types/tools/{get-components → get-all-components}/components.codegen.d.ts +0 -0
  90. /package/dist/types/tools/{get-components → get-all-components}/components.d.ts +0 -0
  91. /package/dist/types/tools/{get-components → get-all-components}/load-all-components.d.ts +0 -0
  92. /package/dist/types/tools/{get-components → get-all-components}/types.d.ts +0 -0
  93. /package/dist/types-ts4.5/tools/{get-components → get-all-components}/components.codegen.d.ts +0 -0
  94. /package/dist/types-ts4.5/tools/{get-components → get-all-components}/components.d.ts +0 -0
  95. /package/dist/types-ts4.5/tools/{get-components → get-all-components}/load-all-components.d.ts +0 -0
  96. /package/dist/types-ts4.5/tools/{get-components → get-all-components}/types.d.ts +0 -0
@@ -1,19 +1,19 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
4
  /* eslint-disable-next-line import/extensions -- MCP SDK requires .js extensions for ESM imports */
4
5
 
5
6
  import Fuse from 'fuse.js';
6
7
  import { z } from 'zod';
7
- import { cleanQuery, zodToJsonSchema } from '../../helpers';
8
- import { loadAllComponents } from '../get-components/load-all-components';
8
+ import { cleanQuery, mergeMultiTermFuseResults, zodToJsonSchema } from '../../helpers';
9
+ import { loadAllComponents } from '../get-all-components/load-all-components';
9
10
  export var searchComponentsInputSchema = z.object({
10
- terms: z.array(z.string()).describe('An array of search terms to find components by name, package name, description, or example, eg. `["button", "input", "select"]`'),
11
- limit: z.number().default(1).describe('Maximum number of results per search term in the array (default: 1)').optional(),
12
- exactName: z.boolean().default(false).describe('Enable to explicitly search components by the exact name match (when you know the name, but need more details)').optional()
11
+ terms: z.array(z.string()).describe('Required: one or more search terms (fuzzy over name, package, category, description, keywords, examples). Example: `["button", "modal", "select"]`.'),
12
+ limit: z.number().default(2).describe('Max matches **per term** (default 2).').optional()
13
13
  });
14
14
  export var listSearchComponentsTool = {
15
15
  name: 'ads_search_components',
16
- description: 'Search for Atlassian Design System components.',
16
+ description: "Searches the bundled Atlassian Design System (ADS) component catalog. Returns JSON objects with **name**, **package**, **examples**, and **props** for each match (trimmed payload).\n\nWHEN TO USE:\n**Selecting which ADS component to use**\u2014package name, examples, and props\u2014before implementation. Use when composing a new view or swapping a primitive. Prefer `ads_plan` when you also need token and icon discovery in one shot.",
17
17
  annotations: {
18
18
  title: 'Search ADS components',
19
19
  readOnlyHint: true,
@@ -23,9 +23,7 @@ export var listSearchComponentsTool = {
23
23
  },
24
24
  inputSchema: zodToJsonSchema(searchComponentsInputSchema)
25
25
  };
26
-
27
- // Clean component result to only return name, package name, example, and props
28
- var cleanComponentResult = function cleanComponentResult(result) {
26
+ var buildComponentResult = function buildComponentResult(result) {
29
27
  return {
30
28
  name: result.name,
31
29
  package: result.package,
@@ -34,52 +32,29 @@ var cleanComponentResult = function cleanComponentResult(result) {
34
32
  };
35
33
  };
36
34
  export var searchComponentsTool = /*#__PURE__*/function () {
37
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(params) {
38
- var terms, _params$limit, limit, _params$exactName, exactName, searchTerms, components, exactNameMatches, fuse, results, uniqueResults;
35
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
36
+ var terms, _ref$limit, limit, searchTerms, components, fuse, matchedItems;
39
37
  return _regeneratorRuntime.wrap(function _callee$(_context) {
40
38
  while (1) switch (_context.prev = _context.next) {
41
39
  case 0:
42
- 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;
43
- searchTerms = terms.filter(Boolean).map(cleanQuery);
40
+ terms = _ref.terms, _ref$limit = _ref.limit, limit = _ref$limit === void 0 ? 2 : _ref$limit;
41
+ searchTerms = _toConsumableArray(new Set(terms.filter(Boolean).map(cleanQuery)));
44
42
  if (searchTerms.length) {
45
43
  _context.next = 4;
46
44
  break;
47
45
  }
48
46
  return _context.abrupt("return", {
49
- isError: true,
50
47
  content: [{
51
48
  type: 'text',
52
- text: "Error: Required parameter 'terms' is missing or empty"
49
+ text: '[]'
53
50
  }]
54
51
  });
55
52
  case 4:
56
53
  components = loadAllComponents();
57
- if (!exactName) {
58
- _context.next = 9;
59
- break;
60
- }
61
- // for each search term, search for the exact match
62
- exactNameMatches = searchTerms.map(function (term) {
63
- return components.find(function (component) {
64
- return component.name.toLowerCase() === term.toLowerCase();
65
- });
66
- }).filter(Boolean);
67
- if (!(exactNameMatches.length > 0)) {
68
- _context.next = 9;
69
- break;
70
- }
71
- return _context.abrupt("return", {
72
- content: [{
73
- type: 'text',
74
- text: JSON.stringify(exactNameMatches.map(cleanComponentResult))
75
- }]
76
- });
77
- case 9:
78
- // use Fuse.js to fuzzy-search through the components
79
54
  fuse = new Fuse(components, {
80
55
  keys: [{
81
56
  name: 'name',
82
- weight: 3
57
+ weight: 5
83
58
  }, {
84
59
  name: 'package',
85
60
  weight: 3
@@ -89,30 +64,42 @@ export var searchComponentsTool = /*#__PURE__*/function () {
89
64
  }, {
90
65
  name: 'description',
91
66
  weight: 2
67
+ }, {
68
+ name: 'keywords',
69
+ weight: 2
70
+ }, {
71
+ name: 'usageGuidelines',
72
+ weight: 2
73
+ }, {
74
+ name: 'contentGuidelines',
75
+ weight: 1
76
+ }, {
77
+ name: 'accessibilityGuidelines',
78
+ weight: 1
92
79
  }, {
93
80
  name: 'examples',
94
81
  weight: 1
95
82
  }],
96
- threshold: 0.4
97
- }); // every search term, search for the results
98
- results = searchTerms.map(function (term) {
99
- // always search exact match from the components first
100
- var exactNameMatch = components.find(function (component) {
101
- return component.name.toLowerCase() === term.toLowerCase();
102
- });
103
- if (exactNameMatch) {
104
- return [{
105
- item: exactNameMatch
106
- }];
83
+ threshold: 0.4,
84
+ distance: 80,
85
+ minMatchCharLength: 3,
86
+ ignoreFieldNorm: true,
87
+ includeScore: true
88
+ });
89
+ matchedItems = mergeMultiTermFuseResults({
90
+ searchTerms: searchTerms,
91
+ limit: limit,
92
+ search: function search(query) {
93
+ return fuse.search(query, {
94
+ limit: limit * searchTerms.length
95
+ });
107
96
  }
108
- return fuse.search(term).slice(0, limit);
109
- }).flat();
110
- if (results.length) {
111
- _context.next = 13;
97
+ });
98
+ if (matchedItems.length) {
99
+ _context.next = 9;
112
100
  break;
113
101
  }
114
102
  return _context.abrupt("return", {
115
- isError: true,
116
103
  content: [{
117
104
  type: 'text',
118
105
  text: "Error: No components found for '".concat(terms.join(', '), "'. Available components: ").concat(components.map(function (c) {
@@ -120,28 +107,20 @@ export var searchComponentsTool = /*#__PURE__*/function () {
120
107
  }).join(', '))
121
108
  }]
122
109
  });
123
- case 13:
124
- // Remove duplicates based on component name
125
- uniqueResults = results.filter(function (result, index, arr) {
126
- return arr.findIndex(function (r) {
127
- return r.item.name === result.item.name;
128
- }) === index;
129
- });
110
+ case 9:
130
111
  return _context.abrupt("return", {
131
112
  content: [{
132
113
  type: 'text',
133
- text: JSON.stringify(uniqueResults.map(function (result) {
134
- return result.item;
135
- }).map(cleanComponentResult))
114
+ text: JSON.stringify(matchedItems.map(buildComponentResult))
136
115
  }]
137
116
  });
138
- case 15:
117
+ case 10:
139
118
  case "end":
140
119
  return _context.stop();
141
120
  }
142
121
  }, _callee);
143
122
  }));
144
123
  return function searchComponentsTool(_x) {
145
- return _ref.apply(this, arguments);
124
+ return _ref2.apply(this, arguments);
146
125
  };
147
126
  }();
@@ -1,19 +1,26 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
4
  /* eslint-disable-next-line import/extensions -- MCP SDK requires .js extensions for ESM imports */
4
5
 
5
6
  import Fuse from 'fuse.js';
6
7
  import { z } from 'zod';
7
- import { cleanQuery, zodToJsonSchema } from '../../helpers';
8
+ import { cleanQuery, mergeMultiTermFuseResults, zodToJsonSchema } from '../../helpers';
8
9
  import { icons } from '../get-all-icons/icons';
9
10
  export var searchIconsInputSchema = z.object({
10
- terms: z.array(z.string()).describe('An array of search terms to find icons by name, keywords, or categorization, eg. `["search", "folder", "user"]`'),
11
- limit: z.number().default(1).describe('Maximum number of results per search term in the array (default: 1)').optional(),
12
- exactName: z.boolean().default(false).describe('Enable to explicitly search icons by the exact name match (when you know the name, but need more details)').optional()
11
+ terms: z.array(z.string()).describe('Required: one or more terms; fuzzy match on icon **componentName**, **iconName**, **keywords**, **categorization**, **type**, and **usage**. Example: `["search", "folder", "user"]`.'),
12
+ limit: z.number().default(2).describe('Max matches **per term** (default 2).').optional()
13
13
  });
14
+ var buildIconResult = function buildIconResult(icon) {
15
+ return {
16
+ componentName: icon.componentName,
17
+ package: icon.package,
18
+ usage: icon.usage
19
+ };
20
+ };
14
21
  export var listSearchIconsTool = {
15
22
  name: 'ads_search_icons',
16
- description: "Search for Atlassian Design System icons.\n\nExample icon usage:\n```tsx\nimport AddIcon from '@atlaskit/icon/core/add';\n<AddIcon label=\"Add work item\" size=\"small\" />\n```",
23
+ description: "Searches the bundled Atlassian Design System **icon** catalog. Returns JSON with **componentName**, **package**, and **usage** for each match.\n\nWHEN TO USE:\n**Choosing an icon** for a control, nav item, empty state, or illustration\u2014find `@atlaskit/icon` import paths and usage notes. Prefer `ads_plan` when you also need tokens and components together.\n\nExample:\n```tsx\nimport AddIcon from '@atlaskit/icon/core/add';\n<AddIcon label=\"Add work item\" size=\"small\" />\n```",
17
24
  annotations: {
18
25
  title: 'Search ADS icons',
19
26
  readOnlyHint: true,
@@ -24,51 +31,28 @@ export var listSearchIconsTool = {
24
31
  inputSchema: zodToJsonSchema(searchIconsInputSchema)
25
32
  };
26
33
  export var searchIconsTool = /*#__PURE__*/function () {
27
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(params) {
28
- var terms, _params$limit, limit, _params$exactName, exactName, searchTerms, exactNameMatches, fuse, results, uniqueResults, matchedIcons;
34
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
35
+ var terms, _ref$limit, limit, searchTerms, fuse, matchedItems;
29
36
  return _regeneratorRuntime.wrap(function _callee$(_context) {
30
37
  while (1) switch (_context.prev = _context.next) {
31
38
  case 0:
32
- 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;
33
- searchTerms = terms.filter(Boolean).map(cleanQuery);
39
+ terms = _ref.terms, _ref$limit = _ref.limit, limit = _ref$limit === void 0 ? 2 : _ref$limit;
40
+ searchTerms = _toConsumableArray(new Set(terms.filter(Boolean).map(cleanQuery)));
34
41
  if (searchTerms.length) {
35
42
  _context.next = 4;
36
43
  break;
37
44
  }
38
45
  return _context.abrupt("return", {
39
- isError: true,
40
46
  content: [{
41
47
  type: 'text',
42
- text: "Error: Required parameter 'terms' is missing or empty"
48
+ text: '[]'
43
49
  }]
44
50
  });
45
51
  case 4:
46
- if (!exactName) {
47
- _context.next = 8;
48
- break;
49
- }
50
- // for each search term, search for the exact match
51
- exactNameMatches = searchTerms.map(function (term) {
52
- return icons.find(function (icon) {
53
- return icon.componentName.toLowerCase() === term.toLowerCase();
54
- });
55
- }).filter(Boolean);
56
- if (!(exactNameMatches.length > 0)) {
57
- _context.next = 8;
58
- break;
59
- }
60
- return _context.abrupt("return", {
61
- content: [{
62
- type: 'text',
63
- text: JSON.stringify(exactNameMatches)
64
- }]
65
- });
66
- case 8:
67
- // use Fuse.js to fuzzy-search through the icons
68
52
  fuse = new Fuse(icons, {
69
53
  keys: [{
70
54
  name: 'componentName',
71
- weight: 3
55
+ weight: 5
72
56
  }, {
73
57
  name: 'iconName',
74
58
  weight: 3
@@ -77,34 +61,37 @@ export var searchIconsTool = /*#__PURE__*/function () {
77
61
  weight: 2
78
62
  }, {
79
63
  name: 'categorization',
80
- weight: 1
64
+ weight: 2
81
65
  }, {
82
66
  name: 'type',
83
67
  weight: 1
84
68
  }, {
85
69
  name: 'usage',
86
- weight: 1
70
+ weight: 2
87
71
  }],
88
- threshold: 0.4
89
- }); // every search term, search for the results
90
- results = searchTerms.map(function (term) {
91
- // always search exact match from the icons
92
- var exactNameMatch = icons.find(function (icon) {
93
- return icon.componentName.toLowerCase() === term.toLowerCase();
94
- });
95
- if (exactNameMatch) {
96
- return [{
97
- item: exactNameMatch
98
- }];
72
+ threshold: 0.4,
73
+ distance: 80,
74
+ minMatchCharLength: 3,
75
+ ignoreFieldNorm: true,
76
+ includeScore: true
77
+ });
78
+ matchedItems = mergeMultiTermFuseResults({
79
+ searchTerms: searchTerms,
80
+ limit: limit,
81
+ search: function search(query) {
82
+ return fuse.search(query, {
83
+ limit: limit * searchTerms.length
84
+ });
85
+ },
86
+ tokenKey: function tokenKey(icon) {
87
+ return icon.componentName;
99
88
  }
100
- return fuse.search(term).slice(0, limit);
101
- }).flat();
102
- if (results.length) {
103
- _context.next = 12;
89
+ });
90
+ if (matchedItems.length) {
91
+ _context.next = 8;
104
92
  break;
105
93
  }
106
94
  return _context.abrupt("return", {
107
- isError: true,
108
95
  content: [{
109
96
  type: 'text',
110
97
  text: "Error: No icons found for '".concat(terms.join(', '), "'. Available icons: ").concat(icons.map(function (i) {
@@ -112,33 +99,20 @@ export var searchIconsTool = /*#__PURE__*/function () {
112
99
  }).join(', '))
113
100
  }]
114
101
  });
115
- case 12:
116
- // Remove duplicates based on componentName
117
- uniqueResults = results.filter(function (result, index, arr) {
118
- return arr.findIndex(function (r) {
119
- return r.item.componentName === result.item.componentName;
120
- }) === index;
121
- });
122
- matchedIcons = uniqueResults.map(function (result) {
123
- return {
124
- componentName: result.item.componentName,
125
- package: result.item.package,
126
- usage: result.item.usage
127
- };
128
- });
102
+ case 8:
129
103
  return _context.abrupt("return", {
130
104
  content: [{
131
105
  type: 'text',
132
- text: JSON.stringify(matchedIcons)
106
+ text: JSON.stringify(matchedItems.map(buildIconResult))
133
107
  }]
134
108
  });
135
- case 15:
109
+ case 9:
136
110
  case "end":
137
111
  return _context.stop();
138
112
  }
139
113
  }, _callee);
140
114
  }));
141
115
  return function searchIconsTool(_x) {
142
- return _ref.apply(this, arguments);
116
+ return _ref2.apply(this, arguments);
143
117
  };
144
118
  }();
@@ -1,3 +1,4 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
4
  /* eslint-disable-next-line import/extensions -- MCP SDK requires .js extensions for ESM imports */
@@ -5,15 +6,14 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
5
6
  import Fuse from 'fuse.js';
6
7
  import { z } from 'zod';
7
8
  import { tokens } from '@atlaskit/tokens/token-metadata';
8
- import { cleanQuery, zodToJsonSchema } from '../../helpers';
9
+ import { cleanQuery, mergeMultiTermFuseResults, zodToJsonSchema } from '../../helpers';
9
10
  export var searchTokensInputSchema = z.object({
10
- terms: z.array(z.string()).describe('An array of search terms to find tokens by name or description, eg. `["spacing", "inverted text", "background primary"]`'),
11
- limit: z.number().default(1).describe('Maximum number of results per search term in the array (default: 1)').optional(),
12
- exactName: z.boolean().default(false).describe('Enable to explicitly search tokens by the exact name match (when you know the name, but need more details)').optional()
11
+ terms: z.array(z.string()).describe('Required: one or more terms; fuzzy match on token **name**, **description**, **exampleValue**, **usageGuidelines.usage**, and **usageGuidelines.cssProperties**. Example: `["spacing", "color.text", "background"]`.'),
12
+ limit: z.number().default(2).describe('Max matches **per term** (default 2).').optional()
13
13
  });
14
14
  export var listSearchTokensTool = {
15
15
  name: 'ads_search_tokens',
16
- description: "Search for Atlassian Design System tokens.\n\nExample token usage:\n```tsx\nimport { token } from '@atlaskit/tokens';\nconst styles = css({ color: token('color.text'), padding: token('space.100') });\n```",
16
+ description: "Searches Atlassian Design System **design tokens** from bundled metadata. Returns JSON objects with **name** and **exampleValue** for each match (search also considers description, usage guidelines, and CSS property hints in metadata).\n\nWHEN TO USE:\n**Styling or theming in code**\u2014you need the right `token('\u2026')` names for colors, space, typography, etc. Use during layout and visual work when tokens must match ADS. Prefer `ads_plan` when you also need icons and components in the same step.\n\nExample:\n```tsx\nimport { token } from '@atlaskit/tokens';\nconst styles = css({ color: token('color.text'), padding: token('space.100') });\n```",
17
17
  annotations: {
18
18
  title: 'Search ADS tokens',
19
19
  readOnlyHint: true,
@@ -24,80 +24,93 @@ export var listSearchTokensTool = {
24
24
  inputSchema: zodToJsonSchema(searchTokensInputSchema)
25
25
  };
26
26
  export var searchTokensTool = /*#__PURE__*/function () {
27
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(params) {
28
- var terms, _params$limit, limit, _params$exactName, exactName, searchTerms, exactNameMatches, fuse, results, uniqueResults, matchedTokens;
27
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
28
+ var terms, _ref$limit, limit, searchTerms, fuse, matchedItems, matchedTokens;
29
29
  return _regeneratorRuntime.wrap(function _callee$(_context) {
30
30
  while (1) switch (_context.prev = _context.next) {
31
31
  case 0:
32
- 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;
33
- searchTerms = terms.filter(Boolean).map(cleanQuery);
34
- if (!exactName) {
35
- _context.next = 6;
36
- break;
37
- }
38
- // for each search term, search for the exact match
39
- exactNameMatches = searchTerms.map(function (term) {
40
- return tokens.find(function (token) {
41
- return token.name.toLowerCase() === term.toLowerCase();
42
- });
43
- }).filter(Boolean);
44
- if (!(exactNameMatches.length > 0)) {
45
- _context.next = 6;
32
+ terms = _ref.terms, _ref$limit = _ref.limit, limit = _ref$limit === void 0 ? 2 : _ref$limit;
33
+ // Unique cleaned terms (order preserved) so duplicates don't concatenate into a bogus query.
34
+ searchTerms = _toConsumableArray(new Set(terms.filter(Boolean).map(cleanQuery)));
35
+ if (searchTerms.length) {
36
+ _context.next = 4;
46
37
  break;
47
38
  }
48
39
  return _context.abrupt("return", {
49
40
  content: [{
50
41
  type: 'text',
51
- text: JSON.stringify(exactNameMatches.map(function (token) {
52
- return {
53
- name: token.name,
54
- exampleValue: token.exampleValue
55
- };
56
- }))
42
+ text: '[]'
57
43
  }]
58
44
  });
59
- case 6:
60
- // use Fuse.js to fuzzy-search for the tokens
45
+ case 4:
61
46
  fuse = new Fuse(tokens, {
62
47
  keys: [{
63
48
  name: 'name',
64
- weight: 3
49
+ weight: 5
50
+ }, {
51
+ name: 'path',
52
+ weight: 2
65
53
  }, {
66
54
  name: 'description',
67
55
  weight: 2
56
+ }, {
57
+ name: 'usageGuidelines.usage',
58
+ weight: 2
59
+ }, {
60
+ name: 'usageGuidelines.cssProperties',
61
+ weight: 3
68
62
  }, {
69
63
  name: 'exampleValue',
70
- weight: 1
64
+ weight: 0.5
71
65
  }],
72
- threshold: 0.4
66
+ threshold: 0.4,
67
+ distance: 80,
68
+ minMatchCharLength: 3,
69
+ ignoreFieldNorm: true,
70
+ includeScore: true
73
71
  });
74
- results = searchTerms.map(function (term) {
75
- return fuse.search(term).slice(0, limit);
76
- }).flat(); // Remove duplicates based on token name
77
- uniqueResults = results.filter(function (result, index, arr) {
78
- return arr.findIndex(function (r) {
79
- return r.item.name === result.item.name;
80
- }) === index;
72
+ matchedItems = mergeMultiTermFuseResults({
73
+ searchTerms: searchTerms,
74
+ limit: limit,
75
+ search: function search(query) {
76
+ return fuse.search(query, {
77
+ limit: limit * searchTerms.length
78
+ });
79
+ },
80
+ searchTermsJoin: '.'
81
81
  });
82
- matchedTokens = uniqueResults.map(function (result) {
82
+ matchedTokens = matchedItems.map(function (item) {
83
83
  return {
84
- name: result.item.name,
85
- exampleValue: result.item.exampleValue
84
+ name: item.name,
85
+ exampleValue: item.exampleValue
86
86
  };
87
87
  });
88
+ if (matchedTokens.length) {
89
+ _context.next = 9;
90
+ break;
91
+ }
92
+ return _context.abrupt("return", {
93
+ content: [{
94
+ type: 'text',
95
+ text: "Error: No tokens found for '".concat(terms.join(', '), "'. Available tokens: ").concat(tokens.map(function (t) {
96
+ return t.name;
97
+ }).join(', '))
98
+ }]
99
+ });
100
+ case 9:
88
101
  return _context.abrupt("return", {
89
102
  content: [{
90
103
  type: 'text',
91
104
  text: JSON.stringify(matchedTokens)
92
105
  }]
93
106
  });
94
- case 11:
107
+ case 10:
95
108
  case "end":
96
109
  return _context.stop();
97
110
  }
98
111
  }, _callee);
99
112
  }));
100
113
  return function searchTokensTool(_x) {
101
- return _ref.apply(this, arguments);
114
+ return _ref2.apply(this, arguments);
102
115
  };
103
116
  }();
@@ -14,16 +14,16 @@ import { zodToJsonSchema } from '../../helpers';
14
14
  import { accessibilityFixes } from './fixes';
15
15
  import { violationKeywords } from './keywords';
16
16
  export var suggestA11yFixesInputSchema = z.object({
17
- violation: z.string().describe('Description of the accessibility violation'),
18
- code: z.string().describe('The problematic code that needs fixing'),
19
- component: z.string().optional().describe('Component name or type'),
20
- context: z.string().optional().describe('Additional context about the usage')
17
+ violation: z.string().describe('Human-readable description of the issue (e.g. axe rule help text, "button has no accessible name", "missing alt"). Used to match curated recipes when possible; otherwise the tool falls back to generic guidance.'),
18
+ code: z.string().describe('Snippet of the problematic code or markup so the response can be tailored (may be shown in the output for traceability).'),
19
+ component: z.string().optional().describe('Optional: React component name involved (e.g. `Button`, `TextField`)—may be ADS or app-specific.'),
20
+ context: z.string().optional().describe('Optional: where this appears (e.g. modal, table row, page section) or constraints.')
21
21
  });
22
22
  export var listSuggestA11yFixesTool = {
23
23
  name: 'ads_suggest_a11y_fixes',
24
- description: "Suggests specific accessibility fixes using Atlassian Design System components and patterns.",
24
+ description: "Suggests remediation steps for an accessibility issue described in natural language (often pasted from **axe-core**, ESLint, or review).\n\nWHAT YOU GET (varies by match):\n- **Curated hit:** ADS-biased examples and patterns from this server\u2019s recipe map (components, tokens, common fixes).\n- **No strong match:** Generic guidance (e.g. \u201Cuse ADS components\u201D, labeling, testing)\u2014still useful, but **not** guaranteed to be ADS-specific. May reference axe/atlassian.design resources.\n\nWHEN TO USE:\nAfter `ads_analyze_a11y` or `ads_analyze_localhost_a11y`, or whenever you have a violation string. For **topic-level** Atlassian Design System accessibility guidance, call `ads_get_a11y_guidelines` (this tool is fix-oriented, not a full guideline browse).\n\nDoes not replace manual testing with assistive technologies or keyboard-only navigation.",
25
25
  annotations: {
26
- title: 'Suggest Accessibility Fixes',
26
+ title: 'Suggest accessibility fixes',
27
27
  readOnlyHint: true,
28
28
  destructiveHint: false,
29
29
  idempotentHint: true,
@@ -164,7 +164,7 @@ export var suggestA11yFixesTool = /*#__PURE__*/function () {
164
164
  availableFixTypes: Object.keys(accessibilityFixes),
165
165
  suggestions: ['Try describing the issue with keywords like: button, label, missing, text, color, contrast, focus, etc.', 'Use axe-core violation IDs or descriptions directly', 'Be more specific about the element type (button, input, image, etc.)'],
166
166
  additionalResources: ['https://atlassian.design/llms-a11y.txt - Complete ADS accessibility documentation', 'https://atlassian.design/foundations/accessibility - ADS accessibility foundation'],
167
- recommendation: 'Try the get_a11y_guidelines tool for component-specific guidance'
167
+ recommendation: 'Try the ads_get_a11y_guidelines tool for component-specific guidance'
168
168
  }, null, 2)
169
169
  }]
170
170
  });
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Allocation for multi-query Fuse search: each term alone, plus one spaced combined query.
3
+ *
4
+ * `poolMax = limit * termCount`. From each term we take up to `perTermTake` hits; the rest of the
5
+ * pool is filled from the spaced combined query.
6
+ */
7
+ export declare function computeMultiTermFuseAllocation(limit: number, termCount: number): {
8
+ /**
9
+ * The amount token by each term, minimum of 1.
10
+ */
11
+ perTermTake: number;
12
+ /**
13
+ * Hits to take from the spaced combined query.
14
+ */
15
+ combinedTake: number;
16
+ /**
17
+ * The total amount of hits to take, minimum of 1.
18
+ */
19
+ totalTake: number;
20
+ };
21
+ export type FuseHit<T> = {
22
+ item: T;
23
+ /**
24
+ * Fuse score when `includeScore` is enabled; lower is a better match.
25
+ */
26
+ score?: number;
27
+ };
28
+ /**
29
+ * Runs `search` for each term (top `perTermTake`) and for `terms.join(' ')` (top `combinedTake`),
30
+ * merges pools, sorts globally by Fuse score, then returns the first `limit` **distinct** keys
31
+ * (later duplicate keys are skipped).
32
+ *
33
+ * Default `tokenKey` uses `item.name` when present; pass an explicit `tokenKey` for types without
34
+ * `name` (e.g. icons keyed by `componentName`).
35
+ */
36
+ export declare function mergeMultiTermFuseResults<T>({ searchTerms, limit, search, tokenKey, searchTermsJoin, }: {
37
+ searchTerms: string[];
38
+ limit: number;
39
+ search: (query: string) => FuseHit<T>[];
40
+ tokenKey?: (item: T) => string;
41
+ /**
42
+ * Join the search terms when querying with this separator, eg. `color.text` vs. `color text`
43
+ */
44
+ searchTermsJoin?: ' ' | '.';
45
+ }): T[];
@@ -1,4 +1,5 @@
1
1
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { zodToJsonSchema as zodToJsonSchemaHelper } from 'zod-to-json-schema';
3
+ export { computeMultiTermFuseAllocation, type FuseHit, mergeMultiTermFuseResults, } from './fuse-multi-term';
3
4
  export declare const cleanQuery: (query: string) => string;
4
5
  export declare const zodToJsonSchema: <T = Tool["inputSchema"]>(schema: Parameters<typeof zodToJsonSchemaHelper>[0], options?: Parameters<typeof zodToJsonSchemaHelper>[1]) => T;
@@ -1 +1 @@
1
- export declare const instructions = "\nYou are an expert in the Atlassian Design System (ADS).\nYou can search for tokens, icons, and components and return guidance on how to build user interfaces.\nYou have special accessibility knowledge and can ensure interfaces built with ADS components are accessible to all users.\nYou can analyze code for accessibility violations, provide specific fix suggestions, and offer guidance on accessibility best practices.\nThese tools will support you, but for deep research, you may also want to to fetch https://atlassian.design/llms.txt, https://atlassian.design/llms-a11y.txt, or https://atlassian.design/ directly.\n";
1
+ export declare const instructions = "\nYou are an expert in the Atlassian Design System (ADS).\nYou can search for tokens, icons, and components and return guidance on how to build user interfaces.\nYou have special accessibility knowledge and can ensure interfaces built with ADS components are accessible to all users.\nYou can analyze code for accessibility violations, provide specific fix suggestions, and offer guidance on accessibility best practices.\nFor org-wide standards alongside ADS tools: pair Context Engine `get_accessibility_docs` with `ads_get_a11y_guidelines`, `get_content_standards_docs` with `ads_get_guidelines`, and `get_i18n_docs` with `ads_i18n_conversion_guide` (Traduki/i18n policy plus the bundled formatMessage refactor guide).\nThese tools will support you, but for deep research you may also fetch https://atlassian.design/llms.txt, https://atlassian.design/llms-a11y.txt, or https://atlassian.design/ directly.\n";
@@ -1,6 +1,6 @@
1
1
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- export declare const listGetComponentsTool: Tool;
3
- export declare const getComponentsTool: () => Promise<{
2
+ export declare const listGetAllComponentsTool: Tool;
3
+ export declare const getAllComponentsTool: () => Promise<{
4
4
  content: {
5
5
  type: string;
6
6
  text: string;