@smartbear/mcp 0.12.0 → 0.13.1

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 (89) hide show
  1. package/README.md +30 -6
  2. package/dist/bugsnag/client/api/CurrentUser.js +50 -26
  3. package/dist/bugsnag/client/api/Error.js +158 -57
  4. package/dist/bugsnag/client/api/Project.js +398 -243
  5. package/dist/bugsnag/client/api/api.js +4087 -3837
  6. package/dist/bugsnag/client/api/base.js +155 -173
  7. package/dist/bugsnag/client/api/configuration.js +28 -25
  8. package/dist/bugsnag/client/filters.js +11 -20
  9. package/dist/bugsnag/client.js +1398 -1277
  10. package/dist/bugsnag/input-schemas.js +39 -57
  11. package/dist/collaborator/client.js +335 -371
  12. package/dist/common/bugsnag.js +5 -3
  13. package/dist/common/cache.js +50 -57
  14. package/dist/common/client-registry.js +106 -119
  15. package/dist/common/info.js +7 -3
  16. package/dist/common/register-clients.js +0 -16
  17. package/dist/common/server.js +270 -228
  18. package/dist/common/tools.js +19 -0
  19. package/dist/common/transport-http.js +252 -343
  20. package/dist/common/transport-stdio.js +40 -37
  21. package/dist/common/zod-utils.js +20 -0
  22. package/dist/index.js +18 -23
  23. package/dist/package.json.js +11 -0
  24. package/dist/pactflow/client/ai.js +142 -169
  25. package/dist/pactflow/client/base.js +41 -51
  26. package/dist/pactflow/client/prompt-utils.js +93 -84
  27. package/dist/pactflow/client/prompts.js +95 -92
  28. package/dist/pactflow/client/tools.js +94 -83
  29. package/dist/pactflow/client/utils.js +60 -64
  30. package/dist/pactflow/client.js +399 -320
  31. package/dist/qmetry/client/api/client-api.js +43 -41
  32. package/dist/qmetry/client/api/error-handler.js +264 -310
  33. package/dist/qmetry/client/auto-resolve.js +78 -99
  34. package/dist/qmetry/client/automation.js +139 -162
  35. package/dist/qmetry/client/handlers.js +49 -46
  36. package/dist/qmetry/client/issues.js +133 -115
  37. package/dist/qmetry/client/project.js +153 -174
  38. package/dist/qmetry/client/requirement.js +82 -70
  39. package/dist/qmetry/client/testcase.js +240 -208
  40. package/dist/qmetry/client/testsuite.js +332 -293
  41. package/dist/qmetry/client/tools/automation-tools.js +291 -288
  42. package/dist/qmetry/client/tools/index.js +16 -13
  43. package/dist/qmetry/client/tools/issue-tools.js +534 -543
  44. package/dist/qmetry/client/tools/project-tools.js +635 -656
  45. package/dist/qmetry/client/tools/requirement-tools.js +525 -528
  46. package/dist/qmetry/client/tools/testcase-tools.js +773 -786
  47. package/dist/qmetry/client/tools/testsuite-tools.js +1069 -1083
  48. package/dist/qmetry/client/utils.js +8 -14
  49. package/dist/qmetry/client.js +111 -109
  50. package/dist/qmetry/config/constants.js +48 -44
  51. package/dist/qmetry/config/rest-endpoints.js +51 -48
  52. package/dist/qmetry/types/automation.js +7 -7
  53. package/dist/qmetry/types/common.js +763 -1049
  54. package/dist/qmetry/types/issues.js +26 -19
  55. package/dist/qmetry/types/project.js +32 -25
  56. package/dist/qmetry/types/requirements.js +26 -21
  57. package/dist/qmetry/types/testcase.js +55 -44
  58. package/dist/qmetry/types/testsuite.js +66 -52
  59. package/dist/reflect/client.js +284 -226
  60. package/dist/swagger/client/api.js +645 -662
  61. package/dist/swagger/client/configuration.js +31 -33
  62. package/dist/swagger/client/portal-types.js +204 -244
  63. package/dist/swagger/client/registry-types.js +62 -96
  64. package/dist/swagger/client/tools.js +148 -158
  65. package/dist/swagger/client/user-management-types.js +11 -22
  66. package/dist/swagger/client.js +143 -135
  67. package/dist/swagger/config-utils.js +10 -16
  68. package/dist/zephyr/client.js +43 -42
  69. package/dist/zephyr/common/api-client.js +35 -30
  70. package/dist/zephyr/common/auth-service.js +16 -13
  71. package/dist/zephyr/common/rest-api-schemas.js +3173 -5146
  72. package/dist/zephyr/tool/environment/get-environments.js +66 -66
  73. package/dist/zephyr/tool/priority/get-priorities.js +41 -41
  74. package/dist/zephyr/tool/project/get-project.js +37 -37
  75. package/dist/zephyr/tool/project/get-projects.js +46 -46
  76. package/dist/zephyr/tool/status/get-statuses.js +47 -47
  77. package/dist/zephyr/tool/test-case/get-test-case.js +37 -37
  78. package/dist/zephyr/tool/test-case/get-test-cases.js +62 -62
  79. package/dist/zephyr/tool/test-cycle/get-test-cycle.js +37 -37
  80. package/dist/zephyr/tool/test-cycle/get-test-cycles.js +70 -70
  81. package/dist/zephyr/tool/test-execution/get-test-execution.js +37 -37
  82. package/dist/zephyr/tool/test-execution/get-test-executions.js +43 -43
  83. package/package.json +5 -5
  84. package/dist/bugsnag/client/api/index.js +0 -6
  85. package/dist/common/types.js +0 -6
  86. package/dist/qmetry/client/tools/types.js +0 -1
  87. package/dist/swagger/client/index.js +0 -6
  88. package/dist/tests/unit/bugsnag/utils/factories.js +0 -86
  89. package/dist/zephyr/tool/zephyr-tool.js +0 -1
