@smartbear/mcp 0.7.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 (52) hide show
  1. package/README.md +19 -2
  2. package/dist/api-hub/client/api.js +198 -23
  3. package/dist/api-hub/client/registry-types.js +22 -0
  4. package/dist/api-hub/client/tools.js +19 -1
  5. package/dist/api-hub/client.js +9 -0
  6. package/dist/bugsnag/client/api/CurrentUser.js +13 -50
  7. package/dist/bugsnag/client/api/Error.js +30 -155
  8. package/dist/bugsnag/client/api/Project.js +56 -124
  9. package/dist/bugsnag/client/api/api.js +3743 -0
  10. package/dist/bugsnag/client/api/base.js +107 -32
  11. package/dist/bugsnag/client/api/configuration.js +26 -0
  12. package/dist/bugsnag/client/api/index.js +2 -0
  13. package/dist/bugsnag/client/filters.js +28 -0
  14. package/dist/bugsnag/client.js +157 -325
  15. package/dist/common/server.js +29 -4
  16. package/dist/common/types.js +6 -1
  17. package/dist/index.js +8 -1
  18. package/dist/pactflow/client/prompt-utils.js +2 -1
  19. package/dist/pactflow/client/tools.js +9 -9
  20. package/dist/pactflow/client/utils.js +5 -4
  21. package/dist/pactflow/client.js +16 -14
  22. package/dist/qmetry/client/api/client-api.js +21 -16
  23. package/dist/qmetry/client/api/error-handler.js +329 -0
  24. package/dist/qmetry/client/auto-resolve.js +74 -0
  25. package/dist/qmetry/client/handlers.js +19 -2
  26. package/dist/qmetry/client/issues.js +26 -0
  27. package/dist/qmetry/client/project.js +56 -0
  28. package/dist/qmetry/client/requirement.js +76 -0
  29. package/dist/qmetry/client/testcase.js +46 -8
  30. package/dist/qmetry/client/testsuite.js +117 -0
  31. package/dist/qmetry/client/tools.js +1455 -4
  32. package/dist/qmetry/client/utils.js +16 -0
  33. package/dist/qmetry/client.js +19 -16
  34. package/dist/qmetry/config/constants.js +14 -0
  35. package/dist/qmetry/config/rest-endpoints.js +20 -0
  36. package/dist/qmetry/types/common.js +313 -8
  37. package/dist/qmetry/types/issues.js +6 -0
  38. package/dist/qmetry/types/project.js +10 -0
  39. package/dist/qmetry/types/requirements.js +19 -0
  40. package/dist/qmetry/types/testcase.js +14 -0
  41. package/dist/qmetry/types/testsuite.js +26 -0
  42. package/dist/reflect/client.js +7 -6
  43. package/dist/zephyr/client.js +16 -0
  44. package/dist/zephyr/common/api-client.js +27 -0
  45. package/dist/zephyr/common/auth-service.js +15 -0
  46. package/dist/zephyr/common/types.js +35 -0
  47. package/dist/zephyr/tool/project/get-projects.js +54 -0
  48. package/dist/zephyr/tool/zephyr-tool.js +1 -0
  49. package/package.json +3 -2
  50. package/dist/bugsnag/client/api/filters.js +0 -167
  51. package/dist/bugsnag/client/configuration.js +0 -10
  52. package/dist/bugsnag/client/index.js +0 -2
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
  </div>
19
19
  <br />
20
20
 
21
- A Model Context Protocol (MCP) server which provides AI assistants with seamless access to SmartBear's suite of testing and monitoring tools, including [BugSnag](https://www.bugsnag.com/), [Reflect](https://reflect.run), [API Hub](https://www.smartbear.com/api-hub), [PactFlow](https://pactflow.io/), [Pact Broker](https://docs.pact.io/), and [QMetry](https://www.qmetry.com/)
21
+ A Model Context Protocol (MCP) server which provides AI assistants with seamless access to SmartBear's suite of testing and monitoring tools, including [BugSnag](https://www.bugsnag.com/), [Reflect](https://reflect.run), [API Hub](https://www.smartbear.com/api-hub), [PactFlow](https://pactflow.io/), [Pact Broker](https://docs.pact.io/), [QMetry](https://www.qmetry.com/), and [Zephyr](https://smartbear.com/test-management/zephyr/).
22
22
 
23
23
  ## What is MCP?
24
24
 
