@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.
- package/README.md +19 -2
- package/dist/api-hub/client/api.js +198 -23
- package/dist/api-hub/client/registry-types.js +22 -0
- package/dist/api-hub/client/tools.js +19 -1
- package/dist/api-hub/client.js +9 -0
- package/dist/bugsnag/client/api/CurrentUser.js +13 -50
- package/dist/bugsnag/client/api/Error.js +30 -155
- package/dist/bugsnag/client/api/Project.js +56 -124
- package/dist/bugsnag/client/api/api.js +3743 -0
- package/dist/bugsnag/client/api/base.js +107 -32
- package/dist/bugsnag/client/api/configuration.js +26 -0
- package/dist/bugsnag/client/api/index.js +2 -0
- package/dist/bugsnag/client/filters.js +28 -0
- package/dist/bugsnag/client.js +157 -325
- package/dist/common/server.js +29 -4
- package/dist/common/types.js +6 -1
- package/dist/index.js +8 -1
- package/dist/pactflow/client/prompt-utils.js +2 -1
- package/dist/pactflow/client/tools.js +9 -9
- package/dist/pactflow/client/utils.js +5 -4
- package/dist/pactflow/client.js +16 -14
- package/dist/qmetry/client/api/client-api.js +21 -16
- package/dist/qmetry/client/api/error-handler.js +329 -0
- package/dist/qmetry/client/auto-resolve.js +74 -0
- package/dist/qmetry/client/handlers.js +19 -2
- package/dist/qmetry/client/issues.js +26 -0
- package/dist/qmetry/client/project.js +56 -0
- package/dist/qmetry/client/requirement.js +76 -0
- package/dist/qmetry/client/testcase.js +46 -8
- package/dist/qmetry/client/testsuite.js +117 -0
- package/dist/qmetry/client/tools.js +1455 -4
- package/dist/qmetry/client/utils.js +16 -0
- package/dist/qmetry/client.js +19 -16
- package/dist/qmetry/config/constants.js +14 -0
- package/dist/qmetry/config/rest-endpoints.js +20 -0
- package/dist/qmetry/types/common.js +313 -8
- package/dist/qmetry/types/issues.js +6 -0
- package/dist/qmetry/types/project.js +10 -0
- package/dist/qmetry/types/requirements.js +19 -0
- package/dist/qmetry/types/testcase.js +14 -0
- package/dist/qmetry/types/testsuite.js +26 -0
- package/dist/reflect/client.js +7 -6
- package/dist/zephyr/client.js +16 -0
- package/dist/zephyr/common/api-client.js +27 -0
- package/dist/zephyr/common/auth-service.js +15 -0
- package/dist/zephyr/common/types.js +35 -0
- package/dist/zephyr/tool/project/get-projects.js +54 -0
- package/dist/zephyr/tool/zephyr-tool.js +1 -0
- package/package.json +3 -2
- package/dist/bugsnag/client/api/filters.js +0 -167
- package/dist/bugsnag/client/configuration.js +0 -10
- package/dist/bugsnag/client/index.js +0 -2
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApiClient } from "./common/api-client.js";
|
|
2
|
+
import { GetProjects } from "./tool/project/get-projects.js";
|
|
3
|
+
export class ZephyrClient {
|
|
4
|
+
apiClient;
|
|
5
|
+
name = "Zephyr";
|
|
6
|
+
prefix = "zephyr";
|
|
7
|
+
constructor(bearerToken, baseUrl = "https://api.zephyrscale.smartbear.com/v2") {
|
|
8
|
+
this.apiClient = new ApiClient(bearerToken, baseUrl);
|
|
9
|
+
}
|
|
10
|
+
registerTools(register, _getInput) {
|
|
11
|
+
const tools = [new GetProjects(this.apiClient)];
|
|
12
|
+
tools.forEach((tool) => {
|
|
13
|
+
register(tool.specification, tool.handle);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AuthService } from "./auth-service.js";
|
|
2
|
+
export class ApiClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
defaultHeaders;
|
|
5
|
+
constructor(bearerToken, baseUrl) {
|
|
6
|
+
this.baseUrl = baseUrl.trim().replace(/\/$/, "");
|
|
7
|
+
this.defaultHeaders = new AuthService(bearerToken).getAuthHeaders();
|
|
8
|
+
}
|
|
9
|
+
getUrl(endpoint, params) {
|
|
10
|
+
const url = new URL(this.baseUrl + endpoint);
|
|
11
|
+
if (params) {
|
|
12
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
13
|
+
if (value !== undefined) {
|
|
14
|
+
url.searchParams.append(key, String(value));
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return url.toString();
|
|
19
|
+
}
|
|
20
|
+
async get(endpoint, params) {
|
|
21
|
+
const response = await fetch(this.getUrl(endpoint, params), {
|
|
22
|
+
method: "GET",
|
|
23
|
+
headers: this.defaultHeaders,
|
|
24
|
+
});
|
|
25
|
+
return response.json();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../../common/info.js";
|
|
2
|
+
export class AuthService {
|
|
3
|
+
bearerToken;
|
|
4
|
+
constructor(accessToken) {
|
|
5
|
+
this.bearerToken = accessToken.trim();
|
|
6
|
+
}
|
|
7
|
+
getAuthHeaders() {
|
|
8
|
+
return {
|
|
9
|
+
Authorization: `Bearer ${this.bearerToken}`,
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
|
|
12
|
+
"zscale-source": "smartbear-mcp",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const MaxResultsSchema = z
|
|
3
|
+
.number()
|
|
4
|
+
.min(1)
|
|
5
|
+
.max(1000)
|
|
6
|
+
.describe(`
|
|
7
|
+
Specifies the maximum number of results to return in a single call. The default value is 10, and the maximum value that can be requested is 1000.
|
|
8
|
+
|
|
9
|
+
Note that the server may enforce a lower limit than requested, depending on resource availability or other internal constraints.
|
|
10
|
+
If this happens, the result set may be truncated. Always check the maxResults value in the response to confirm how many results were actually returned.
|
|
11
|
+
`);
|
|
12
|
+
export const StartAtSchema = z
|
|
13
|
+
.number()
|
|
14
|
+
.min(0)
|
|
15
|
+
.max(1000000)
|
|
16
|
+
.describe(`
|
|
17
|
+
Zero-indexed starting position used to paginate through results. Defaults to 0.
|
|
18
|
+
`);
|
|
19
|
+
export const ZephyrProjectSchema = z.object({
|
|
20
|
+
id: z.number(),
|
|
21
|
+
jiraProjectId: z.number(),
|
|
22
|
+
key: z.string(),
|
|
23
|
+
enabled: z.boolean(),
|
|
24
|
+
});
|
|
25
|
+
export function createListSchema(itemSchema) {
|
|
26
|
+
return z.object({
|
|
27
|
+
next: z.string().nullable(),
|
|
28
|
+
startAt: StartAtSchema,
|
|
29
|
+
maxResults: MaxResultsSchema,
|
|
30
|
+
total: z.number(),
|
|
31
|
+
isLast: z.boolean(),
|
|
32
|
+
values: z.array(itemSchema),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export const ZephyrProjectListSchema = createListSchema(ZephyrProjectSchema);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { MaxResultsSchema, StartAtSchema } from "../../common/types.js";
|
|
3
|
+
export const GetProjectsInputSchema = z.object({
|
|
4
|
+
startAt: StartAtSchema.optional(),
|
|
5
|
+
maxResults: MaxResultsSchema.optional(),
|
|
6
|
+
});
|
|
7
|
+
export class GetProjects {
|
|
8
|
+
apiClient;
|
|
9
|
+
constructor(apiClient) {
|
|
10
|
+
this.apiClient = apiClient;
|
|
11
|
+
}
|
|
12
|
+
specification = {
|
|
13
|
+
title: "Get Projects",
|
|
14
|
+
summary: "Get details of projects in Zephyr",
|
|
15
|
+
readOnly: true,
|
|
16
|
+
idempotent: true,
|
|
17
|
+
zodSchema: GetProjectsInputSchema,
|
|
18
|
+
examples: [
|
|
19
|
+
{
|
|
20
|
+
description: "Get the first 10 projects",
|
|
21
|
+
parameters: {
|
|
22
|
+
maxResults: 10,
|
|
23
|
+
startAt: 0,
|
|
24
|
+
},
|
|
25
|
+
expectedOutput: "The first 10 projects with their details",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
description: "Get any project",
|
|
29
|
+
parameters: {
|
|
30
|
+
maxResults: 1,
|
|
31
|
+
},
|
|
32
|
+
expectedOutput: "One project with its details",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
description: "Get five projects starting from the 7th project of the list",
|
|
36
|
+
parameters: {
|
|
37
|
+
maxResults: 5,
|
|
38
|
+
startAt: 6,
|
|
39
|
+
},
|
|
40
|
+
expectedOutput: "The 7th to the 11th projects with their details",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
handle = async (args) => {
|
|
45
|
+
const { maxResults, startAt } = args;
|
|
46
|
+
const response = await this.apiClient.get("/projects", {
|
|
47
|
+
maxResults,
|
|
48
|
+
startAt,
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartbear/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "MCP server for interacting SmartBear Products",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"smartbear",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"bugsnag",
|
|
9
9
|
"reflect",
|
|
10
10
|
"api-hub",
|
|
11
|
-
"pactflow"
|
|
11
|
+
"pactflow",
|
|
12
|
+
"zephyr"
|
|
12
13
|
],
|
|
13
14
|
"homepage": "https://developer.smartbear.com/smartbear-mcp",
|
|
14
15
|
"mcpName": "com.smartbear/smartbear-mcp",
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Filters utility for BugSnag API
|
|
3
|
-
*
|
|
4
|
-
* This file provides utility functions for creating filter URL parameters
|
|
5
|
-
* based on the BugSnag filtering specification described in the Filtering.md document.
|
|
6
|
-
*/
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
export const FilterValueSchema = z.object({
|
|
9
|
-
type: z.enum(["eq", "ne", "empty"]),
|
|
10
|
-
value: z.union([z.string(), z.boolean(), z.number()]),
|
|
11
|
-
});
|
|
12
|
-
export const FilterObjectSchema = z.record(z.array(FilterValueSchema));
|
|
13
|
-
/**
|
|
14
|
-
* Creates a filter value object for equality comparison
|
|
15
|
-
*
|
|
16
|
-
* @param value The value to compare against
|
|
17
|
-
* @returns FilterValue with type 'eq'
|
|
18
|
-
*/
|
|
19
|
-
export function equals(value) {
|
|
20
|
-
return {
|
|
21
|
-
type: "eq",
|
|
22
|
-
value,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Creates a filter value object for inequality comparison
|
|
27
|
-
*
|
|
28
|
-
* @param value The value to compare against
|
|
29
|
-
* @returns FilterValue with type 'ne'
|
|
30
|
-
*/
|
|
31
|
-
export function notEquals(value) {
|
|
32
|
-
return {
|
|
33
|
-
type: "ne",
|
|
34
|
-
value,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Creates a filter value object for checking if a field is empty or not
|
|
39
|
-
*
|
|
40
|
-
* @param isEmpty Whether the field should be empty (true) or not (false)
|
|
41
|
-
* @returns FilterValue with type 'empty'
|
|
42
|
-
*/
|
|
43
|
-
export function empty(isEmpty) {
|
|
44
|
-
return {
|
|
45
|
-
type: "empty",
|
|
46
|
-
value: isEmpty.toString(),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Creates a relative time filter for event.since or event.before
|
|
51
|
-
*
|
|
52
|
-
* @param value The amount of time
|
|
53
|
-
* @param unit The time unit ('h' for hours, 'd' for days)
|
|
54
|
-
* @returns FilterValue for the relative time
|
|
55
|
-
*/
|
|
56
|
-
export function relativeTime(value, unit) {
|
|
57
|
-
return {
|
|
58
|
-
type: "eq",
|
|
59
|
-
value: `${value}${unit}`,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Creates an ISO 8601 time filter (must be in UTC format like 2018-05-20T00:00:00Z)
|
|
64
|
-
*
|
|
65
|
-
* @param date The date object to convert to ISO string
|
|
66
|
-
* @returns FilterValue for the ISO time
|
|
67
|
-
*/
|
|
68
|
-
export function isoTime(date) {
|
|
69
|
-
return {
|
|
70
|
-
type: "eq",
|
|
71
|
-
value: date.toISOString(),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Converts a FilterObject to URL search parameters
|
|
76
|
-
*
|
|
77
|
-
* @param filters The filter object to convert
|
|
78
|
-
* @returns URLSearchParams object with the encoded filters
|
|
79
|
-
*/
|
|
80
|
-
export function toUrlSearchParams(filters) {
|
|
81
|
-
const params = new URLSearchParams();
|
|
82
|
-
Object.entries(filters).forEach(([field, filterValues]) => {
|
|
83
|
-
filterValues.forEach((filterValue) => {
|
|
84
|
-
params.append(`filters[${field}][][type]`, filterValue.type);
|
|
85
|
-
params.append(`filters[${field}][][value]`, filterValue.value.toString());
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
return params;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Converts a FilterObject to a query string
|
|
92
|
-
*
|
|
93
|
-
* @param filters The filter object to convert
|
|
94
|
-
* @returns Query string representation of the filters
|
|
95
|
-
*/
|
|
96
|
-
export function toQueryString(filters) {
|
|
97
|
-
return toUrlSearchParams(filters).toString();
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Helper to build a FilterObject with type safety
|
|
101
|
-
*
|
|
102
|
-
* @returns An empty FilterObject that can be built upon
|
|
103
|
-
*/
|
|
104
|
-
export function createFilter() {
|
|
105
|
-
return {};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Adds a field filter to an existing FilterObject
|
|
109
|
-
*
|
|
110
|
-
* @param filters The FilterObject to add to
|
|
111
|
-
* @param field The field name (e.g., 'error.status', 'event.since')
|
|
112
|
-
* @param filterValue The FilterValue to add
|
|
113
|
-
* @returns The updated FilterObject for chaining
|
|
114
|
-
*/
|
|
115
|
-
export function addFilter(filters, field, filterValue) {
|
|
116
|
-
if (!filters[field]) {
|
|
117
|
-
filters[field] = [];
|
|
118
|
-
}
|
|
119
|
-
filters[field].push(filterValue);
|
|
120
|
-
return filters;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Utility to create a time range filter between two dates
|
|
124
|
-
*
|
|
125
|
-
* @param filters The FilterObject to add to
|
|
126
|
-
* @param since Start date
|
|
127
|
-
* @param before End date
|
|
128
|
-
* @returns The updated FilterObject for chaining
|
|
129
|
-
*/
|
|
130
|
-
export function addTimeRange(filters, since, before) {
|
|
131
|
-
addFilter(filters, "event.since", isoTime(since));
|
|
132
|
-
addFilter(filters, "event.before", isoTime(before));
|
|
133
|
-
return filters;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Utility to create a relative time range filter
|
|
137
|
-
*
|
|
138
|
-
* @param filters The FilterObject to add to
|
|
139
|
-
* @param amount The amount of time (e.g., 7 for 7 days)
|
|
140
|
-
* @param unit The time unit ('h' for hours, 'd' for days)
|
|
141
|
-
* @returns The updated FilterObject for chaining
|
|
142
|
-
*/
|
|
143
|
-
export function addRelativeTimeRange(filters, amount, unit) {
|
|
144
|
-
addFilter(filters, "event.since", relativeTime(amount, unit));
|
|
145
|
-
return filters;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Usage examples:
|
|
149
|
-
*
|
|
150
|
-
* // Example 1: Open errors with events in the last day
|
|
151
|
-
* const filters = createFilter();
|
|
152
|
-
* addRelativeTimeRange(filters, 1, 'd');
|
|
153
|
-
* addFilter(filters, 'error.status', equals('open'));
|
|
154
|
-
* const queryString = toQueryString(filters);
|
|
155
|
-
*
|
|
156
|
-
* // Example 2: Events affecting specific users on a specific day
|
|
157
|
-
* const filters = createFilter();
|
|
158
|
-
* addTimeRange(filters, new Date('2017-01-01'), new Date('2017-01-02'));
|
|
159
|
-
* addFilter(filters, 'user.email', equals('user1@example.com'));
|
|
160
|
-
* addFilter(filters, 'user.email', equals('user2@example.com'));
|
|
161
|
-
* const queryString = toQueryString(filters);
|
|
162
|
-
*
|
|
163
|
-
* // Example 3: Events that have user data
|
|
164
|
-
* const filters = createFilter();
|
|
165
|
-
* addFilter(filters, 'user.id', empty(false));
|
|
166
|
-
* const queryString = toQueryString(filters);
|
|
167
|
-
*/
|