@smartbear/mcp 0.9.0 → 0.10.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 (43) hide show
  1. package/README.md +29 -4
  2. package/dist/api-hub/client/api.js +188 -0
  3. package/dist/api-hub/client/configuration.js +5 -0
  4. package/dist/api-hub/client/index.js +1 -0
  5. package/dist/api-hub/client/portal-types.js +126 -0
  6. package/dist/api-hub/client/tools.js +72 -15
  7. package/dist/api-hub/client/user-management-types.js +24 -0
  8. package/dist/api-hub/client.js +31 -0
  9. package/dist/bugsnag/client.js +4 -4
  10. package/dist/collaborator/client.js +364 -0
  11. package/dist/common/server.js +48 -20
  12. package/dist/index.js +9 -1
  13. package/dist/pactflow/client/tools.js +4 -4
  14. package/dist/qmetry/client/auto-resolve.js +22 -0
  15. package/dist/qmetry/client/handlers.js +18 -4
  16. package/dist/qmetry/client/issues.js +98 -1
  17. package/dist/qmetry/client/project.js +18 -1
  18. package/dist/qmetry/client/testcase.js +79 -1
  19. package/dist/qmetry/client/testsuite.js +156 -1
  20. package/dist/qmetry/client/tools/index.js +17 -0
  21. package/dist/qmetry/client/tools/issue-tools.js +545 -0
  22. package/dist/qmetry/client/tools/project-tools.js +348 -0
  23. package/dist/qmetry/client/tools/requirement-tools.js +530 -0
  24. package/dist/qmetry/client/tools/testcase-tools.js +526 -0
  25. package/dist/qmetry/client/tools/testsuite-tools.js +772 -0
  26. package/dist/qmetry/client/tools/types.js +1 -0
  27. package/dist/qmetry/client.js +9 -2
  28. package/dist/qmetry/config/constants.js +14 -0
  29. package/dist/qmetry/config/rest-endpoints.js +10 -0
  30. package/dist/qmetry/types/common.js +287 -2
  31. package/dist/qmetry/types/issues.js +11 -1
  32. package/dist/qmetry/types/project.js +7 -0
  33. package/dist/qmetry/types/testcase.js +6 -0
  34. package/dist/qmetry/types/testsuite.js +19 -1
  35. package/dist/zephyr/client.js +7 -1
  36. package/dist/zephyr/common/api-client.js +8 -0
  37. package/dist/zephyr/common/rest-api-schemas.js +5173 -0
  38. package/dist/zephyr/tool/project/get-project.js +39 -0
  39. package/dist/zephyr/tool/project/get-projects.js +7 -13
  40. package/dist/zephyr/tool/test-cycle/get-test-cycles.js +72 -0
  41. package/package.json +1 -1
  42. package/dist/qmetry/client/tools.js +0 -1673
  43. package/dist/zephyr/common/types.js +0 -35
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  <!-- Badges -->
11
11
  <div>
12
- <a href="https://github.com/SmartBear/smartbear-mcp/actions/workflows/node-ci.yml"><img src="https://github.com/SmartBear/smartbear-mcp/actions/workflows/node-ci.yml/badge.svg?branch=next" alt="Test Status"></a>
12
+ <a href="https://github.com/SmartBear/smartbear-mcp/actions/workflows/test.yml"><img src="https://github.com/SmartBear/smartbear-mcp/actions/workflows/test.yml/badge.svg?branch=main" alt="Test Status"></a>
13
13
  <a href="https://smartbear.github.io/smartbear-mcp/"><img src="https://img.shields.io/badge/coverage-dynamic-brightgreen" alt="Coverage"></a>
14
14
  <a href="https://www.npmjs.com/package/@smartbear/mcp"><img src="https://img.shields.io/npm/v/@smartbear/mcp" alt="npm version"></a>
15
15
  <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Compatible-blue" alt="MCP Compatible"></a>