@@ -33,12 +33,13 @@ See individual guides for suggested prompts and supported tools and resources:
33
33
  - [API Hub](https://developer.smartbear.com/smartbear-mcp/docs/api-hub-integration) - Portal management capabilities
34
34
  - [PactFlow](https://developer.smartbear.com/pactflow/default/getting-started) - Contract testing capabilities
35
35
  - [QMetry](https://developer.smartbear.com/smartbear-mcp/docs/qmetry-integration) - QMetry Test Management capabilities
36
+ - [Zephyr](https://developer.smartbear.com/smartbear-mcp/docs/zephyr-integration) - Zephyr Test Management capabilities
36
37
 
37
38
 
38
39
  ## Prerequisites
39
40
 
40
41
  - Node.js 20+ and npm
41
- - Access to SmartBear products (BugSnag, Reflect, API Hub, or QMetry)
42
+ - Access to SmartBear products (BugSnag, Reflect, API Hub, QMetry, or Zephyr)
42
43
  - Valid API tokens for the products you want to integrate
43
44
 
44
45
  ## Installation
@@ -77,6 +78,8 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
77
78
  "PACT_BROKER_PASSWORD": "${input:pact_broker_password}",
78
79
  "QMETRY_API_KEY": "${input:qmetry_api_key}",
79
80
  "QMETRY_BASE_URL": "${input:qmetry_base_url}",
81
+ "ZEPHYR_API_TOKEN": "${input:zephyr_api_token}",
82
+ "ZEPHYR_BASE_URL": "${input:zephyr_base_url}"
80
83
  }
81
84
  }
82
85
  },
@@ -141,6 +144,18 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
141
144
  "description": "By default, connects to https://testmanagement.qmetry.com. Change to a custom QMetry server URL or a region-specific endpoint if needed.",
142
145
  "password": false
143
146
  },
147
+ {
148
+ "id": "zephyr_api_token",
149
+ "type": "promptString",
150
+ "description": "Zephyr API token - leave blank to disable Zephyr tools",
151
+ "password": true
152
+ },
153
+ {
154
+ "id": "zephyr_base_url",
155
+ "type": "promptString",
156
+ "description": "Zephyr API base URL. By default, connects to https://api.zephyrscale.smartbear.com/v2. Change to region-specific endpoint if needed.",
157
+ "password": false
158
+ }
144
159
  ]
145
160
  }
146
161
  ```
@@ -170,6 +185,8 @@ Add the following configuration to your `claude_desktop_config.json` to launch t
170
185
  "PACT_BROKER_PASSWORD": "your_pact_broker_password",
171
186
  "QMETRY_API_KEY": "your_qmetry_api_key",
172
187
  "QMETRY_BASE_URL": "https://testmanagement.qmetry.com",
188
+ "ZEPHYR_API_TOKEN": "your_zephyr_api_token",
189
+ "ZEPHYR_BASE_URL": "https://api.zephyrscale.smartbear.com/v2"
173
190
  }
174
191
  }
175
192
  }
@@ -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
@@ -39,13 +40,26 @@ export class ApiHubAPI {
39
40
  return (await response.json());
40
41
  }
41
42
  catch (error) {
42
- console.warn("Failed to parse JSON response:", error);
43
+ console.warn("Failed to parse JSON response (declared JSON):", error);
43
44
  return defaultReturn;
44
45
  }
45
46
  }
46
- // Fallback for non-JSON responses
47
+ // Fallback: read text and attempt heuristic JSON parse
47
48
  const text = await response.text();
48
- return text ? { message: text } : defaultReturn;
49
+ if (!text)
50
+ return defaultReturn;
51
+ const trimmed = text.trim();
52
+ const firstChar = trimmed[0];
53
+ if (firstChar === "{" || firstChar === "[") {
54
+ try {
55
+ return JSON.parse(trimmed);
56
+ }
57
+ catch (error) {
58
+ console.warn("Heuristic JSON parse failed:", error);
59
+ return { message: text };
60
+ }
61
+ }
62
+ return { message: text };
49
63
  }
50
64
  /**
51
65
  * Handles HTTP responses with smart JSON parsing and fallback handling.
@@ -57,7 +71,7 @@ export class ApiHubAPI {
57
71
  */
58
72
  async handleResponse(response, defaultReturn = {}) {
59
73
  if (!response.ok) {
60
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
74
+ throw new ToolError(`HTTP ${response.status}: ${response.statusText}`);
61
75
  }
62
76
  return this.parseResponse(response, defaultReturn);
63
77
  }
@@ -66,7 +80,8 @@ export class ApiHubAPI {
66
80
  method: "GET",
67
81
  headers: this.headers,
68
82
  });
69
- return response.json();
83
+ const result = await this.handleResponse(response, []);
84
+ return result;
70
85
  }
71
86
  async createPortal(body) {
72
87
  const response = await fetch(`${this.config.portalBasePath}/portals`, {
@@ -74,20 +89,32 @@ export class ApiHubAPI {
74
89
  headers: this.headers,
75
90
  body: JSON.stringify(body),
76
91
  });
77
- return response.json();
92
+ const result = await this.handleResponse(response);
93
+ if (!("id" in result)) {
94
+ throw new Error("Unexpected empty response creating portal");
95
+ }
96
+ return result;
78
97
  }
79
98
  async getPortal(portalId) {
80
99
  const response = await fetch(`${this.config.portalBasePath}/portals/${portalId}`, {
81
100
  method: "GET",
82
101
  headers: this.headers,
83
102
  });
84
- return response.json();
103
+ const result = await this.handleResponse(response);
104
+ if (!("id" in result)) {
105
+ throw new ToolError("Portal not found or empty response");
106
+ }
107
+ return result;
85
108
  }
86
109
  async deletePortal(portalId) {
87
- await fetch(`${this.config.portalBasePath}/portals/${portalId}`, {
110
+ const response = await fetch(`${this.config.portalBasePath}/portals/${portalId}`, {
88
111
  method: "DELETE",
89
112
  headers: this.headers,
90
113
  });
114
+ if (!response.ok) {
115
+ const errorText = await response.text().catch(() => "");
116
+ throw new ToolError(`API Hub deletePortal failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
117
+ }
91
118
  }
