@smartbear/mcp 0.8.0 → 0.9.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 (44) hide show
  1. package/dist/api-hub/client/api.js +51 -10
  2. package/dist/api-hub/client/registry-types.js +8 -0
  3. package/dist/api-hub/client/tools.js +7 -1
  4. package/dist/api-hub/client.js +3 -0
  5. package/dist/bugsnag/client/api/CurrentUser.js +12 -49
  6. package/dist/bugsnag/client/api/Error.js +29 -142
  7. package/dist/bugsnag/client/api/Project.js +52 -113
  8. package/dist/bugsnag/client/api/api.js +3743 -0
  9. package/dist/bugsnag/client/api/base.js +97 -34
  10. package/dist/bugsnag/client/api/configuration.js +26 -0
  11. package/dist/bugsnag/client/api/index.js +2 -0
  12. package/dist/bugsnag/client/filters.js +28 -0
  13. package/dist/bugsnag/client.js +100 -151
  14. package/dist/common/server.js +25 -3
  15. package/dist/common/types.js +6 -1
  16. package/dist/pactflow/client/prompt-utils.js +2 -1
  17. package/dist/pactflow/client/utils.js +5 -4
  18. package/dist/pactflow/client.js +10 -9
  19. package/dist/qmetry/client/api/client-api.js +21 -16
  20. package/dist/qmetry/client/api/error-handler.js +329 -0
  21. package/dist/qmetry/client/auto-resolve.js +74 -0
  22. package/dist/qmetry/client/handlers.js +19 -2
  23. package/dist/qmetry/client/issues.js +26 -0
  24. package/dist/qmetry/client/project.js +56 -0
  25. package/dist/qmetry/client/requirement.js +76 -0
  26. package/dist/qmetry/client/testcase.js +46 -8
  27. package/dist/qmetry/client/testsuite.js +117 -0
  28. package/dist/qmetry/client/tools.js +1455 -4
  29. package/dist/qmetry/client/utils.js +16 -0
  30. package/dist/qmetry/client.js +19 -16
  31. package/dist/qmetry/config/constants.js +14 -0
  32. package/dist/qmetry/config/rest-endpoints.js +20 -0
  33. package/dist/qmetry/types/common.js +313 -8
  34. package/dist/qmetry/types/issues.js +6 -0
  35. package/dist/qmetry/types/project.js +10 -0
  36. package/dist/qmetry/types/requirements.js +19 -0
  37. package/dist/qmetry/types/testcase.js +14 -0
  38. package/dist/qmetry/types/testsuite.js +26 -0
  39. package/dist/reflect/client.js +7 -6
  40. package/dist/zephyr/common/auth-service.js +1 -0
  41. package/package.json +1 -1
  42. package/dist/bugsnag/client/api/filters.js +0 -167
  43. package/dist/bugsnag/client/configuration.js +0 -10
  44. package/dist/bugsnag/client/index.js +0 -2
@@ -1,3 +1,4 @@
1
+ import { ToolError } from "../../common/types.js";
1
2
  // Regex to extract owner, name, and version from SwaggerHub URLs.
2
3
  // Matches /apis/owner/name/version, /domains/owner/name/version, or /templates/owner/name/version
3
4
  // Example: /apis/acme/petstore/1.0.0
@@ -70,7 +71,7 @@ export class ApiHubAPI {
70
71
  */
71
72
  async handleResponse(response, defaultReturn = {}) {
72
73
  if (!response.ok) {
73
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
74
+ throw new ToolError(`HTTP ${response.status}: ${response.statusText}`);
74
75
  }
75
76
  return this.parseResponse(response, defaultReturn);
76
77
  }
@@ -101,7 +102,7 @@ export class ApiHubAPI {
101
102
  });
102
103
  const result = await this.handleResponse(response);
103
104
  if (!("id" in result)) {
104
- throw new Error("Portal not found or empty response");
105
+ throw new ToolError("Portal not found or empty response");
105
106
  }
106
107
  return result;
107
108
  }