@@ -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/), [QMetry](https://www.qmetry.com/), and [Zephyr](https://smartbear.com/test-management/zephyr/).
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/), [Zephyr](https://smartbear.com/test-management/zephyr/) and [Collaborator](https://smartbear.com/product/collaborator/).
22
22
 
23
23
  ## What is MCP?
24
24
 
@@ -34,6 +34,7 @@ See individual guides for suggested prompts and supported tools and resources:
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
36
  - [Zephyr](https://developer.smartbear.com/smartbear-mcp/docs/zephyr-integration) - Zephyr Test Management capabilities
37
+ - [Collaborator](https://developer.smartbear.com/smartbear-mcp/docs/collaborator-integration) - Review and Remote System Configuration management capabilities
37
38
 
38
39
 
39
40
  ## Prerequisites
@@ -79,7 +80,10 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
79
80
  "QMETRY_API_KEY": "${input:qmetry_api_key}",
80
81
  "QMETRY_BASE_URL": "${input:qmetry_base_url}",
81
82
  "ZEPHYR_API_TOKEN": "${input:zephyr_api_token}",
82
- "ZEPHYR_BASE_URL": "${input:zephyr_base_url}"
83
+ "ZEPHYR_BASE_URL": "${input:zephyr_base_url}",
84
+ "COLLAB_BASE_URL": "${input:collab_base_url}",
85
+ "COLLAB_USERNAME": "${input:collab_username}",
86
+ "COLLAB_LOGIN_TICKET": "${input:collab_login_ticket}"
83
87
  }
84
88
  }
85
89
  },
@@ -155,6 +159,24 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
155
159
  "type": "promptString",
156
160
  "description": "Zephyr API base URL. By default, connects to https://api.zephyrscale.smartbear.com/v2. Change to region-specific endpoint if needed.",
157
161
  "password": false
162
+ },
163
+ {
164
+ "id": "collab_base_url",
165
+ "type": "promptString",
166
+ "description": "Collab base url",
167
+ "password": true
168
+ },
169
+ {
170
+ "id": "collab_username",
171
+ "type": "promptString",
172
+ "description": "Collab username",
173
+ "password": true
174
+ },
175
+ {
176
+ "id": "collab_login_ticket",
177
+ "type": "promptString",
178
+ "description": "Collab login ticket",
179
+ "password": true
158
180
  }
159
181
  ]
160
182
  }
@@ -186,7 +208,10 @@ Add the following configuration to your `claude_desktop_config.json` to launch t
186
208
  "QMETRY_API_KEY": "your_qmetry_api_key",
187
209
  "QMETRY_BASE_URL": "https://testmanagement.qmetry.com",
188
210
  "ZEPHYR_API_TOKEN": "your_zephyr_api_token",
189
- "ZEPHYR_BASE_URL": "https://api.zephyrscale.smartbear.com/v2"
211
+ "ZEPHYR_BASE_URL": "https://api.zephyrscale.smartbear.com/v2",
212
+ "COLLAB_BASE_URL": "your collab base url",
213
+ "COLLAB_USERNAME": "your collab user name",
214
+ "COLLAB_LOGIN_TICKET": "your collab login ticket"
190
215
  }
191
216
  }
192
217
  }
@@ -83,6 +83,34 @@ export class ApiHubAPI {
83
83
  const result = await this.handleResponse(response, []);
84
84
  return result;
85
85
  }