92
119
  async updatePortal(portalId, body) {
93
120
  const response = await fetch(`${this.config.portalBasePath}/portals/${portalId}`, {
@@ -102,7 +129,8 @@ export class ApiHubAPI {
102
129
  method: "GET",
103
130
  headers: this.headers,
104
131
  });
105
- return response.json();
132
+ const result = await this.handleResponse(response, []);
133
+ return result;
106
134
  }
107
135
  async createPortalProduct(portalId, body) {
108
136
  const response = await fetch(`${this.config.portalBasePath}/portals/${portalId}/products`, {
@@ -110,14 +138,22 @@ export class ApiHubAPI {
110
138
  headers: this.headers,
111
139
  body: JSON.stringify(body),
112
140
  });
113
- return response.json();
141
+ const result = await this.handleResponse(response);
142
+ if (!("id" in result)) {
143
+ throw new Error("Unexpected empty response creating product");
144
+ }
145
+ return result;
114
146
  }
115
147
  async getPortalProduct(productId) {
116
148
  const response = await fetch(`${this.config.portalBasePath}/products/${productId}`, {
117
149
  method: "GET",
118
150
  headers: this.headers,
119
151
  });
120
- return response.json();
152
+ const result = await this.handleResponse(response);
153
+ if (!("id" in result)) {
154
+ throw new ToolError("Product not found or empty response");
155
+ }
156
+ return result;
121
157
  }
122
158
  async deletePortalProduct(productId) {
123
159
  const response = await fetch(`${this.config.portalBasePath}/products/${productId}`, {
@@ -132,13 +168,9 @@ export class ApiHubAPI {
132
168
  headers: this.headers,
133
169
  body: JSON.stringify(body),
134
170
  });
135
- // Custom error handling for updatePortalProduct
136
- if (!response.ok) {
137
- const errorText = await response.text().catch(() => "");
138
- throw new Error(`API Hub updatePortalProduct failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
139
- }
140
- // Use handleResponse but with custom default return value
141
- return this.handleResponseWithoutErrorCheck(response, { success: true });
171
+ return this.handleResponse(response, {
172
+ success: true,
173
+ });
142
174
  }
143
175
  /**
144
176
  * Helper method for handling responses when error checking is already done.
@@ -149,9 +181,6 @@ export class ApiHubAPI {
149
181
  * @param defaultReturn - Default value to return for empty responses
150
182
  * @returns Parsed response data or fallback value
151
183
  */
152
- async handleResponseWithoutErrorCheck(response, defaultReturn = {}) {
153
- return this.parseResponse(response, defaultReturn);
154
- }
155
184
  // Registry API methods for SwaggerHub Design functionality
156
185
  /**
157
186
  * Search APIs and Domains in SwaggerHub Registry using /specs endpoint
@@ -184,7 +213,7 @@ export class ApiHubAPI {
184
213
  headers: this.headers,
185
214
  });
186
215
  if (!response.ok) {
187
- 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}`);
188
217
  }
189
218
  const apisJsonResponse = (await response.json());
190
219
  // Transform APIs.json response to our ApiMetadata format
@@ -239,7 +268,7 @@ export class ApiHubAPI {
239
268
  headers: this.headers,
240
269
  });
241
270
  if (!response.ok) {
242
- 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}`);
243
272
  }
244
273
  // Return the raw API definition (could be JSON or YAML)
245
274
  const contentType = response.headers.get("content-type");
@@ -250,4 +279,150 @@ export class ApiHubAPI {
250
279
  return response.text();
251
280
  }
252
281
  }
282
+ /**
283
+ * Create or Update API in SwaggerHub Registry
284
+ * @param params Parameters for creating or updating the API including owner, name, version, specification, and definition
285
+ * @returns Created or updated API metadata with URL. HTTP 201 indicates creation, HTTP 200 indicates update
286
+ */
287
+ async createOrUpdateApi(params) {
288
+ // Determine the format of the definition
289
+ let contentType;
290
+ let requestBody;
291
+ // Auto-detect format from the definition content
292
+ const format = this.detectDefinitionFormat(params.definition);
293
+ if (format === "yaml") {
294
+ contentType = "application/yaml";
295
+ requestBody = params.definition; // Send YAML as-is
296
+ }
297
+ else {
298
+ contentType = "application/json";
299
+ // For JSON, parse and stringify to ensure valid JSON
300
+ try {
301
+ const parsedDefinition = JSON.parse(params.definition);
302
+ requestBody = JSON.stringify(parsedDefinition);
303
+ }
304
+ catch (error) {
305
+ throw new ToolError(`Invalid JSON format in definition: ${error instanceof Error ? error.message : "Unknown error"}`);
306
+ }
307
+ }
308
+ // Construct the URL with query parameters
309
+ // Fixed values: visibility=private, automock=false, version=1.0.0
310
+ const searchParams = new URLSearchParams();
311
+ searchParams.append("isPrivate", "true");
312
+ const url = `${this.config.registryBasePath}/apis/${encodeURIComponent(params.owner)}/${encodeURIComponent(params.apiName)}?${searchParams.toString()}`;
313
+ // Use POST method with the appropriate content type
314
+ const response = await fetch(url, {
315
+ method: "POST",
316
+ headers: {
317
+ ...this.headers,
318
+ "Content-Type": contentType,
319
+ },
320
+ body: requestBody,
321
+ });
322
+ if (!response.ok) {
323
+ const errorText = await response.text().catch(() => "");
324
+ throw new ToolError(`SwaggerHub Registry API createOrUpdateApi failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
325
+ }
326
+ // Determine operation type based on HTTP status code
327
+ const operation = response.status === 201 ? "create" : "update";
328
+ // Return formatted response with the required fields
329
+ // Fixed version is always 1.0.0
330
+ return {
331
+ owner: params.owner,
332
+ apiName: params.apiName,
333
+ version: "1.0.0",
334
+ url: `https://app.swaggerhub.com/apis/${params.owner}/${params.apiName}/1.0.0`,
335
+ operation,
336
+ };
337
+ }
338
+ /**
339
+ * Create API from Template in SwaggerHub Registry
340
+ * @param params Parameters for creating API from template including owner, api name, and template
341
+ * @returns Created API metadata with URL. HTTP 201 indicates creation, HTTP 200 indicates update
342
+ */
343
+ async createApiFromTemplate(params) {
344
+ // Construct the URL with query parameters
345
+ // Fixed values: visibility=private, no project, noReconcile=false
346
+ const searchParams = new URLSearchParams();
347
+ searchParams.append("isPrivate", "true");
348
+ searchParams.append("template", params.template);
349
+ const url = `${this.config.registryBasePath}/apis/${encodeURIComponent(params.owner)}/${encodeURIComponent(params.apiName)}/.template?${searchParams.toString()}`;
350
+ // Use POST method for template creation
351
+ const response = await fetch(url, {
352
+ method: "POST",
353
+ headers: this.headers,
354
+ });
355
+ if (!response.ok) {
356
+ const errorText = await response.text().catch(() => "");
357
+ throw new ToolError(`SwaggerHub Registry API createApiFromTemplate failed - status: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}. URL: ${url}`);
358
+ }
359
+ // Determine operation type based on HTTP status code
360
+ const operation = response.status === 201 ? "create" : "update";
361
+ // Return formatted response with the required fields
362
+ return {
363
+ owner: params.owner,
364
+ apiName: params.apiName,
365
+ template: params.template,
366
+ url: `https://app.swaggerhub.com/apis/${params.owner}/${params.apiName}`,
367
+ operation,
368
+ };
369
+ }
370
+ /**
371
+ * Auto-detect the format of an API definition string
372
+ * @param definition The API definition content
373
+ * @returns 'json' or 'yaml'
374
+ */
375
+ detectDefinitionFormat(definition) {
376
+ const trimmed = definition.trim();
377
+ if (!trimmed) {
378
+ throw new ToolError("Empty definition content provided");
379
+ }
380
+ try {
381
+ JSON.parse(trimmed);
382
+ return "json";
383
+ }
384
+ catch {
385
+ return "yaml";
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
+ }
253
428
  }
@@ -53,3 +53,25 @@ export const ApiDefinitionParamsSchema = z.object({
53
53
  .optional()
54
54
  .describe("Set to true to create models from inline schemas in OpenAPI definition (default false)"),
55
55
  });
56
+ export const CreateApiParamsSchema = z.object({
57
+ owner: z.string().describe("Organization name (owner of the API)"),
58
+ apiName: z.string().describe("API name"),
59
+ definition: z
60
+ .string()
61
+ .describe("API definition content (OpenAPI/AsyncAPI specification in JSON or YAML format). Format is automatically detected. API is created with fixed values: version 1.0.0, private visibility, automock disabled, and no project assignment."),
62
+ });
63
+ export const CreateApiFromTemplateParamsSchema = z.object({
64
+ owner: z.string().describe("Organization name (owner of the API)"),
65
+ apiName: z.string().describe("API name"),
66
+ template: z
67
+ .string()
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
+ });
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, } 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",
@@ -83,4 +83,22 @@ export const TOOLS = [
83
83
  zodSchema: ApiDefinitionParamsSchema,
84
84
  handler: "getApiDefinition",
85
85
  },