@@ -112,7 +113,7 @@ export class ApiHubAPI {
112
113
  });
113
114
  if (!response.ok) {
114
115
  const errorText = await response.text().catch(() => "");
115
- throw new Error(`API Hub deletePortal failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
116
+ throw new ToolError(`API Hub deletePortal failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
116
117
  }
117
118
  }
118
119
  async updatePortal(portalId, body) {
@@ -150,7 +151,7 @@ export class ApiHubAPI {
150
151
  });
151
152
  const result = await this.handleResponse(response);
152
153
  if (!("id" in result)) {
153
- throw new Error("Product not found or empty response");
154
+ throw new ToolError("Product not found or empty response");
154
155
  }
155
156
  return result;
156
157
  }
@@ -212,7 +213,7 @@ export class ApiHubAPI {
212
213
  headers: this.headers,
213
214
  });
214
215
  if (!response.ok) {
215
- throw new Error(`SwaggerHub Registry API searchApis failed - status: ${response.status} ${response.statusText}`);
216
+ throw new ToolError(`SwaggerHub Registry API searchApis failed - status: ${response.status} ${response.statusText}`);
216
217
  }
217
218
  const apisJsonResponse = (await response.json());
218
219
  // Transform APIs.json response to our ApiMetadata format
@@ -267,7 +268,7 @@ export class ApiHubAPI {
267
268
  headers: this.headers,
268
269
  });
269
270
  if (!response.ok) {
270
- throw new Error(`SwaggerHub Registry API getApiDefinition failed - status: ${response.status} ${response.statusText}`);
271
+ throw new ToolError(`SwaggerHub Registry API getApiDefinition failed - status: ${response.status} ${response.statusText}`);
271
272
  }
272
273
  // Return the raw API definition (could be JSON or YAML)
273
274
  const contentType = response.headers.get("content-type");
@@ -301,7 +302,7 @@ export class ApiHubAPI {
301
302
  requestBody = JSON.stringify(parsedDefinition);
302
303
  }
303
304
  catch (error) {
304
- throw new Error(`Invalid JSON format in definition: ${error instanceof Error ? error.message : "Unknown error"}`);
305
+ throw new ToolError(`Invalid JSON format in definition: ${error instanceof Error ? error.message : "Unknown error"}`);
305
306
  }
306
307
  }
307
308
  // Construct the URL with query parameters
@@ -320,7 +321,7 @@ export class ApiHubAPI {
320
321
  });
321
322
  if (!response.ok) {
322
323
  const errorText = await response.text().catch(() => "");
323
- throw new Error(`SwaggerHub Registry API createOrUpdateApi failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
324
+ throw new ToolError(`SwaggerHub Registry API createOrUpdateApi failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
324
325
  }
325
326
  // Determine operation type based on HTTP status code
326
327
  const operation = response.status === 201 ? "create" : "update";
@@ -353,7 +354,7 @@ export class ApiHubAPI {
353
354
  });