86
+ async getOrganizations(params) {
87
+ // Build query string if parameters are provided
88
+ const searchParams = new URLSearchParams();
89
+ if (params?.q)
90
+ searchParams.append("q", params.q);
91
+ if (params?.sortBy)
92
+ searchParams.append("sortBy", params.sortBy);
93
+ if (params?.order)
94
+ searchParams.append("order", params.order);
95
+ if (params?.page !== undefined)
96
+ searchParams.append("page", params.page.toString());
97
+ if (params?.pageSize)
98
+ searchParams.append("pageSize", params.pageSize.toString());
99
+ const queryString = searchParams.toString();
100
+ const url = `${this.config.userManagementBasePath}/orgs${queryString ? `?${queryString}` : ""}`;
101
+ const response = await fetch(url, {
102
+ method: "GET",
103
+ headers: this.headers,
104
+ });
105
+ const defaultResponse = {
106
+ items: [],
107
+ totalCount: 0,
108
+ pageSize: 50,
109
+ page: 0,
110
+ };
111
+ const result = await this.handleResponse(response, defaultResponse);
112
+ return result;
113
+ }
86
114
  async createPortal(body) {
87
115
  const response = await fetch(`${this.config.portalBasePath}/portals`, {
88
116
  method: "POST",
@@ -172,6 +200,166 @@ export class ApiHubAPI {
172
200
  success: true,
173
201
  });
174
202
  }
203
+ async publishPortalProduct(productId, preview = false) {
204
+ const response = await fetch(`${this.config.portalBasePath}/products/${productId}/published-content?preview=${preview}`, {
205
+ method: "PUT",
206
+ headers: this.headers,
207
+ });
208
+ return this.handleResponse(response, {
209
+ success: true,
210
+ });
211
+ }
212
+ async getPortalProductSections(productId, params) {
213
+ const queryParameters = new URLSearchParams();
214
+ if (params.embed) {
215
+ for (const item of params.embed) {
216
+ queryParameters.append("embed", item);
217
+ }
218
+ }
219
+ if (params.page !== undefined) {
220
+ queryParameters.append("page", params.page.toString());
221
+ }
222
+ if (params.size !== undefined) {
223
+ queryParameters.append("size", params.size.toString());
224
+ }
225
+ const url = `${this.config.portalBasePath}/products/${productId}/sections${queryParameters.toString() ? `?${queryParameters.toString()}` : ""}`;
226
+ const response = await fetch(url, {
227
+ method: "GET",
228
+ headers: this.headers,
229
+ });
230
+ const result = await this.handleResponse(response, []);
231
+ return result;
232
+ }
233
+ /**
234
+ * Create a new table of contents item in a portal product section
235
+ * @param sectionId - Section ID where the table of contents item will be created
236
+ * @param body - Table of contents creation parameters
237
+ * @returns Created table of contents item with metadata
238
+ */
239
+ async createTableOfContents(sectionId, body) {
240
+ const url = `${this.config.portalBasePath}/sections/${sectionId}/table-of-contents`;
241
+ const response = await fetch(url, {
242
+ method: "POST",
243
+ headers: this.headers,
244
+ body: JSON.stringify(body),
245
+ });
246
+ if (!response.ok) {
247
+ const errorText = await response.text();
248
+ throw new Error(`API Hub createTableOfContents failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
249
+ }
250
+ const result = await response.json();
251
+ return result;
252
+ }
253
+ /**
254
+ * Get table of contents for a section
255
+ * @param args - Parameters for retrieving table of contents
256
+ * @returns List of table of contents items
257
+ */
258
+ async getTableOfContents(args) {
259
+ const { sectionId, embed, page, size } = args;
260
+ const searchParams = new URLSearchParams();
261
+ if (embed) {
262
+ for (const item of embed) {
263
+ searchParams.append("embed", item);
264
+ }
265
+ }
266
+ if (page !== undefined) {
267
+ searchParams.set("page", page.toString());
268
+ }
269
+ if (size !== undefined) {
270
+ searchParams.set("size", size.toString());
271
+ }
272
+ const url = `${this.config.portalBasePath}/sections/${sectionId}/table-of-contents${searchParams.toString() ? `?${searchParams.toString()}` : ""}`;
273
+ const response = await fetch(url, {
274
+ method: "GET",
275
+ headers: this.headers,
276
+ });
277
+ if (!response.ok) {
278
+ const errorText = await response.text();
279
+ throw new Error(`API Hub getTableOfContents failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
280
+ }
281
+ const result = await response.json();
282
+ // The API returns a paginated response, so we extract the items array
283
+ return result.items;
284
+ }
285
+ /**
286
+ * Get document content and metadata
287
+ * @param args - Parameters for retrieving document
288
+ * @returns Document with content and metadata
289
+ */
290
+ async getDocument(args) {
291
+ const { documentId } = args;
292
+ const url = `${this.config.portalBasePath}/documents/${documentId}`;
293
+ const response = await fetch(url, {
294
+ method: "GET",
295
+ headers: this.headers,
296
+ });
297
+ if (!response.ok) {
298
+ const errorText = await response.text();
299
+ throw new Error(`API Hub getDocument failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
300
+ }
301
+ const result = await response.json();
302
+ return result;
303
+ }
304
+ /**
305
+ * Update document content
306
+ * @param args - Parameters for updating document
307
+ * @returns Success response
308
+ */
309
+ async updateDocument(args) {
310
+ const { documentId, ...body } = args;
311
+ const url = `${this.config.portalBasePath}/documents/${documentId}`;
312
+ const response = await fetch(url, {
313
+ method: "PATCH",
314
+ headers: this.headers,
315
+ body: JSON.stringify(body),
316
+ });
317
+ if (!response.ok) {
318
+ const errorText = await response.text();
319
+ throw new Error(`API Hub updateDocument failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
320
+ }
321
+ return { success: true };
322
+ }
323
+ /**
324
+ * Delete document
325
+ * @param args - Parameters for deleting document
326
+ * @returns Success response
327
+ */
328
+ async deleteDocument(args) {
329
+ const { documentId } = args;
330
+ const url = `${this.config.portalBasePath}/documents/${documentId}`;
331
+ const response = await fetch(url, {
332
+ method: "DELETE",
333
+ headers: this.headers,
334
+ });
335
+ if (!response.ok) {
336
+ const errorText = await response.text();
337
+ throw new Error(`API Hub deleteDocument failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
338
+ }
339
+ return { success: true };
340
+ }
341
+ /**
342
+ * Delete table of contents entry
343
+ * @param args - Parameters for deleting table of contents entry
344
+ * @returns Success response
345
+ */
346
+ async deleteTableOfContents(args) {
347
+ const { tableOfContentsId, recursive } = args;
348
+ const searchParams = new URLSearchParams();
349
+ if (recursive !== undefined) {
350
+ searchParams.set("recursive", recursive.toString());
351
+ }
352
+ const url = `${this.config.portalBasePath}/table-of-contents/${tableOfContentsId}${searchParams.toString() ? `?${searchParams.toString()}` : ""}`;
353
+ const response = await fetch(url, {
354
+ method: "DELETE",
355
+ headers: this.headers,
356
+ });
357
+ if (!response.ok) {
358
+ const errorText = await response.text();
359
+ throw new Error(`API Hub deleteTableOfContents failed - status: ${response.status} ${response.statusText}. Response: ${errorText}`);
360
+ }
361
+ return { success: true };
362
+ }
175
363
  /**
176
364
  * Helper method for handling responses when error checking is already done.
177
365
  * Delegates to parseResponse for the actual parsing logic.
@@ -2,6 +2,7 @@ export class ApiHubConfiguration {
2
2
  token;
3
3
  portalBasePath;
4
4
  registryBasePath;
5
+ userManagementBasePath;
5
6
  headers;
6
7
  constructor(param) {
7
8
  this.token = param.token;
@@ -9,6 +10,10 @@ export class ApiHubConfiguration {
9
10
  param.portalBasePath || "https://api.portal.swaggerhub.com/v1";
10
11
  this.registryBasePath =
11
12
  param.registryBasePath || "https://api.swaggerhub.com";
13
+ this.userManagementBasePath =
14
+ param.userManagementBasePath ||
15
+ "https://api.swaggerhub.com/user-management/v1";
16
+ // Use Bearer token format consistently across all APIs
12
17
  this.headers = {
13
18
  Authorization: `Bearer ${this.token}`,
14
19
  "Content-Type": "application/json",
@@ -3,3 +3,4 @@ export { ApiHubConfiguration, } from "./configuration.js";
3
3
  export * from "./portal-types.js";
4
4
  export * from "./registry-types.js";
5
5
  export { TOOLS } from "./tools.js";
6
+ export * from "./user-management-types.js";
@@ -10,6 +10,93 @@ export const ProductArgsSchema = z.object({
10
10
  .string()
11
11
  .describe("Product UUID or identifier in the format 'portal-subdomain:product-slug' - unique identifier for the product"),
12
12
  });
13
+ export const GetProductSectionsArgsSchema = z.object({
14
+ productId: z
15
+ .string()
16
+ .describe("Product UUID or identifier in the format 'portal-subdomain:product-slug' - unique identifier for the product"),
17
+ embed: z
18
+ .array(z.string())
19
+ .optional()
20
+ .describe("List of related entities to embed in the response - e.g., ['tableOfContents', 'tableOfContents.swaggerhubApi'] to include table of contents and SwaggerHub API details"),
21
+ page: z
22
+ .number()
23
+ .optional()
24
+ .describe("Page number for paginated results - specifies which page of results to retrieve (default is 1)"),
25
+ size: z
26
+ .number()
27
+ .optional()
28
+ .describe("Number of items per page for pagination - controls how many results are returned per page (default is 20)"),
29
+ });
30
+ export const GetTableOfContentsArgsSchema = z.object({
31
+ sectionId: z
32
+ .string()
33
+ .describe("Section ID - unique identifier for the section within the product"),
34
+ embed: z
35
+ .array(z.string())
36
+ .optional()
37
+ .describe("List of related entities to embed in the response - e.g., ['swaggerhubApi'] to include SwaggerHub API details"),
38
+ page: z
39
+ .number()
40
+ .optional()
41
+ .describe("Page number for paginated results - specifies which page of results to retrieve (default is 1)"),
42
+ size: z
43
+ .number()
44
+ .optional()
45
+ .describe("Number of items per page for pagination - controls how many results are returned per page (default is 20)"),
46
+ });
47
+ export const CreateTableOfContentsArgsSchema = z.object({
48
+ sectionId: z
49
+ .string()
50
+ .describe("Section ID - unique identifier for the section within the product"),
51
+ type: z
52
+ .enum(["new", "copy"])
53
+ .describe("Type of table of contents creation - 'new' to create from scratch or 'copy' to duplicate an existing one"),
54
+ title: z
55
+ .string()
56
+ .describe("Title of the table of contents item - will be displayed in navigation (3-40 characters)"),
57
+ slug: z
58
+ .string()
59
+ .describe("URL-friendly identifier for the table of contents item - must be unique within the section (3-22 characters, lowercase, alphanumeric with hyphens/underscores/dots)"),
60
+ order: z
61
+ .number()
62
+ .describe("Order position of the table of contents item within its parent section or item"),
63
+ parentId: z
64
+ .string()
65
+ .nullable()
66
+ .optional()
67
+ .describe("Parent table of contents item ID - null for top-level items, or ID of parent item for nested structure"),
68
+ content: z
69
+ .object({
70
+ type: z
71
+ .enum(["apiUrl", "html", "markdown"])
72
+ .describe("Content type - 'apiUrl' for API references, 'html' for HTML content, or 'markdown' for Markdown content"),
73
+ url: z
74
+ .string()
75
+ .optional()
76
+ .describe("URL for API reference content (required when type is 'apiUrl')"),
77
+ apiSpec: z
78
+ .string()
79
+ .nullable()
80
+ .optional()
81
+ .describe("API specification format for API URL content"),
82
+ documentId: z
83
+ .string()
84
+ .nullable()
85
+ .optional()
86
+ .describe("Document ID for HTML or Markdown content"),
87
+ })
88
+ .optional()
89
+ .describe("Content configuration for the table of contents item")
90
+ .refine((content) => {
91
+ if (content?.type === "apiUrl") {
92
+ return content.url?.endsWith("/swagger.json");
93
+ }
94
+ return true;
95
+ }, {
96
+ message: "URL must end with '/swagger.json' when content type is 'apiUrl'",
97
+ path: ["url"],
98
+ }),
99
+ });
13
100
  export const CreatePortalArgsSchema = z.object({
14
101
  name: z
15
102
  .string()
@@ -129,3 +216,42 @@ export const UpdateProductArgsSchema = ProductArgsSchema.extend({
129
216
  .optional()
130
217
  .describe("Change navigation visibility - true hides from portal landing page menus while keeping the product accessible via direct links"),
131
218
  });
219
+ export const PublishProductArgsSchema = ProductArgsSchema.extend({
220
+ preview: z
221
+ .boolean()
222
+ .optional()
223
+ .default(false)
224
+ .describe("Whether to publish as preview (true) or live (false). Preview allows testing before going live. Defaults to false (live publication)"),
225
+ });
226
+ // Document management schemas
227
+ export const GetDocumentArgsSchema = z.object({
228
+ documentId: z
229
+ .string()
230
+ .describe("Document UUID - unique identifier for the document"),
231
+ });
232
+ export const UpdateDocumentArgsSchema = z.object({
233
+ documentId: z
234
+ .string()
235
+ .describe("Document UUID - unique identifier for the document"),
236
+ content: z
237
+ .string()
238
+ .describe("The document content to update (HTML or Markdown based on document type)"),
239
+ type: z
240
+ .enum(["html", "markdown"])
241
+ .optional()
242
+ .describe("Content type - 'html' for HTML content or 'markdown' for Markdown content"),
243
+ });
244
+ export const DeleteDocumentArgsSchema = z.object({
245
+ documentId: z
246
+ .string()
247
+ .describe("Document UUID - unique identifier for the document to delete"),
248
+ });
249
+ export const DeleteTableOfContentsArgsSchema = z.object({
250
+ tableOfContentsId: z
251
+ .string()
252
+ .describe("The table of contents UUID, or identifier in the format 'portal-subdomain:product-slug:section-slug:table-of-contents-slug'"),
253
+ recursive: z
254
+ .boolean()
255
+ .optional()
256
+ .describe("Flag to include all the nested tables of contents (default: false)"),
257
+ });
@@ -5,8 +5,9 @@
5
5
  * Each tool includes parameters, descriptions, and handler method names.
6
6
  * This follows the pattern established in the pactflow module.
7
7
  */
8
- import { CreatePortalArgsSchema, CreateProductArgsSchema, PortalArgsSchema, ProductArgsSchema, UpdatePortalArgsSchema, UpdateProductArgsSchema, } from "./portal-types.js";
8
+ import { CreatePortalArgsSchema, CreateProductArgsSchema, CreateTableOfContentsArgsSchema, DeleteDocumentArgsSchema, DeleteTableOfContentsArgsSchema, GetDocumentArgsSchema, GetProductSectionsArgsSchema, GetTableOfContentsArgsSchema, PortalArgsSchema, ProductArgsSchema, PublishProductArgsSchema, UpdateDocumentArgsSchema, UpdatePortalArgsSchema, UpdateProductArgsSchema, } from "./portal-types.js";
9
9
  import { ApiDefinitionParamsSchema, ApiSearchParamsSchema, CreateApiFromTemplateParamsSchema, CreateApiParamsSchema, ScanStandardizationParamsSchema, } from "./registry-types.js";
10
+ import { OrganizationsQuerySchema } from "./user-management-types.js";
10
11
  export const TOOLS = [
11
12
  {
12
13
  title: "List Portals",
@@ -17,88 +18,144 @@ export const TOOLS = [
17
18
  {
18
19
  title: "Create Portal",
19
20
  summary: "Create a new portal within API Hub.",
20
- zodSchema: CreatePortalArgsSchema,
21
+ inputSchema: CreatePortalArgsSchema,
21
22
  handler: "createPortal",
22
23
  },
23
24
  {
24
25
  title: "Get Portal",
25
26
  summary: "Retrieve information about a specific portal.",
26
- zodSchema: PortalArgsSchema,
27
+ inputSchema: PortalArgsSchema,
27
28
  handler: "getPortal",
28
29
  },
29
30
  {
30
31
  title: "Delete Portal",
31
32
  summary: "Delete a specific portal.",
32
- zodSchema: PortalArgsSchema,
33
+ inputSchema: PortalArgsSchema,
33
34
  handler: "deletePortal",
34
35
  formatResponse: () => "Portal deleted successfully.",
35
36
  },
36
37
  {
37
38
  title: "Update Portal",
38
39
  summary: "Update a specific portal's configuration.",
39
- zodSchema: UpdatePortalArgsSchema,
40
+ inputSchema: UpdatePortalArgsSchema,
40
41
  handler: "updatePortal",
41
42
  },
42
43
  {
43
44
  title: "List Portal Products",
44
45
  summary: "Get products for a specific portal that match your criteria.",
45
- zodSchema: PortalArgsSchema,
46
+ inputSchema: PortalArgsSchema,
46
47
  handler: "getPortalProducts",
47
48
  },
48
49
  {
49
50
  title: "Create Portal Product",
50
51
  summary: "Create a new product for a specific portal.",
51
- zodSchema: CreateProductArgsSchema,
52
+ inputSchema: CreateProductArgsSchema,
52
53
  handler: "createPortalProduct",
53
54
  },
54
55
  {
55
56
  title: "Get Portal Product",
56
57
  summary: "Retrieve information about a specific product resource.",
57
- zodSchema: ProductArgsSchema,
58
+ inputSchema: ProductArgsSchema,
58
59
  handler: "getPortalProduct",
59
60
  },
60
61
  {
61
62
  title: "Delete Portal Product",
62
63
  summary: "Delete a product from a specific portal",
63
- zodSchema: ProductArgsSchema,
64
+ inputSchema: ProductArgsSchema,
64
65
  handler: "deletePortalProduct",
65
66
  formatResponse: () => "Product deleted successfully.",
66
67
  },
67
68
  {
68
69
  title: "Update Portal Product",
69
70
  summary: "Update a product's settings within a specific portal.",
70
- zodSchema: UpdateProductArgsSchema,
71
+ inputSchema: UpdateProductArgsSchema,
71
72
  handler: "updatePortalProduct",
72
73
  },
74
+ {
75
+ title: "Publish Portal Product",
76
+ summary: "Publish a product's content to make it live or as preview. This endpoint publishes the current content of a product, making it visible to portal visitors. Use preview mode to test before going live.",
77
+ inputSchema: PublishProductArgsSchema,
78
+ handler: "publishPortalProduct",
79
+ },
80
+ {
81
+ title: "List Portal Product Sections",
82
+ summary: "Get sections for a specific product within a portal.",
83
+ inputSchema: GetProductSectionsArgsSchema,
84
+ handler: "getPortalProductSections",
85
+ },
86
+ {
87
+ title: "Create Table Of Contents",
88
+ summary: "Create a new table of contents item in a portal product section. Supports API references, HTML content, and Markdown content types.",
89
+ inputSchema: CreateTableOfContentsArgsSchema,
90
+ handler: "createTableOfContents",
91
+ },
92
+ {
93
+ title: "List Table Of Contents",
94
+ summary: "Get table of contents for a section of a product within a portal.",
95
+ inputSchema: GetTableOfContentsArgsSchema,
96
+ handler: "getTableOfContents",
97
+ },
98
+ {
99
+ title: "Delete Table Of Contents",
100
+ summary: "Delete table of contents entry. Performs a soft-delete of an entry from the table of contents. Supports recursive deletion of nested items.",
101
+ inputSchema: DeleteTableOfContentsArgsSchema,
102
+ handler: "deleteTableOfContents",
103
+ },
104
+ // Document management tools
105
+ {
106
+ title: "Get Document",
107
+ summary: "Get document content and metadata by document ID. Useful for retrieving HTML or Markdown content from table of contents items.",
108
+ inputSchema: GetDocumentArgsSchema,
109
+ handler: "getDocument",
110
+ },
111
+ {
112
+ title: "Update Document",
113
+ summary: "Update the content of an existing document. Supports both HTML and Markdown content types.",
114
+ inputSchema: UpdateDocumentArgsSchema,
115
+ handler: "updateDocument",
116
+ },
117
+ {
118
+ title: "Delete Document",
119
+ summary: "Delete a document by its ID. This will permanently remove the document content.",
120
+ inputSchema: DeleteDocumentArgsSchema,
121
+ handler: "deleteDocument",
122
+ },
73
123
  // Registry API tools for SwaggerHub Design functionality
74
124
  {
75
125
  title: "Search APIs and Domains",
76
126
  summary: "Search for APIs and Domains in SwaggerHub Registry using the comprehensive /specs endpoint and retrieve metadata including owner, name, description, summary, version, and specification.",
77
- zodSchema: ApiSearchParamsSchema,
127
+ inputSchema: ApiSearchParamsSchema,
78
128
  handler: "searchApis",
79
129
  },
80
130
  {
81
131
  title: "Get API Definition",
82
132
  summary: "Fetch resolved API definition from SwaggerHub Registry based on owner, API name, and version.",
83
- zodSchema: ApiDefinitionParamsSchema,
133
+ inputSchema: ApiDefinitionParamsSchema,
84
134
  handler: "getApiDefinition",
85
135
  },
86
136
  {
87
137
  title: "Create or Update API",
88
138
  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,
139
+ inputSchema: CreateApiParamsSchema,
90
140
  handler: "createOrUpdateApi",
91
141
  },
92
142
  {
93
143
  title: "Create API from Template",
94
144
  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,
145
+ inputSchema: CreateApiFromTemplateParamsSchema,
96
146
  handler: "createApiFromTemplate",
97
147
  },
148
+ // User Management API tools for organization management functionality
149
+ {
150
+ title: "List Organizations",
151
+ summary: "Get organizations for a user. Returns a list of organizations that the authenticating user is a member of. On-Premise admin gets a list of all organizations in the system.",
152
+ inputSchema: OrganizationsQuerySchema,
153
+ handler: "getOrganizations",
154
+ },
98
155
  {
99
156
  title: "Scan API Standardization",
100
157
  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,
158
+ inputSchema: ScanStandardizationParamsSchema,
102
159
  handler: "scanStandardization",
103
160
  },
104
161
  ];
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ // Query parameters for getting organizations
3
+ export const OrganizationsQuerySchema = z.object({
4
+ q: z
5
+ .string()
6
+ .optional()
7
+ .describe("Search organizations by partial or full name (case-insensitive)"),
8
+ sortBy: z
9
+ .enum(["NAME", "EMAIL"])
10
+ .optional()
11
+ .describe("The property to sort the results by"),
12
+ order: z.enum(["ASC", "DESC"]).optional().describe("Sort order"),
13
+ page: z
14
+ .number()
15
+ .min(0)
16
+ .optional()
17
+ .describe("0-based index of the page to return"),
18
+ pageSize: z
19
+ .number()
20
+ .min(1)
21
+ .max(1000)
22
+ .optional()
23
+ .describe("Number of results per page to return"),
24
+ });