@@ -1,191 +1,173 @@
1
- import { ToolError } from "../../../common/types.js";
2
- // Utility to pick only allowed fields from an object
3
- export function pickFields(obj, keys) {
4
- const result = {};
5
- if (!obj)
6
- return result;
7
- for (const key of keys) {
8
- if (key in obj) {
9
- result[key] = obj[key];
10
- }
1
+ import { ToolError } from "../../../common/tools.js";
2
+ function pickFields(obj, keys) {
3
+ const result = {};
4
+ if (!obj) return result;
5
+ for (const key of keys) {
6
+ if (key in obj) {
7
+ result[key] = obj[key];
11
8
  }
12
- return result;
9
+ }
10
+ return result;
13
11
  }
14
- // Utility to pick only allowed fields from an array of objects
15
- export function pickFieldsFromArray(arr, keys) {
16
- return arr.map((obj) => pickFields(obj, keys));
12
+ function pickFieldsFromArray(arr, keys) {
13
+ return arr.map((obj) => pickFields(obj, keys));
17
14
  }
18
- // Utility to extract next URL path from Link header
19
- export function getNextUrlPathFromHeader(headers, basePath) {
20
- if (!headers)
21
- return null;
22
- const link = headers.get("link") || headers.get("Link");
23
- if (!link)
24
- return null;
25
- const match = link.match(/<([^>]+)>;\s*rel="next"/)?.[1];
26
- if (!match)
27
- return null;
28
- return match.replace(basePath, "");
15
+ function getNextUrlPathFromHeader(headers, basePath) {
16
+ if (!headers) return null;
17
+ const link = headers.get("link") || headers.get("Link");
18
+ if (!link) return null;
19
+ const match = link.match(/<([^>]+)>;\s*rel="next"/)?.[1];
20
+ if (!match) return null;
21
+ return match.replace(basePath, "");
29
22
  }
30
- // Utility to extract total count from headers
31
23
  function getTotalCountFromHeader(headers) {
32
- if (!headers)
33
- return null;
34
- const totalCount = headers.get("X-Total-Count");
35
- if (!totalCount)
36
- return null;
37
- const parsed = parseInt(totalCount, 10);
38
- return Number.isNaN(parsed) ? null : parsed;
24
+ if (!headers) return null;
25
+ const totalCount = headers.get("X-Total-Count");
26
+ if (!totalCount) return null;
27
+ const parsed = parseInt(totalCount, 10);
28
+ return Number.isNaN(parsed) ? null : parsed;
29
+ }
30
+ function ensureFullUrl(url, basePath) {
31
+ return url.startsWith("http") ? url : `${basePath}${url}`;
39
32
  }
40
- // Utility to recursively convert object keys from snake_case to camelCase
41
- function convertKeysToCamelCase(obj) {
42
- if (obj === null || obj === undefined) {
43
- return obj;
33
+ function getQueryParams(nextUrl, options) {
34
+ const nextOptions = { query: {} };
35
+ if (nextUrl) {
36
+ nextOptions.query = {};
37
+ if (!nextUrl.includes("?")) {
38
+ throw new Error("nextUrl must contains query parameters");
44
39
  }
45
- if (Array.isArray(obj)) {
46
- return obj.map(convertKeysToCamelCase);
40
+ new URLSearchParams(nextUrl.split("?")[1]).forEach((value, key) => {
41
+ nextOptions.query[key] = value;
42
+ });
43
+ }
44
+ return nextOptions;
45
+ }
46
+ class BaseAPI {
47
+ configuration;
48
+ filterFields;
49
+ constructor(configuration, filterFields) {
50
+ this.configuration = configuration;
51
+ this.filterFields = filterFields || [];
52
+ }
53
+ async requestObject(url, options = {}, fields) {
54
+ if (!this.configuration.basePath) {
55
+ throw new Error("Base path is not configured for API requests");
47
56
  }
48
- if (typeof obj === "object" && obj.constructor === Object) {
49
- const converted = {};
50
- for (const [key, value] of Object.entries(obj)) {
51
- const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
52
- converted[camelKey] = convertKeysToCamelCase(value);
53
- }
54
- return converted;
57
+ if (this.configuration.headers) {
58
+ options.headers = {
59
+ ...this.configuration.headers,
60
+ ...options.headers
61
+ };
55
62
  }
56
- return obj;
57
- }
58
- // Ensure URL is absolute
59
- // The MCP tools exposed use only the path for pagination
60
- // For making requests, we need to ensure the URL is absolute
61
- export function ensureFullUrl(url, basePath) {
62
- return url.startsWith("http") ? url : `${basePath}${url}`;
63
- }
64
- // Merge nextUrl query parameters with options query parameters (usually filters)
65
- export function getQueryParams(nextUrl, options) {
66
- const nextOptions = { query: {} };
67
- if (nextUrl) {
68
- nextOptions.query = {};
69
- if (!nextUrl.includes("?")) {
70
- throw new Error("nextUrl must contains query parameters");
63
+ const response = await fetch(
64
+ ensureFullUrl(url, this.configuration.basePath),
65
+ {
66
+ ...options,
67
+ headers: {
68
+ ...options.headers,
69
+ ...this.configuration.headers
71
70
  }
72
- new URLSearchParams(nextUrl.split("?")[1]).forEach((value, key) => {
73
- nextOptions.query[key] = value;
74
- });
71
+ }
72
+ );
73
+ if (!response.ok) {
74
+ const errorText = await response.text();
75
+ throw new Error(
76
+ `Request failed with status ${response.status}: ${errorText}`
77
+ );
75
78
  }
76
- if (options) {
77
- nextOptions.query = { ...nextOptions.query, ...options.query };
79
+ const apiResponse = {
80
+ status: response.status,
81
+ headers: response.headers,
82
+ body: await response.json()
83
+ };
84
+ if (fields) {
85
+ apiResponse.body = pickFields(apiResponse.body, fields);
78
86
  }
79
- return nextOptions;
80
- }
81
- export class BaseAPI {
82
- configuration;
83
- filterFields;
84
- constructor(configuration, filterFields) {
85
- this.configuration = configuration;
86
- this.filterFields = filterFields || [];
87
+ if (this.filterFields) {
88
+ this.sanitizeResponse(apiResponse.body);
87
89
  }
88
- async requestObject(url, options = {}, fields) {
89
- if (!this.configuration.basePath) {
90
- throw new Error("Base path is not configured for API requests");
90
+ return apiResponse;
91
+ }
92
+ /**
93
+ * Fetches an array of resources from the API with support for pagination and field filtering.
94
+ *
95
+ * @template T - The type of objects in the response array, must extend Record<string, any>
96
+ * @param url - The API endpoint URL to fetch data from
97
+ * @param options - Optional request configuration including headers and other fetch options
98
+ * @param fetchAll - Whether to automatically fetch all pages of paginated results (default: false)
99
+ * @param fields - Optional array of field names to include in the response objects
100
+ * @returns A Promise resolving to an ApiResponse containing an array of type T
101
+ *
102
+ * @throws {ToolError} When the HTTP request fails with a non-ok status
103
+ * @throws {Error} When the response data is not an array
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const response = await client.requestArray<User>('/users', {}, true, ['id', 'name']);
108
+ * console.log(response.body); // Array of User objects with only id and name fields
109
+ * ```
110
+ */
111
+ async requestArray(url, options = {}, fetchAll = true, fields) {
112
+ let results = [];
113
+ let nextUrl = url;
114
+ let apiResponse;
115
+ do {
116
+ nextUrl = ensureFullUrl(nextUrl, this.configuration.basePath);
117
+ const response = await fetch(nextUrl, {
118
+ ...options,
119
+ headers: {
120
+ ...options.headers,
121
+ ...this.configuration.headers
91
122
  }
92
- if (this.configuration.headers) {
93
- options.headers = {
94
- ...this.configuration.headers,
95
- ...options.headers,
96
- };
97
- }
98
- const response = await fetch(ensureFullUrl(url, this.configuration.basePath), {
99
- ...options,
100
- headers: {
101
- ...options.headers,
102
- ...this.configuration.headers,
103
- },
104
- });
105
- if (!response.ok) {
106
- const errorText = await response.text();
107
- throw new Error(`Request failed with status ${response.status}: ${errorText}`);
108
- }
109
- const apiResponse = {
110
- status: response.status,
111
- headers: response.headers,
112
- body: convertKeysToCamelCase(await response.json()),
113
- };
114
- if (fields) {
115
- apiResponse.body = pickFields(apiResponse.body, fields);
116
- }
117
- if (this.filterFields) {
118
- this.sanitizeResponse(apiResponse.body);
119
- }
120
- return apiResponse;
123
+ });
124
+ if (!response.ok) {
125
+ const errorText = await response.text();
126
+ throw new ToolError(
127
+ `Request failed with status ${response.status}: ${errorText}`
128
+ );
129
+ }
130
+ const data = await response.json();
131
+ nextUrl = getNextUrlPathFromHeader(
132
+ response.headers,
133
+ this.configuration.basePath
134
+ );
135
+ if (!Array.isArray(data)) {
136
+ throw new Error("Expected response to be an array");
137
+ }
138
+ results = results.concat(data);
139
+ apiResponse = {
140
+ status: response.status,
141
+ headers: response.headers,
142
+ nextUrl,
143
+ totalCount: getTotalCountFromHeader(response.headers),
144
+ body: results
145
+ };
146
+ } while (fetchAll && nextUrl);
147
+ if (fields) {
148
+ apiResponse.body = pickFieldsFromArray(apiResponse.body, fields);
121
149
  }
122
- /**
123
- * Fetches an array of resources from the API with support for pagination and field filtering.
124
- *
125
- * @template T - The type of objects in the response array, must extend Record<string, any>
126
- * @param url - The API endpoint URL to fetch data from
127
- * @param options - Optional request configuration including headers and other fetch options
128
- * @param fetchAll - Whether to automatically fetch all pages of paginated results (default: false)
129
- * @param fields - Optional array of field names to include in the response objects
130
- * @returns A Promise resolving to an ApiResponse containing an array of type T
131
- *
132
- * @throws {ToolError} When the HTTP request fails with a non-ok status
133
- * @throws {Error} When the response data is not an array
134
- *
135
- * @example
136
- * ```typescript
137
- * const response = await client.requestArray<User>('/users', {}, true, ['id', 'name']);
138
- * console.log(response.body); // Array of User objects with only id and name fields
139
- * ```
140
- */
141
- async requestArray(url, options = {}, fetchAll = true, fields) {
142
- let results = [];
143
- let nextUrl = url;
144
- let apiResponse;
145
- do {
146
- nextUrl = ensureFullUrl(nextUrl, this.configuration.basePath);
147
- const response = await fetch(nextUrl, {
148
- ...options,
149
- headers: {
150
- ...options.headers,
151
- ...this.configuration.headers,
152
- },
153
- });
154
- if (!response.ok) {
155
- const errorText = await response.text();
156
- throw new ToolError(`Request failed with status ${response.status}: ${errorText}`);
157
- }
158
- const data = convertKeysToCamelCase(await response.json());
159
- nextUrl = getNextUrlPathFromHeader(response.headers, this.configuration.basePath);
160
- if (!Array.isArray(data)) {
161
- throw new Error("Expected response to be an array");
162
- }
163
- results = results.concat(data);
164
- apiResponse = {
165
- status: response.status,
166
- headers: response.headers,
167
- nextUrl: nextUrl,
168
- totalCount: getTotalCountFromHeader(response.headers),
169
- body: results,
170
- };
171
- } while (fetchAll && nextUrl);
172
- if (fields) {
173
- apiResponse.body = pickFieldsFromArray(apiResponse.body, fields);
174
- }
175
- if (this.filterFields) {
176
- apiResponse.body.forEach((item) => {
177
- this.sanitizeResponse(item);
178
- });
179
- }
180
- return apiResponse;
150
+ if (this.filterFields) {
151
+ apiResponse.body.forEach((item) => {
152
+ this.sanitizeResponse(item);
153
+ });
181
154
  }
182
- sanitizeResponse(data) {
183
- if (!data)
184
- return;
185
- for (const key of this.filterFields) {
186
- if (key in data) {
187
- delete data[key];
188
- }
189
- }
155
+ return apiResponse;
156
+ }
157
+ sanitizeResponse(data) {
158
+ if (!data) return;
159
+ for (const key of this.filterFields) {
160
+ if (key in data) {
161
+ delete data[key];
162
+ }
190
163
  }
164
+ }
191
165
  }
166
+ export {
167
+ BaseAPI,
168
+ ensureFullUrl,
169
+ getNextUrlPathFromHeader,
170
+ getQueryParams,
171
+ pickFields,
172
+ pickFieldsFromArray
173
+ };
@@ -1,26 +1,29 @@
1
- export class Configuration {
2
- /**
3
- * parameter for apiKey security
4
- * @param name security name
5
- * @memberof Configuration
6
- */
7
- apiKey;
8
- /**
9
- * override base path
10
- *
11
- * @type {string}
12
- * @memberof Configuration
13
- */
14
- basePath;
15
- /**
16
- * Additional headers for API requests
17
- * @type {Record<string, string>}
18
- * @memberof Configuration
19
- */
20
- headers;
21
- constructor(param) {
22
- this.apiKey = param.apiKey;
23
- this.basePath = param.basePath;
24
- this.headers = param.headers;
25
- }
1
+ class Configuration {
2
+ /**
3
+ * parameter for apiKey security
4
+ * @param name security name
5
+ * @memberof Configuration
6
+ */
7
+ apiKey;
8
+ /**
9
+ * override base path
10
+ *
11
+ * @type {string}
12
+ * @memberof Configuration
13
+ */
14
+ basePath;
15
+ /**
16
+ * Additional headers for API requests
17
+ * @type {Record<string, string>}
18
+ * @memberof Configuration
19
+ */
20
+ headers;
21
+ constructor(param) {
22
+ this.apiKey = param.apiKey;
23
+ this.basePath = param.basePath;
24
+ this.headers = param.headers;
25
+ }
26
26
  }
27
+ export {
28
+ Configuration
29
+ };
@@ -1,22 +1,13 @@
1
- /**
2
- * Filters utility for BugSnag API
3
- *
4
- * This file provides utility functions for creating filter URL parameters
5
- * based on the BugSnag filtering specification described in the Filtering.md document.
6
- */
7
- /**
8
- * Converts a FilterObject to URL search parameters
9
- *
10
- * @param filters The filter object to convert
11
- * @returns URLSearchParams object with the encoded filters
12
- */
13
- export function toUrlSearchParams(filters) {
14
- const params = new URLSearchParams();
15
- Object.entries(filters).forEach(([field, filterValues]) => {
16
- filterValues.forEach((filterValue) => {
17
- params.append(`filters[${field}][][type]`, filterValue.type);
18
- params.append(`filters[${field}][][value]`, filterValue.value.toString());
19
- });
1
+ function toUrlSearchParams(filters) {
2
+ const params = new URLSearchParams();
3
+ Object.entries(filters).forEach(([field, filterValues]) => {
4
+ filterValues.forEach((filterValue) => {
5
+ params.append(`filters[${field}][][type]`, filterValue.type);
6
+ params.append(`filters[${field}][][value]`, filterValue.value.toString());
20
7
  });
21
- return params;
8
+ });
9
+ return params;
22
10
  }
11
+ export {
12
+ toUrlSearchParams
13
+ };