354
355
  if (!response.ok) {
355
356
  const errorText = await response.text().catch(() => "");
356
- throw new Error(`SwaggerHub Registry API createApiFromTemplate failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
357
+ throw new ToolError(`SwaggerHub Registry API createApiFromTemplate failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
357
358
  }
358
359
  // Determine operation type based on HTTP status code
359
360
  const operation = response.status === 201 ? "create" : "update";
@@ -374,7 +375,7 @@ export class ApiHubAPI {
374
375
  detectDefinitionFormat(definition) {
375
376
  const trimmed = definition.trim();
376
377
  if (!trimmed) {
377
- throw new Error("Empty definition content provided");
378
+ throw new ToolError("Empty definition content provided");
378
379
  }
379
380
  try {
380
381
  JSON.parse(trimmed);
@@ -384,4 +385,44 @@ export class ApiHubAPI {
384
385
  return "yaml";
385
386
  }
386
387
  }
388
+ /**
389
+ * Run a standardization scan against an API definition
390
+ * @param params Parameters including organization name and API definition
391
+ * @returns Standardization result with validation errors
392
+ */
393
+ async scanStandardization(params) {
394
+ // Auto-detect format from the definition content
395
+ const format = this.detectDefinitionFormat(params.definition);
396
+ let contentType;
397
+ let requestBody;
398
+ if (format === "yaml") {
399
+ contentType = "application/yaml";
400
+ requestBody = params.definition; // Send YAML as-is
401
+ }
402
+ else {
403
+ contentType = "application/json";
404
+ // For JSON, parse and stringify to ensure valid JSON
405
+ try {
406
+ const parsedDefinition = JSON.parse(params.definition);
407
+ requestBody = JSON.stringify(parsedDefinition);
408
+ }
409
+ catch (error) {
410
+ throw new Error(`Invalid JSON format in definition: ${error instanceof Error ? error.message : "Unknown error"}`);
411
+ }
412
+ }
413
+ const url = `${this.config.registryBasePath}/standardization/${encodeURIComponent(params.orgName)}/scan`;
414
+ const response = await fetch(url, {
415
+ method: "POST",
416
+ headers: {
417
+ ...this.headers,
418
+ "Content-Type": contentType,
419
+ },
420
+ body: requestBody,
421
+ });
422
+ if (!response.ok) {
423
+ const errorText = await response.text().catch(() => "");
424
+ throw new Error(`SwaggerHub Registry API scanStandardization failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
425
+ }
426
+ return await this.handleResponse(response);
427
+ }
387
428
  }
@@ -67,3 +67,11 @@ export const CreateApiFromTemplateParamsSchema = z.object({
67
67
  .string()
68
68
  .describe("Template name to use for creating the API. Format: owner/template-name/version (e.g., 'swagger-hub/petstore-template/1.0.0'). API is created with fixed values: private visibility, no project assignment, and reconciliation enabled."),
69
69
  });
70
+ export const ScanStandardizationParamsSchema = z.object({
71
+ orgName: z
72
+ .string()
73
+ .describe("The organization name to use for standardization rules"),
74
+ definition: z
75
+ .string()
76
+ .describe("API definition content (OpenAPI/AsyncAPI specification in JSON or YAML format) to scan for standardization errors"),
77
+ });
@@ -6,7 +6,7 @@
6
6
  * This follows the pattern established in the pactflow module.
7
7
  */
8
8
  import { CreatePortalArgsSchema, CreateProductArgsSchema, PortalArgsSchema, ProductArgsSchema, UpdatePortalArgsSchema, UpdateProductArgsSchema, } from "./portal-types.js";
9
- import { ApiDefinitionParamsSchema, ApiSearchParamsSchema, CreateApiFromTemplateParamsSchema, CreateApiParamsSchema, } from "./registry-types.js";
9
+ import { ApiDefinitionParamsSchema, ApiSearchParamsSchema, CreateApiFromTemplateParamsSchema, CreateApiParamsSchema, ScanStandardizationParamsSchema, } from "./registry-types.js";
10
10
  export const TOOLS = [
11
11
  {
12
12
  title: "List Portals",
@@ -95,4 +95,10 @@ export const TOOLS = [
95
95
  zodSchema: CreateApiFromTemplateParamsSchema,
96
96
  handler: "createApiFromTemplate",
97
97
  },
98
+ {
99
+ title: "Scan API Standardization",
100
+ summary: "Run a standardization scan against an API definition using the organization's standardization configuration. Accepts a YAML or JSON OpenAPI/AsyncAPI definition and returns a list of standardization errors and validation issues.",
101
+ zodSchema: ScanStandardizationParamsSchema,
102
+ handler: "scanStandardization",
103
+ },
98
104
  ];
@@ -57,6 +57,9 @@ export class ApiHubClient {
57
57
  async createApiFromTemplate(args) {
58
58
  return this.api.createApiFromTemplate(args);
59
59
  }
60
+ async scanStandardization(args) {
61
+ return this.api.scanStandardization(args);
62
+ }
60
63
  registerTools(register, _getInput) {
61
64
  TOOLS.forEach((tool) => {
62
65
  const { handler, formatResponse, ...toolParams } = tool;
@@ -1,41 +1,19 @@
1
- import { BaseAPI, pickFieldsFromArray } from "./base.js";
1
+ import { CurrentUserApiFetchParamCreator, } from "./api.js";
2
+ import { BaseAPI } from "./base.js";
2
3
  import { ProjectAPI } from "./Project.js";
3
- // --- API Class ---
4
4
  export class CurrentUserAPI extends BaseAPI {
5
- static filterFields = [
6
- "collaborators_url",
7
- "projects_url",
8
- "upgrade_url",
5
+ static organizationFields = [
6
+ "id",
7
+ "name",
8
+ "slug",
9
9
  ];
10
- static organizationFields = ["id", "name", "slug"];
11
- constructor(configuration) {
12
- super(configuration, CurrentUserAPI.filterFields);
13
- }
14
10
  /**
15
11
  * List the current user's organizations
16
12
  * GET /user/organizations
17
13
  */
18
- async listUserOrganizations(options = {}) {
19
- const { admin, ...queryOptions } = options;
20
- const params = new URLSearchParams();
21
- if (admin !== undefined)
22
- params.append("admin", String(admin));
23
- for (const [key, value] of Object.entries(queryOptions)) {
24
- if (value !== undefined)
25
- params.append(key, String(value));
26
- }
27
- const url = params.toString()
28
- ? `/user/organizations?${params}`
29
- : "/user/organizations";
30
- const data = await this.request({
31
- method: "GET",
32
- url,
33
- });
34
- // Only return allowed fields
35
- return {
36
- ...data,
37
- body: pickFieldsFromArray(data.body || [], CurrentUserAPI.organizationFields),
38
- };
14
+ async listUserOrganizations(admin, perPage, options = {}) {
15
+ const localVarFetchArgs = CurrentUserApiFetchParamCreator(this.configuration).listUserOrganizations(admin, perPage, options);
16
+ return await this.requestArray(localVarFetchArgs.url, localVarFetchArgs.options, true, CurrentUserAPI.organizationFields);
39
17
  }
40
18
  /**
41
19
  * List projects for a given organization
@@ -44,23 +22,8 @@ export class CurrentUserAPI extends BaseAPI {
44
22
  * @param options Optional parameters for filtering, pagination, etc.
45
23
  * @returns A promise that resolves to the list of projects in the organization
46
24
  */
47
- async getOrganizationProjects(organizationId, options = {}) {
48
- const { ...queryOptions } = options;
49
- const params = new URLSearchParams();
50
- for (const [key, value] of Object.entries(queryOptions)) {
51
- if (value !== undefined)
52
- params.append(key, String(value));
53
- }
54
- const url = params.toString()
55
- ? `/organizations/${organizationId}/projects?${params}`
56
- : `/organizations/${organizationId}/projects`;
57
- const data = await this.request({
58
- method: "GET",
59
- url,
60
- });
61
- return {
62
- ...data,
63
- body: pickFieldsFromArray(data.body || [], ProjectAPI.projectFields),
64
- };
25
+ async getOrganizationProjects(organizationId, q, sort, direction, perPage, options) {
26
+ const localVarFetchArgs = CurrentUserApiFetchParamCreator(this.configuration).getOrganizationProjects(organizationId, q, sort, direction, perPage, options);
27
+ return await this.requestArray(localVarFetchArgs.url, localVarFetchArgs.options, true, ProjectAPI.projectFields);
65
28
  }
66
29
  }
@@ -1,177 +1,64 @@
1
- import { BaseAPI } from "./base.js";
2
- import { toQueryString } from "./filters.js";
3
- export const ErrorOperations = [
4
- "override_severity",
5
- "assign",
6
- "create_issue",
7
- "link_issue",
8
- "unlink_issue",
9
- "open",
10
- "snooze",
11
- "fix",
12
- "ignore",
13
- "delete",
14
- "discard",
15
- "undiscard",
16
- ];
17
- export const ReopenConditions = [
18
- "occurs_after",
19
- "n_occurrences_in_m_hours",
20
- "n_additional_occurrences",
21
- "n_additional_users",
22
- ];
23
- // --- API Class ---
1
+ import { ErrorsApiFetchParamCreator, } from "./api.js";
2
+ import { BaseAPI, getQueryParams } from "./base.js";
24
3
  export class ErrorAPI extends BaseAPI {
25
4
  static filterFields = ["url", "project_url", "events_url"];
26
- constructor(configuration) {
27
- super(configuration, ErrorAPI.filterFields);
28
- }
29
5
  /**
30
6
  * View an Error on a Project
31
7
  * GET /projects/{project_id}/errors/{error_id}
32
8
  */
33
- async viewErrorOnProject(projectId, errorId, options = {}) {
34
- const params = new URLSearchParams();
35
- for (const [key, value] of Object.entries(options)) {
36
- if (value !== undefined)
37
- params.append(key, String(value));
38
- }
39
- const url = params.toString()
40
- ? `/projects/${projectId}/errors/${errorId}?${params}`
41
- : `/projects/${projectId}/errors/${errorId}`;
42
- return (await this.request({
43
- method: "GET",
44
- url,
45
- }));
9
+ async viewErrorOnProject(projectId, errorId) {
10
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).viewErrorOnProject(projectId, errorId);
11
+ return await this.requestObject(localVarFetchArgs.url, localVarFetchArgs.options);
46
12
  }
47
13
  /**
48
14
  * Get the latest Event in a Project, with optional filters
49
15
  * GET /projects/{project_id}/events
50
16
  */
51
- async getLatestEventOnProject(projectId, queryString = "") {
52
- const url = `/projects/${projectId}/events${queryString}`;
53
- const response = await this.request({
54
- method: "GET",
55
- url,
56
- });
57
- return {
58
- ...response,
59
- body: response.body && response.body.length > 0
60
- ? response.body[0]
61
- : undefined, // Return only the latest event
62
- };
17
+ async listEventsOnProject(projectId, base, sort, direction, perPage, filters, fullReports) {
18
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).listEventsOnProject(projectId, base ?? undefined, sort, direction, perPage, undefined, fullReports, { query: filters });
19
+ return await this.requestArray(localVarFetchArgs.url, localVarFetchArgs.options, false);
63
20
  }
64
21
  /**
65
22
  * View an Event by ID
66
23
  * GET /projects/{project_id}/events/{event_id}
67
24
  */
68
- async viewEventById(projectId, eventId, options = {}) {
69
- const params = new URLSearchParams();
70
- for (const [key, value] of Object.entries(options)) {
71
- if (value !== undefined)
72
- params.append(key, String(value));
73
- }
74
- const url = params.toString()
75
- ? `/projects/${projectId}/events/${eventId}?${params}`
76
- : `/projects/${projectId}/events/${eventId}`;
77
- return (await this.request({
78
- method: "GET",
79
- url,
80
- }));
25
+ async viewEventById(projectId, eventId) {
26
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).viewEventById(projectId, eventId);
27
+ return await this.requestObject(localVarFetchArgs.url, localVarFetchArgs.options);
81
28
  }
82
29
  /**
83
30
  * List the Errors on a Project
84
31
  * GET /projects/{project_id}/errors
85
32
  */
86
- async listProjectErrors(projectId, options = {}) {
87
- let url = `/projects/${projectId}/errors`;
88
- // Next links need to be used as-is to ensure results are consistent, so only the page size can be modified
89
- if (options.next_url !== undefined) {
90
- const nextUrl = new URL(options.next_url);
91
- if (options.per_page !== undefined) {
92
- nextUrl.searchParams.set("per_page", options.per_page.toString());
33
+ async listProjectErrors(projectId, base, sort, direction, perPage, filters, nextUrl) {
34
+ const options = getQueryParams(nextUrl, nextUrl ? undefined : filters);
35
+ if (nextUrl) {
36
+ if (perPage) {
37
+ // Next links need to be used as-is to ensure results are consistent, so only the page size can be modified
38
+ // the others will get overridden
39
+ options.query.per_page = perPage.toString();
93
40
  }
94
- url = nextUrl.toString();
41
+ direction = undefined;
42
+ sort = undefined;
43
+ base = undefined;
95
44
  }
96
- else {
97
- const params = new URLSearchParams();
98
- // Add filter parameters
99
- if (options.filters) {
100
- const filterParams = new URLSearchParams(toQueryString(options.filters));
101
- filterParams.forEach((value, key) => {
102
- params.append(key, value);
103
- });
104
- }
105
- // Add pagination and sorting parameters
106
- if (options.base !== undefined) {
107
- params.append("base", options.base);
108
- }
109
- if (options.sort !== undefined) {
110
- params.append("sort", options.sort);
111
- }
112
- if (options.direction !== undefined) {
113
- params.append("direction", options.direction);
114
- }
115
- if (options.per_page !== undefined) {
116
- params.append("per_page", options.per_page.toString());
117
- }
118
- if (params.size > 0) {
119
- url = `/projects/${projectId}/errors?${params}`;
120
- }
121
- }
122
- return (await this.request({
123
- method: "GET",
124
- url,
125
- }, false));
45
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).listProjectErrors(projectId, base ?? undefined, sort, direction, perPage, undefined, options);
46
+ return await this.requestArray(localVarFetchArgs.url, localVarFetchArgs.options, false);
126
47
  }
127
48
  /**
128
49
  * Update an Error on a Project
129
50
  * PATCH /projects/{project_id}/errors/{error_id}
130
51
  */
131
- async updateErrorOnProject(projectId, errorId, data, options = {}) {
132
- const params = new URLSearchParams();
133
- for (const [key, value] of Object.entries(options)) {
134
- if (value !== undefined)
135
- params.append(key, String(value));
136
- }
137
- const url = params.toString()
138
- ? `/projects/${projectId}/errors/${errorId}?${params}`
139
- : `/projects/${projectId}/errors/${errorId}`;
140
- return (await this.request({
141
- method: "PATCH",
142
- url,
143
- body: data,
144
- }));
52
+ async updateErrorOnProject(projectId, errorId, body) {
53
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).updateErrorOnProject(body, projectId, errorId);
54
+ return await this.requestObject(localVarFetchArgs.url, localVarFetchArgs.options);
145
55
  }
146
56
  /**
147
57
  * List Pivots on an Error
148
58
  * GET /projects/{project_id}/errors/{error_id}/pivots
149
59
  */
150
- async listErrorPivots(projectId, errorId, options = {}) {
151
- const params = new URLSearchParams();
152
- if (options.filters) {
153
- const filterParams = new URLSearchParams(toQueryString(options.filters));
154
- filterParams.forEach((value, key) => {
155
- params.append(key, value);
156
- });
157
- }
158
- if (options.summary_size !== undefined) {
159
- params.append("summary_size", options.summary_size.toString());
160
- }
161
- if (options.pivots && options.pivots.length > 0) {
162
- options.pivots.forEach((pivot) => {
163
- params.append("pivots[]", pivot);
164
- });
165
- }
166
- if (options.per_page !== undefined) {
167
- params.append("per_page", options.per_page.toString());
168
- }
169
- const url = params.toString()
170
- ? `/projects/${projectId}/errors/${errorId}/pivots?${params}`
171
- : `/projects/${projectId}/errors/${errorId}/pivots`;
172
- return await this.request({
173
- method: "GET",
174
- url,
175
- });
60
+ async getPivotValuesOnAnError(projectId, errorId, filters, summarySize, pivots, perPage) {
61
+ const localVarFetchArgs = ErrorsApiFetchParamCreator(this.configuration).listPivotsOnAnError(projectId, errorId, undefined, summarySize, pivots, perPage, { query: filters });
62
+ return await this.requestArray(localVarFetchArgs.url, localVarFetchArgs.options, false);
176
63
  }
177
64
  }