@atlaskit/ads-mcp 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +63 -2
- package/dist/cjs/helpers/analytics.js +98 -0
- package/dist/cjs/index.js +142 -28
- package/dist/cjs/tools/analyze-a11y/index.js +38 -38
- package/dist/cjs/tools/get-a11y-guidelines/index.js +4 -4
- package/dist/cjs/tools/get-all-icons/index.js +1 -1
- package/dist/cjs/tools/get-all-tokens/index.js +1 -1
- package/dist/cjs/tools/get-components/components.js +2 -2
- package/dist/cjs/tools/get-components/index.js +1 -1
- package/dist/cjs/tools/plan/index.js +6 -6
- package/dist/cjs/tools/search-components/index.js +9 -9
- package/dist/cjs/tools/search-icons/index.js +9 -9
- package/dist/cjs/tools/search-tokens/index.js +5 -5
- package/dist/cjs/tools/suggest-a11y-fixes/index.js +4 -4
- package/dist/es2019/helpers/analytics.js +88 -0
- package/dist/es2019/index.js +118 -15
- package/dist/es2019/tools/get-components/components.js +2 -2
- package/dist/esm/helpers/analytics.js +90 -0
- package/dist/esm/index.js +143 -29
- package/dist/esm/tools/analyze-a11y/index.js +38 -38
- package/dist/esm/tools/get-a11y-guidelines/index.js +4 -4
- package/dist/esm/tools/get-all-icons/index.js +1 -1
- package/dist/esm/tools/get-all-tokens/index.js +1 -1
- package/dist/esm/tools/get-components/components.js +2 -2
- package/dist/esm/tools/get-components/index.js +1 -1
- package/dist/esm/tools/plan/index.js +6 -6
- package/dist/esm/tools/search-components/index.js +9 -9
- package/dist/esm/tools/search-icons/index.js +9 -9
- package/dist/esm/tools/search-tokens/index.js +5 -5
- package/dist/esm/tools/suggest-a11y-fixes/index.js +4 -4
- package/dist/types/helpers/analytics.d.ts +28 -0
- package/dist/types/tools/get-components/components.d.ts +1 -1
- package/dist/types-ts4.5/helpers/analytics.d.ts +28 -0
- package/dist/types-ts4.5/tools/get-components/components.d.ts +1 -1
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @atlaskit/ads-mcp
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`307bb9ca6972b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/307bb9ca6972b) -
|
|
8
|
+
Add analytics tracking for tool requests and errors
|
|
9
|
+
|
|
10
|
+
## 0.7.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [`1e36a2d0fe31e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1e36a2d0fe31e) -
|
|
15
|
+
Tiny update to form component types
|
|
16
|
+
|
|
3
17
|
## 0.7.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -111,12 +111,70 @@ Add an entry to your `mcp.json` (eg. `~/.cursor/mcp.json` or wherever your MCP c
|
|
|
111
111
|
"mcpServers": {
|
|
112
112
|
"ads": {
|
|
113
113
|
"command": "npx",
|
|
114
|
-
"args": ["-y", "@atlaskit/ads-mcp"]
|
|
114
|
+
"args": ["-y", "@atlaskit/ads-mcp"],
|
|
115
|
+
"env": {
|
|
116
|
+
"ADSMCP_AGENT": "cursor"
|
|
117
|
+
}
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
```
|
|
119
122
|
|
|
123
|
+
### Environment Variables
|
|
124
|
+
|
|
125
|
+
- `ADSMCP_AGENT` - Identifies the AI agent/platform using the MCP server. Supported values:
|
|
126
|
+
- `cursor` - Cursor editor
|
|
127
|
+
- `vscode` - Visual Studio Code
|
|
128
|
+
- `rovodev` - Rovo Development environment
|
|
129
|
+
- `codelassian` - Codelassian platform
|
|
130
|
+
- `unknown` - Default value when not specified
|
|
131
|
+
|
|
132
|
+
The `ADSMCP_AGENT` variable helps track which platforms are using the MCP server for analytics purposes.
|
|
133
|
+
|
|
134
|
+
- `ADSMCP_ANALYTICS_OPT_OUT` - Opt out of analytics collection. Set to `true` to disable:
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"ads": {
|
|
139
|
+
"command": "npx",
|
|
140
|
+
"args": ["-y", "@atlaskit/ads-mcp"],
|
|
141
|
+
"env": {
|
|
142
|
+
"ADSMCP_AGENT": "cursor",
|
|
143
|
+
"ADSMCP_ANALYTICS_OPT_OUT": true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Analytics
|
|
151
|
+
|
|
152
|
+
The MCP server includes built-in analytics to help improve the service. Analytics are sent to
|
|
153
|
+
Atlassian's internal analytics system and track:
|
|
154
|
+
|
|
155
|
+
### What We Track
|
|
156
|
+
|
|
157
|
+
- **Tool Usage**: Which tools are being called (e.g., `ads_plan`, `ads_analyze_a11y`)
|
|
158
|
+
- **Tool Parameters**: Arguments passed to tools (search terms, component names, etc.)
|
|
159
|
+
- **Success/Failure**: Whether tool calls succeed or fail, including error messages
|
|
160
|
+
- **Environment Context**:
|
|
161
|
+
- `agent`: The platform using the MCP server (from `ADSMCP_AGENT` env var)
|
|
162
|
+
- `os`: Operating system name (darwin, win32, linux)
|
|
163
|
+
- `osVersion`: Operating system version (e.g., 24.6.0 for macOS)
|
|
164
|
+
- `version`: The version of `@atlaskit/ads-mcp` being used
|
|
165
|
+
- `staffId`: User identifier (from `STAFF_ID`, `USER`, `ATLAS_USER`, or username)
|
|
166
|
+
- `timestamp`: When the event occurred
|
|
167
|
+
|
|
168
|
+
### Privacy & Error Handling
|
|
169
|
+
|
|
170
|
+
- Analytics are collected for internal Atlassian use only to improve the MCP server
|
|
171
|
+
- **You can opt out** by setting `ADSMCP_ANALYTICS_OPT_OUT=true` in your environment variables
|
|
172
|
+
- If the analytics client fails to initialize or send events, the MCP server continues to work
|
|
173
|
+
normally
|
|
174
|
+
- All analytics errors are caught and logged, ensuring they never interrupt your workflow
|
|
175
|
+
- Events are batched and flushed every 5 seconds for efficiency
|
|
176
|
+
|
|
177
|
+
|
|
120
178
|
## Development
|
|
121
179
|
|
|
122
180
|
You may automatically be served the local version of `@atlaskit/ads-mcp` depending on where you're
|
|
@@ -130,7 +188,10 @@ running it from, but you should force it like so:
|
|
|
130
188
|
"args": [
|
|
131
189
|
"-y",
|
|
132
190
|
"~/git/atlassian/atlassian-frontend-monorepo/platform/packages/design-system/ads-mcp"
|
|
133
|
-
]
|
|
191
|
+
],
|
|
192
|
+
"env": {
|
|
193
|
+
"ADSMCP_AGENT": "cursor"
|
|
194
|
+
}
|
|
134
195
|
}
|
|
135
196
|
}
|
|
136
197
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.configPath = exports.agent = void 0;
|
|
8
|
+
exports.sendOperationalEvent = sendOperationalEvent;
|
|
9
|
+
exports.staffId = void 0;
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _nodeOs = require("node:os");
|
|
12
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
13
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable no-console */
|
|
14
|
+
// 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
|
|
15
|
+
var pkgJson = require('@atlaskit/ads-mcp/package.json');
|
|
16
|
+
var version = pkgJson.version || '0.0.0-unknown';
|
|
17
|
+
|
|
18
|
+
// Get staff ID using the same logic as @repo-feature-flags-statsig
|
|
19
|
+
var staffId = exports.staffId = process.env.STAFF_ID || process.env.USER || process.env.ATLAS_USER || (0, _nodeOs.userInfo)().username;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* This is a user-passed value via environment to define what agent we may be running in.
|
|
23
|
+
* This could be anything, do not rely on it!
|
|
24
|
+
* @default `'unknown'`
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
var agent = exports.agent = process.env.ADSMCP_AGENT || 'unknown';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The path to the MCP config file that is being used to run the MCP server
|
|
31
|
+
* e.g. 'mcp.json', 'jira/.cursor/mcp.json', 'platform/.vscode/mcp.json' or 'unknown'
|
|
32
|
+
* This could be anything, do not rely on it!
|
|
33
|
+
* @default `'unknown'`
|
|
34
|
+
*/
|
|
35
|
+
var configPath = exports.configPath = process.env.ADSMCP_CONFIG_PATH || 'unknown';
|
|
36
|
+
|
|
37
|
+
// Check if user has opted out of analytics
|
|
38
|
+
var isAnalyticsOptedOut = String(process.env.ADSMCP_ANALYTICS_OPT_OUT) === 'true' || String(process.env.ADSMCP_ANALYTICS_OPT_OUT) === '1';
|
|
39
|
+
|
|
40
|
+
// Initialize analytics client with error handling
|
|
41
|
+
// If analytics client fails to initialize or user has opted out, we continue without analytics
|
|
42
|
+
var analyticsClient = null;
|
|
43
|
+
if (!isAnalyticsOptedOut) {
|
|
44
|
+
try {
|
|
45
|
+
// Dynamic import to catch initialization errors
|
|
46
|
+
var _require = require('@atlassiansox/analytics-node-client'),
|
|
47
|
+
createAnalyticsClient = _require.analyticsClient;
|
|
48
|
+
analyticsClient = createAnalyticsClient({
|
|
49
|
+
env: process.env.NODE_ENV === 'development' ? 'dev' : 'prod',
|
|
50
|
+
product: 'atlaskit',
|
|
51
|
+
subproduct: 'ads-mcp',
|
|
52
|
+
flushInterval: 5000
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Analytics client not available or failed to initialize
|
|
56
|
+
// Log the error but continue without analytics
|
|
57
|
+
console.error('Could not initialize analytics client. This is normal as it is only intended to measure authenticated Atlassians');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Send an operational event to analytics
|
|
62
|
+
* Wraps the analytics client and handles errors gracefully
|
|
63
|
+
* If analytics client is not available, this function is a no-op
|
|
64
|
+
*/
|
|
65
|
+
function sendOperationalEvent(_ref) {
|
|
66
|
+
var action = _ref.action,
|
|
67
|
+
actionSubject = _ref.actionSubject,
|
|
68
|
+
_ref$actionSubjectId = _ref.actionSubjectId,
|
|
69
|
+
actionSubjectId = _ref$actionSubjectId === void 0 ? '' : _ref$actionSubjectId,
|
|
70
|
+
_ref$attributes = _ref.attributes,
|
|
71
|
+
attributes = _ref$attributes === void 0 ? {} : _ref$attributes;
|
|
72
|
+
// If analytics client is not available, skip analytics
|
|
73
|
+
if (!analyticsClient) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
analyticsClient.sendOperationalEvent({
|
|
78
|
+
anonymousId: 'unknown',
|
|
79
|
+
operationalEvent: {
|
|
80
|
+
action: action,
|
|
81
|
+
actionSubject: actionSubject,
|
|
82
|
+
actionSubjectId: actionSubjectId,
|
|
83
|
+
source: '@atlaskit/ads-mcp',
|
|
84
|
+
tags: ['ads-mcp'],
|
|
85
|
+
attributes: _objectSpread({
|
|
86
|
+
version: version,
|
|
87
|
+
staffId: staffId,
|
|
88
|
+
agent: agent,
|
|
89
|
+
configPath: configPath
|
|
90
|
+
}, attributes)
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// Analytics errors should not prevent normal operation
|
|
95
|
+
// Silently fail to avoid disrupting the main functionality
|
|
96
|
+
console.error('Error sending operational event to analytics');
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
|
|
|
6
6
|
var _index = require("@modelcontextprotocol/sdk/server/index.js");
|
|
7
7
|
var _stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8
8
|
var _types = require("@modelcontextprotocol/sdk/types.js");
|
|
9
|
+
var _analytics = require("./helpers/analytics");
|
|
9
10
|
var _instructions = require("./instructions");
|
|
10
11
|
var _analyzeA11y = require("./tools/analyze-a11y");
|
|
11
12
|
var _getA11yGuidelines = require("./tools/get-a11y-guidelines");
|
|
@@ -17,7 +18,7 @@ var _searchComponents = require("./tools/search-components");
|
|
|
17
18
|
var _searchIcons = require("./tools/search-icons");
|
|
18
19
|
var _searchTokens = require("./tools/search-tokens");
|
|
19
20
|
var _suggestA11yFixes = require("./tools/suggest-a11y-fixes");
|
|
20
|
-
/* eslint-disable import/extensions */
|
|
21
|
+
/* eslint-disable no-console, import/extensions */
|
|
21
22
|
|
|
22
23
|
// 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
|
|
23
24
|
var pkgJson = require('@atlaskit/ads-mcp/package.json');
|
|
@@ -27,29 +28,68 @@ var server = new _index.Server({
|
|
|
27
28
|
}, {
|
|
28
29
|
instructions: _instructions.instructions,
|
|
29
30
|
capabilities: {
|
|
31
|
+
// logging: {}, // NOTE: We do not have logging enabled as it's not implemented consistently in MCP specs
|
|
30
32
|
// Tools are defined in the handlers below.
|
|
31
33
|
tools: {}
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
|
-
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
var generateLogger = function generateLogger(level) {
|
|
37
|
+
return function () {
|
|
38
|
+
// NOTE: We do not have logging enabled as it's not implemented consistently in MCP specs
|
|
39
|
+
// server.sendLoggingMessage({
|
|
40
|
+
// level,
|
|
41
|
+
// data: args,
|
|
42
|
+
// });
|
|
43
|
+
|
|
44
|
+
// Log to console if ADSMCP_DEBUG is set to true
|
|
45
|
+
// using console.error since the only one that works for logging is `stderr`
|
|
46
|
+
// using console.log / other console.fn that use `stdout` will cause an error
|
|
47
|
+
// ref: https://www.mcpevals.io/blog/debugging-mcp-servers-tips-and-best-practices
|
|
48
|
+
if (String(process.env.ADSMCP_DEBUG) === 'true') {
|
|
49
|
+
var _console;
|
|
50
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
51
|
+
args[_key] = arguments[_key];
|
|
52
|
+
}
|
|
53
|
+
(_console = console).error.apply(_console, ["[ads-mcp.custom-logging][".concat(level, "]")].concat(args));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
server.setRequestHandler(_types.ListToolsRequestSchema, /*#__PURE__*/function () {
|
|
58
|
+
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(request, extra) {
|
|
59
|
+
var tools;
|
|
60
|
+
return _regenerator.default.wrap(function (_context) {
|
|
61
|
+
while (1) switch (_context.prev = _context.next) {
|
|
62
|
+
case 0:
|
|
63
|
+
tools = [_analyzeA11y.listAnalyzeA11yTool, _analyzeA11y.listAnalyzeLocalhostA11yTool, _getA11yGuidelines.listGetA11yGuidelinesTool, _getAllIcons.listGetAllIconsTool, _getAllTokens.listGetAllTokensTool, _getComponents.listGetComponentsTool, _plan.listPlanTool,
|
|
40
64
|
// NOTE: These are disabled as `ads_plan` should cover everything more performantly.
|
|
41
65
|
// When these are enabled, they result in token usage to describe them, even if never used.
|
|
42
66
|
// listSearchComponentsTool,
|
|
43
67
|
// listSearchIconsTool,
|
|
44
68
|
// listSearchTokensTool,
|
|
45
|
-
_suggestA11yFixes.listSuggestA11yFixesTool]
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
69
|
+
_suggestA11yFixes.listSuggestA11yFixesTool]; // Track list tools request
|
|
70
|
+
(0, _analytics.sendOperationalEvent)({
|
|
71
|
+
action: 'listed',
|
|
72
|
+
actionSubject: 'ads.mcp.listTools',
|
|
73
|
+
attributes: {
|
|
74
|
+
toolsCount: tools.length,
|
|
75
|
+
// Number of available tools
|
|
76
|
+
request: request,
|
|
77
|
+
extra: extra
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return _context.abrupt("return", {
|
|
81
|
+
tools: tools
|
|
82
|
+
});
|
|
83
|
+
case 1:
|
|
84
|
+
case "end":
|
|
85
|
+
return _context.stop();
|
|
86
|
+
}
|
|
87
|
+
}, _callee);
|
|
88
|
+
}));
|
|
89
|
+
return function (_x, _x2) {
|
|
90
|
+
return _ref.apply(this, arguments);
|
|
91
|
+
};
|
|
92
|
+
}());
|
|
53
93
|
var callTools = {
|
|
54
94
|
ads_analyze_a11y: _analyzeA11y.analyzeA11yTool,
|
|
55
95
|
ads_analyze_localhost_a11y: _analyzeA11y.analyzeLocalhostA11yTool,
|
|
@@ -68,26 +108,87 @@ var callTools = {
|
|
|
68
108
|
|
|
69
109
|
// Handle tool execution
|
|
70
110
|
server.setRequestHandler(_types.CallToolRequestSchema, /*#__PURE__*/function () {
|
|
71
|
-
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(request) {
|
|
72
|
-
var tool;
|
|
73
|
-
return _regenerator.default.wrap(function
|
|
111
|
+
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(request, extra) {
|
|
112
|
+
var toolName, tool, actionSubject, result, _t;
|
|
113
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
74
114
|
while (1) switch (_context2.prev = _context2.next) {
|
|
75
115
|
case 0:
|
|
76
|
-
|
|
116
|
+
toolName = request.params.name;
|
|
117
|
+
tool = callTools[toolName];
|
|
118
|
+
actionSubject = "ads.mcp.callTool"; // Track call tool request
|
|
119
|
+
(0, _analytics.sendOperationalEvent)({
|
|
120
|
+
action: 'called',
|
|
121
|
+
actionSubject: actionSubject,
|
|
122
|
+
actionSubjectId: toolName,
|
|
123
|
+
attributes: {
|
|
124
|
+
toolName: toolName,
|
|
125
|
+
request: request,
|
|
126
|
+
extra: extra
|
|
127
|
+
}
|
|
128
|
+
});
|
|
77
129
|
if (!tool) {
|
|
78
|
-
_context2.next =
|
|
130
|
+
_context2.next = 4;
|
|
79
131
|
break;
|
|
80
132
|
}
|
|
81
|
-
|
|
133
|
+
_context2.prev = 1;
|
|
134
|
+
_context2.next = 2;
|
|
135
|
+
return tool(request.params.arguments);
|
|
136
|
+
case 2:
|
|
137
|
+
result = _context2.sent;
|
|
138
|
+
// Track successful tool execution
|
|
139
|
+
(0, _analytics.sendOperationalEvent)({
|
|
140
|
+
action: 'succeeded',
|
|
141
|
+
actionSubject: actionSubject,
|
|
142
|
+
actionSubjectId: toolName,
|
|
143
|
+
attributes: {
|
|
144
|
+
toolName: toolName,
|
|
145
|
+
request: request,
|
|
146
|
+
extra: extra
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return _context2.abrupt("return", result);
|
|
82
150
|
case 3:
|
|
83
|
-
|
|
151
|
+
_context2.prev = 3;
|
|
152
|
+
_t = _context2["catch"](1);
|
|
153
|
+
// Track tool execution error
|
|
154
|
+
(0, _analytics.sendOperationalEvent)({
|
|
155
|
+
action: 'failed',
|
|
156
|
+
actionSubject: actionSubject,
|
|
157
|
+
actionSubjectId: toolName,
|
|
158
|
+
attributes: {
|
|
159
|
+
toolName: toolName,
|
|
160
|
+
request: request,
|
|
161
|
+
extra: extra,
|
|
162
|
+
errorMessage: _t instanceof Error ? _t.message : 'Unknown error'
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
/* Throwing an MCP error will cause the MCP server to return an error response to the client.
|
|
167
|
+
We don't use console.error here:
|
|
168
|
+
- when used alone, without the throw new McpError, it causes "Client error for command...", which will loop back to this catch
|
|
169
|
+
*/
|
|
170
|
+
throw new _types.McpError(-32000, "Failed to execute '".concat(toolName, "' tool: ").concat(_t instanceof Error ? _t.message : 'Unknown error'));
|
|
84
171
|
case 4:
|
|
172
|
+
// Track tool not found error
|
|
173
|
+
(0, _analytics.sendOperationalEvent)({
|
|
174
|
+
action: 'notFound',
|
|
175
|
+
actionSubject: actionSubject,
|
|
176
|
+
actionSubjectId: toolName,
|
|
177
|
+
attributes: {
|
|
178
|
+
toolName: toolName,
|
|
179
|
+
request: request,
|
|
180
|
+
extra: extra
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
console.error("Tool '".concat(request.params.name, "' not found, only the following tools are available: ").concat(Object.keys(callTools).join(', ')));
|
|
184
|
+
return _context2.abrupt("return");
|
|
185
|
+
case 5:
|
|
85
186
|
case "end":
|
|
86
187
|
return _context2.stop();
|
|
87
188
|
}
|
|
88
|
-
}, _callee2);
|
|
189
|
+
}, _callee2, null, [[1, 3]]);
|
|
89
190
|
}));
|
|
90
|
-
return function (
|
|
191
|
+
return function (_x3, _x4) {
|
|
91
192
|
return _ref2.apply(this, arguments);
|
|
92
193
|
};
|
|
93
194
|
}());
|
|
@@ -97,13 +198,25 @@ function runServer() {
|
|
|
97
198
|
function _runServer() {
|
|
98
199
|
_runServer = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
99
200
|
var transport;
|
|
100
|
-
return _regenerator.default.wrap(function
|
|
201
|
+
return _regenerator.default.wrap(function (_context3) {
|
|
101
202
|
while (1) switch (_context3.prev = _context3.next) {
|
|
102
203
|
case 0:
|
|
204
|
+
/**
|
|
205
|
+
* We force all logging to go through the MCP server to avoid breaking the MCP.
|
|
206
|
+
*/
|
|
207
|
+
console.log = generateLogger('info');
|
|
208
|
+
console.debug = generateLogger('debug');
|
|
209
|
+
console.warn = generateLogger('warning');
|
|
210
|
+
|
|
211
|
+
// Track server initialization
|
|
212
|
+
(0, _analytics.sendOperationalEvent)({
|
|
213
|
+
action: 'initialized',
|
|
214
|
+
actionSubject: 'ads.mcp.initialize'
|
|
215
|
+
});
|
|
103
216
|
transport = new _stdio.StdioServerTransport();
|
|
104
|
-
_context3.next =
|
|
217
|
+
_context3.next = 1;
|
|
105
218
|
return server.connect(transport);
|
|
106
|
-
case
|
|
219
|
+
case 1:
|
|
107
220
|
case "end":
|
|
108
221
|
return _context3.stop();
|
|
109
222
|
}
|
|
@@ -112,5 +225,6 @@ function _runServer() {
|
|
|
112
225
|
return _runServer.apply(this, arguments);
|
|
113
226
|
}
|
|
114
227
|
runServer().catch(function (error) {
|
|
115
|
-
|
|
228
|
+
var errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
229
|
+
console.error("Invalid input to ads-mcp: ".concat(errorMessage));
|
|
116
230
|
});
|
|
@@ -152,20 +152,20 @@ function generateADSFixForViolation(violation) {
|
|
|
152
152
|
}
|
|
153
153
|
var analyzeA11yTool = exports.analyzeA11yTool = /*#__PURE__*/function () {
|
|
154
154
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(params) {
|
|
155
|
-
var code, componentName, context, _params$includePatter, includePatternAnalysis, violations, suggestions, axeResults, _axeResults$violation, _axeResults$passes, _axeResults$incomplet, results, adsViolations, relevantGuidelines, summary;
|
|
156
|
-
return _regenerator.default.wrap(function
|
|
155
|
+
var code, componentName, context, _params$includePatter, includePatternAnalysis, violations, suggestions, axeResults, _axeResults$violation, _axeResults$passes, _axeResults$incomplet, results, adsViolations, relevantGuidelines, summary, _t;
|
|
156
|
+
return _regenerator.default.wrap(function (_context) {
|
|
157
157
|
while (1) switch (_context.prev = _context.next) {
|
|
158
158
|
case 0:
|
|
159
159
|
code = params.code, componentName = params.componentName, context = params.context, _params$includePatter = params.includePatternAnalysis, includePatternAnalysis = _params$includePatter === void 0 ? true : _params$includePatter;
|
|
160
160
|
violations = [];
|
|
161
161
|
suggestions = [];
|
|
162
162
|
axeResults = {};
|
|
163
|
-
_context.prev =
|
|
164
|
-
_context.next =
|
|
163
|
+
_context.prev = 1;
|
|
164
|
+
_context.next = 2;
|
|
165
165
|
return _axeCore.default.run({
|
|
166
166
|
fromFrames: ['iframe', 'html']
|
|
167
167
|
});
|
|
168
|
-
case
|
|
168
|
+
case 2:
|
|
169
169
|
results = _context.sent;
|
|
170
170
|
// Process axe-core results
|
|
171
171
|
if (results.violations && results.violations.length > 0) {
|
|
@@ -251,9 +251,9 @@ var analyzeA11yTool = exports.analyzeA11yTool = /*#__PURE__*/function () {
|
|
|
251
251
|
}, null, 2)
|
|
252
252
|
}]
|
|
253
253
|
});
|
|
254
|
-
case
|
|
255
|
-
_context.prev =
|
|
256
|
-
|
|
254
|
+
case 3:
|
|
255
|
+
_context.prev = 3;
|
|
256
|
+
_t = _context["catch"](1);
|
|
257
257
|
// Fallback to pattern-based analysis if axe-core fails
|
|
258
258
|
// console.warn('Axe-core analysis failed, falling back to pattern analysis:', error);
|
|
259
259
|
|
|
@@ -302,11 +302,11 @@ var analyzeA11yTool = exports.analyzeA11yTool = /*#__PURE__*/function () {
|
|
|
302
302
|
}, null, 2)
|
|
303
303
|
}]
|
|
304
304
|
});
|
|
305
|
-
case
|
|
305
|
+
case 4:
|
|
306
306
|
case "end":
|
|
307
307
|
return _context.stop();
|
|
308
308
|
}
|
|
309
|
-
}, _callee, null, [[
|
|
309
|
+
}, _callee, null, [[1, 3]]);
|
|
310
310
|
}));
|
|
311
311
|
return function analyzeA11yTool(_x) {
|
|
312
312
|
return _ref.apply(this, arguments);
|
|
@@ -314,59 +314,59 @@ var analyzeA11yTool = exports.analyzeA11yTool = /*#__PURE__*/function () {
|
|
|
314
314
|
}();
|
|
315
315
|
var analyzeLocalhostA11yTool = exports.analyzeLocalhostA11yTool = /*#__PURE__*/function () {
|
|
316
316
|
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(params) {
|
|
317
|
-
var url, componentName, context, selector, violations, suggestions, axeResults, browser, page, _axeResults$violation2, _axeResults$passes2, _axeResults$incomplet2, elementExists, availableElements, axePuppeteer, results, adsViolations, relevantGuidelines, summary;
|
|
318
|
-
return _regenerator.default.wrap(function
|
|
317
|
+
var url, componentName, context, selector, violations, suggestions, axeResults, browser, page, _axeResults$violation2, _axeResults$passes2, _axeResults$incomplet2, elementExists, availableElements, axePuppeteer, results, adsViolations, relevantGuidelines, summary, _t2;
|
|
318
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
319
319
|
while (1) switch (_context2.prev = _context2.next) {
|
|
320
320
|
case 0:
|
|
321
321
|
url = params.url, componentName = params.componentName, context = params.context, selector = params.selector;
|
|
322
322
|
violations = [];
|
|
323
323
|
suggestions = [];
|
|
324
324
|
axeResults = {};
|
|
325
|
-
_context2.next =
|
|
325
|
+
_context2.next = 1;
|
|
326
326
|
return _puppeteer2.default.launch();
|
|
327
|
-
case
|
|
327
|
+
case 1:
|
|
328
328
|
browser = _context2.sent;
|
|
329
|
-
_context2.next =
|
|
329
|
+
_context2.next = 2;
|
|
330
330
|
return browser.newPage();
|
|
331
|
-
case
|
|
331
|
+
case 2:
|
|
332
332
|
page = _context2.sent;
|
|
333
|
-
_context2.prev =
|
|
334
|
-
_context2.next =
|
|
333
|
+
_context2.prev = 3;
|
|
334
|
+
_context2.next = 4;
|
|
335
335
|
return page.goto(url, {
|
|
336
336
|
waitUntil: 'networkidle0'
|
|
337
337
|
});
|
|
338
|
-
case
|
|
338
|
+
case 4:
|
|
339
339
|
if (!selector) {
|
|
340
|
-
_context2.next =
|
|
340
|
+
_context2.next = 7;
|
|
341
341
|
break;
|
|
342
342
|
}
|
|
343
|
-
_context2.next =
|
|
343
|
+
_context2.next = 5;
|
|
344
344
|
return page.$(selector);
|
|
345
|
-
case
|
|
345
|
+
case 5:
|
|
346
346
|
elementExists = _context2.sent;
|
|
347
347
|
if (elementExists) {
|
|
348
|
-
_context2.next =
|
|
348
|
+
_context2.next = 7;
|
|
349
349
|
break;
|
|
350
350
|
}
|
|
351
|
-
_context2.next =
|
|
351
|
+
_context2.next = 6;
|
|
352
352
|
return page.evaluate(function () {
|
|
353
353
|
var elements = Array.from(document.querySelectorAll('[id]'));
|
|
354
354
|
return elements.map(function (el) {
|
|
355
355
|
return "#".concat(el.id);
|
|
356
356
|
});
|
|
357
357
|
});
|
|
358
|
-
case
|
|
358
|
+
case 6:
|
|
359
359
|
availableElements = _context2.sent;
|
|
360
360
|
throw new Error("Element with selector \"".concat(selector, "\" not found on the page after waiting. Available elements: ").concat(availableElements.join(', ')));
|
|
361
|
-
case
|
|
361
|
+
case 7:
|
|
362
362
|
// Run axe-core accessibility analysis
|
|
363
363
|
axePuppeteer = new _puppeteer.AxePuppeteer(page); // If selector is provided, analyze only that element
|
|
364
364
|
if (selector) {
|
|
365
365
|
axePuppeteer.include(selector);
|
|
366
366
|
}
|
|
367
|
-
_context2.next =
|
|
367
|
+
_context2.next = 8;
|
|
368
368
|
return axePuppeteer.analyze();
|
|
369
|
-
case
|
|
369
|
+
case 8:
|
|
370
370
|
results = _context2.sent;
|
|
371
371
|
if (results.violations && results.violations.length > 0) {
|
|
372
372
|
adsViolations = mapAxeViolationsToADSFixes(results.violations);
|
|
@@ -422,9 +422,9 @@ var analyzeLocalhostA11yTool = exports.analyzeLocalhostA11yTool = /*#__PURE__*/f
|
|
|
422
422
|
incomplete: ((_axeResults$incomplet2 = axeResults.incomplete) === null || _axeResults$incomplet2 === void 0 ? void 0 : _axeResults$incomplet2.length) || 0
|
|
423
423
|
}
|
|
424
424
|
};
|
|
425
|
-
_context2.next =
|
|
425
|
+
_context2.next = 9;
|
|
426
426
|
return browser.close();
|
|
427
|
-
case
|
|
427
|
+
case 9:
|
|
428
428
|
return _context2.abrupt("return", {
|
|
429
429
|
content: [{
|
|
430
430
|
type: 'text',
|
|
@@ -438,12 +438,12 @@ var analyzeLocalhostA11yTool = exports.analyzeLocalhostA11yTool = /*#__PURE__*/f
|
|
|
438
438
|
}, null, 2)
|
|
439
439
|
}]
|
|
440
440
|
});
|
|
441
|
-
case
|
|
442
|
-
_context2.prev =
|
|
443
|
-
|
|
444
|
-
_context2.next =
|
|
441
|
+
case 10:
|
|
442
|
+
_context2.prev = 10;
|
|
443
|
+
_t2 = _context2["catch"](3);
|
|
444
|
+
_context2.next = 11;
|
|
445
445
|
return browser.close();
|
|
446
|
-
case
|
|
446
|
+
case 11:
|
|
447
447
|
return _context2.abrupt("return", {
|
|
448
448
|
content: [{
|
|
449
449
|
type: 'text',
|
|
@@ -466,16 +466,16 @@ var analyzeLocalhostA11yTool = exports.analyzeLocalhostA11yTool = /*#__PURE__*/f
|
|
|
466
466
|
},
|
|
467
467
|
violations: violations,
|
|
468
468
|
suggestions: [],
|
|
469
|
-
error: String(
|
|
469
|
+
error: String(_t2),
|
|
470
470
|
recommendations: ['Use ADS components for better accessibility out of the box', 'Reference https://atlassian.design/llms-a11y.txt for detailed guidelines', 'Test with keyboard navigation and screen readers', 'Use automated accessibility testing tools']
|
|
471
471
|
}, null, 2)
|
|
472
472
|
}]
|
|
473
473
|
});
|
|
474
|
-
case
|
|
474
|
+
case 12:
|
|
475
475
|
case "end":
|
|
476
476
|
return _context2.stop();
|
|
477
477
|
}
|
|
478
|
-
}, _callee2, null, [[
|
|
478
|
+
}, _callee2, null, [[3, 10]]);
|
|
479
479
|
}));
|
|
480
480
|
return function analyzeLocalhostA11yTool(_x2) {
|
|
481
481
|
return _ref2.apply(this, arguments);
|
|
@@ -32,12 +32,12 @@ var listGetA11yGuidelinesTool = exports.listGetA11yGuidelinesTool = {
|
|
|
32
32
|
var getA11yGuidelinesTool = exports.getA11yGuidelinesTool = /*#__PURE__*/function () {
|
|
33
33
|
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref) {
|
|
34
34
|
var topic, guidelines;
|
|
35
|
-
return _regenerator.default.wrap(function
|
|
35
|
+
return _regenerator.default.wrap(function (_context) {
|
|
36
36
|
while (1) switch (_context.prev = _context.next) {
|
|
37
37
|
case 0:
|
|
38
38
|
topic = _ref.topic;
|
|
39
39
|
if (!(topic && _guidelines.accessibilityGuidelines[topic])) {
|
|
40
|
-
_context.next =
|
|
40
|
+
_context.next = 1;
|
|
41
41
|
break;
|
|
42
42
|
}
|
|
43
43
|
guidelines = _guidelines.accessibilityGuidelines[topic];
|
|
@@ -51,7 +51,7 @@ var getA11yGuidelinesTool = exports.getA11yGuidelinesTool = /*#__PURE__*/functio
|
|
|
51
51
|
}), null, 2)
|
|
52
52
|
}]
|
|
53
53
|
});
|
|
54
|
-
case
|
|
54
|
+
case 1:
|
|
55
55
|
return _context.abrupt("return", {
|
|
56
56
|
content: [{
|
|
57
57
|
type: 'text',
|
|
@@ -63,7 +63,7 @@ var getA11yGuidelinesTool = exports.getA11yGuidelinesTool = /*#__PURE__*/functio
|
|
|
63
63
|
}, null, 2)
|
|
64
64
|
}]
|
|
65
65
|
});
|
|
66
|
-
case
|
|
66
|
+
case 2:
|
|
67
67
|
case "end":
|
|
68
68
|
return _context.stop();
|
|
69
69
|
}
|
|
@@ -40,7 +40,7 @@ var listGetAllIconsTool = exports.listGetAllIconsTool = {
|
|
|
40
40
|
};
|
|
41
41
|
var getAllIconsTool = exports.getAllIconsTool = /*#__PURE__*/function () {
|
|
42
42
|
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
43
|
-
return _regenerator.default.wrap(function
|
|
43
|
+
return _regenerator.default.wrap(function (_context) {
|
|
44
44
|
while (1) switch (_context.prev = _context.next) {
|
|
45
45
|
case 0:
|
|
46
46
|
return _context.abrupt("return", {
|
|
@@ -25,7 +25,7 @@ var listGetAllTokensTool = exports.listGetAllTokensTool = {
|
|
|
25
25
|
};
|
|
26
26
|
var getAllTokensTool = exports.getAllTokensTool = /*#__PURE__*/function () {
|
|
27
27
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
28
|
-
return _regenerator.default.wrap(function
|
|
28
|
+
return _regenerator.default.wrap(function (_context) {
|
|
29
29
|
while (1) switch (_context.prev = _context.next) {
|
|
30
30
|
case 0:
|
|
31
31
|
return _context.abrupt("return", {
|