@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.
- package/README.md +29 -4
- package/dist/api-hub/client/api.js +188 -0
- package/dist/api-hub/client/configuration.js +5 -0
- package/dist/api-hub/client/index.js +1 -0
- package/dist/api-hub/client/portal-types.js +126 -0
- package/dist/api-hub/client/tools.js +72 -15
- package/dist/api-hub/client/user-management-types.js +24 -0
- package/dist/api-hub/client.js +31 -0
- package/dist/bugsnag/client.js +4 -4
- package/dist/collaborator/client.js +364 -0
- package/dist/common/server.js +48 -20
- package/dist/index.js +9 -1
- package/dist/pactflow/client/tools.js +4 -4
- package/dist/qmetry/client/auto-resolve.js +22 -0
- package/dist/qmetry/client/handlers.js +18 -4
- package/dist/qmetry/client/issues.js +98 -1
- package/dist/qmetry/client/project.js +18 -1
- package/dist/qmetry/client/testcase.js +79 -1
- package/dist/qmetry/client/testsuite.js +156 -1
- package/dist/qmetry/client/tools/index.js +17 -0
- package/dist/qmetry/client/tools/issue-tools.js +545 -0
- package/dist/qmetry/client/tools/project-tools.js +348 -0
- package/dist/qmetry/client/tools/requirement-tools.js +530 -0
- package/dist/qmetry/client/tools/testcase-tools.js +526 -0
- package/dist/qmetry/client/tools/testsuite-tools.js +772 -0
- package/dist/qmetry/client/tools/types.js +1 -0
- package/dist/qmetry/client.js +9 -2
- package/dist/qmetry/config/constants.js +14 -0
- package/dist/qmetry/config/rest-endpoints.js +10 -0
- package/dist/qmetry/types/common.js +287 -2
- package/dist/qmetry/types/issues.js +11 -1
- package/dist/qmetry/types/project.js +7 -0
- package/dist/qmetry/types/testcase.js +6 -0
- package/dist/qmetry/types/testsuite.js +19 -1
- package/dist/zephyr/client.js +7 -1
- package/dist/zephyr/common/api-client.js +8 -0
- package/dist/zephyr/common/rest-api-schemas.js +5173 -0
- package/dist/zephyr/tool/project/get-project.js +39 -0
- package/dist/zephyr/tool/project/get-projects.js +7 -13
- package/dist/zephyr/tool/test-cycle/get-test-cycles.js +72 -0
- package/package.json +1 -1
- package/dist/qmetry/client/tools.js +0 -1673
- 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/
|
|
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/),
|
|
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",
|
|
@@ -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
|
-
|
|
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
|
-
|
|
27
|
+
inputSchema: PortalArgsSchema,
|
|
27
28
|
handler: "getPortal",
|
|
28
29
|
},
|
|
29
30
|
{
|
|
30
31
|
title: "Delete Portal",
|
|
31
32
|
summary: "Delete a specific portal.",
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
});
|