86
+ {
87
+ title: "Create or Update API",
88
+ summary: "Create a new API or update an existing API in SwaggerHub Registry for API Hub for Design. The API specification type (OpenAPI, AsyncAPI) is automatically detected from the definition content. APIs are always created with fixed values: version 1.0.0, private visibility, and automock disabled (these values cannot be changed). Returns HTTP 201 for creation, HTTP 200 for update. Response includes 'operation' field indicating whether it was a 'create' or 'update' operation along with API details and SwaggerHub URL.",
89
+ zodSchema: CreateApiParamsSchema,
90
+ handler: "createOrUpdateApi",
91
+ },
92
+ {
93
+ title: "Create API from Template",
94
+ summary: "Create a new API in SwaggerHub Registry using a predefined template. This endpoint creates APIs based on existing templates without requiring manual definition content. APIs are always created with fixed values: private visibility, no project assignment, and reconciliation enabled (these values cannot be changed). Returns HTTP 201 for creation, HTTP 200 for update. Response includes 'operation' field and API details with SwaggerHub URL.",
95
+ zodSchema: CreateApiFromTemplateParamsSchema,
96
+ handler: "createApiFromTemplate",
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
+ },
86
104
  ];
@@ -51,6 +51,15 @@ export class ApiHubClient {
51
51
  async getApiDefinition(args) {
52
52
  return this.api.getApiDefinition(args);
53
53
  }
54
+ async createOrUpdateApi(args) {
55
+ return this.api.createOrUpdateApi(args);
56
+ }
57
+ async createApiFromTemplate(args) {
58
+ return this.api.createApiFromTemplate(args);
59
+ }
60
+ async scanStandardization(args) {
61
+ return this.api.scanStandardization(args);
62
+ }
54
63
  registerTools(register, _getInput) {
55
64
  TOOLS.forEach((tool) => {
56
65
  const { handler, formatResponse, ...toolParams } = tool;
@@ -1,41 +1,19 @@
1
- import { BaseAPI, pickFieldsFromArray } from "./base.js";
2
- // --- API Class ---
1
+ import { CurrentUserApiFetchParamCreator, } from "./api.js";
2
+ import { BaseAPI } from "./base.js";
3
+ import { ProjectAPI } from "./Project.js";
3
4
  export class CurrentUserAPI extends BaseAPI {
4
- static filterFields = [
5
- "collaborators_url",
6
- "projects_url",
7
- "upgrade_url",
5
+ static organizationFields = [
6
+ "id",
7
+ "name",
8
+ "slug",
8
9
  ];
9
- static organizationFields = ["id", "name", "slug"];
10
- static projectFields = ["id", "name", "slug", "api_key"];
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, paginate = false, ...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
- }, paginate);
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
- }, true); // Always paginate for projects
61
- return {
62
- ...data,
63
- body: pickFieldsFromArray(data.body || [], CurrentUserAPI.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
  }