@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
package/dist/bugsnag/client.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import NodeCache from "node-cache";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { Configuration, CurrentUserAPI, ErrorAPI } from "./client/index.js";
|
|
4
|
+
import { ToolError, } from "../common/types.js";
|
|
5
|
+
import { Configuration, CurrentUserAPI, ErrorAPI, ProjectAPI, } from "./client/api/index.js";
|
|
6
|
+
import { FilterObjectSchema, toUrlSearchParams, } from "./client/filters.js";
|
|
8
7
|
const HUB_PREFIX = "00000";
|
|
9
8
|
const DEFAULT_DOMAIN = "bugsnag.com";
|
|
10
9
|
const HUB_DOMAIN = "bugsnag.smartbear.com";
|
|
@@ -13,9 +12,6 @@ const cacheKeys = {
|
|
|
13
12
|
PROJECTS: "bugsnag_projects",
|
|
14
13
|
CURRENT_PROJECT: "bugsnag_current_project",
|
|
15
14
|
CURRENT_PROJECT_EVENT_FILTERS: "bugsnag_current_project_event_filters",
|
|
16
|
-
BUILD: "bugsnag_build", // + buildId
|
|
17
|
-
RELEASE: "bugsnag_release", // + releaseId
|
|
18
|
-
BUILDS_IN_RELEASE: "bugsnag_builds_in_release", // + releaseId
|
|
19
15
|
};
|
|
20
16
|
// Exclude certain event fields from the project event filters to improve agent usage
|
|
21
17
|
const EXCLUDED_EVENT_FIELDS = new Set([
|
|
@@ -43,7 +39,7 @@ export class BugsnagClient {
|
|
|
43
39
|
this.apiEndpoint = this.getEndpoint("api", projectApiKey, endpoint);
|
|
44
40
|
this.appEndpoint = this.getEndpoint("app", projectApiKey, endpoint);
|
|
45
41
|
const config = new Configuration({
|
|
46
|
-
|
|
42
|
+
apiKey: `token ${token}`,
|
|
47
43
|
headers: {
|
|
48
44
|
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
|
|
49
45
|
"Content-Type": "application/json",
|
|
@@ -125,15 +121,15 @@ export class BugsnagClient {
|
|
|
125
121
|
async getDashboardUrl(project) {
|
|
126
122
|
return `${this.appEndpoint}/${(await this.getOrganization()).slug}/${project.slug}`;
|
|
127
123
|
}
|
|
128
|
-
async getErrorUrl(project, errorId, queryString
|
|
124
|
+
async getErrorUrl(project, errorId, queryString) {
|
|
129
125
|
const dashboardUrl = await this.getDashboardUrl(project);
|
|
130
|
-
return `${dashboardUrl}/errors/${errorId}${queryString}`;
|
|
126
|
+
return `${dashboardUrl}/errors/${errorId}${queryString ? `?${queryString}` : ""}`;
|
|
131
127
|
}
|
|
132
128
|
async getOrganization() {
|
|
133
129
|
let org = this.cache.get(cacheKeys.ORG);
|
|
134
130
|
if (!org) {
|
|
135
131
|
const response = await this.currentUserApi.listUserOrganizations();
|
|
136
|
-
const orgs = response.body
|
|
132
|
+
const orgs = response.body;
|
|
137
133
|
if (!orgs || orgs.length === 0) {
|
|
138
134
|
throw new Error("No organizations found for the current user.");
|
|
139
135
|
}
|
|
@@ -151,7 +147,7 @@ export class BugsnagClient {
|
|
|
151
147
|
if (!projects) {
|
|
152
148
|
const org = await this.getOrganization();
|
|
153
149
|
const response = await this.currentUserApi.getOrganizationProjects(org.id);
|
|
154
|
-
projects = response.body
|
|
150
|
+
projects = response.body;
|
|
155
151
|
this.cache.set(cacheKeys.PROJECTS, projects);
|
|
156
152
|
}
|
|
157
153
|
return projects;
|
|
@@ -164,9 +160,10 @@ export class BugsnagClient {
|
|
|
164
160
|
let project = this.cache.get(cacheKeys.CURRENT_PROJECT) ?? null;
|
|
165
161
|
if (!project && this.projectApiKey) {
|
|
166
162
|
const projects = await this.getProjects();
|
|
167
|
-
project =
|
|
163
|
+
project =
|
|
164
|
+
projects.find((p) => p.apiKey === this.projectApiKey) ?? null;
|
|
168
165
|
if (!project) {
|
|
169
|
-
throw new
|
|
166
|
+
throw new ToolError("Unable to find project with the configured API key.");
|
|
170
167
|
}
|
|
171
168
|
this.cache.set(cacheKeys.CURRENT_PROJECT, project);
|
|
172
169
|
if (project) {
|
|
@@ -178,9 +175,9 @@ export class BugsnagClient {
|
|
|
178
175
|
async getProjectEventFilters(project) {
|
|
179
176
|
let filtersResponse = (await this.projectApi.listProjectEventFields(project.id)).body;
|
|
180
177
|
if (!filtersResponse || filtersResponse.length === 0) {
|
|
181
|
-
throw new
|
|
178
|
+
throw new ToolError(`No event fields found for project ${project.name}.`);
|
|
182
179
|
}
|
|
183
|
-
filtersResponse = filtersResponse.filter((field) => !EXCLUDED_EVENT_FIELDS.has(field.
|
|
180
|
+
filtersResponse = filtersResponse.filter((field) => field.displayId && !EXCLUDED_EVENT_FIELDS.has(field.displayId));
|
|
184
181
|
return filtersResponse;
|
|
185
182
|
}
|
|
186
183
|
async getEvent(eventId, projectId) {
|
|
@@ -190,108 +187,48 @@ export class BugsnagClient {
|
|
|
190
187
|
const projectEvents = await Promise.all(projectIds.map((projectId) => this.errorsApi.viewEventById(projectId, eventId).catch((_e) => null)));
|
|
191
188
|
return projectEvents.find((event) => event && !!event.body)?.body || null;
|
|
192
189
|
}
|
|
193
|
-
async updateError(projectId, errorId, operation, options) {
|
|
194
|
-
const errorUpdateRequest = {
|
|
195
|
-
operation: operation,
|
|
196
|
-
...options,
|
|
197
|
-
};
|
|
198
|
-
const response = await this.errorsApi.updateErrorOnProject(projectId, errorId, errorUpdateRequest);
|
|
199
|
-
return response.status === 200 || response.status === 204;
|
|
200
|
-
}
|
|
201
190
|
async getInputProject(projectId) {
|
|
202
191
|
if (typeof projectId === "string") {
|
|
203
192
|
const maybeProject = await this.getProject(projectId);
|
|
204
193
|
if (!maybeProject) {
|
|
205
|
-
throw new
|
|
194
|
+
throw new ToolError(`Project with ID ${projectId} not found.`);
|
|
206
195
|
}
|
|
207
196
|
return maybeProject;
|
|
208
197
|
}
|
|
209
198
|
else {
|
|
210
199
|
const currentProject = await this.getCurrentProject();
|
|
211
200
|
if (!currentProject) {
|
|
212
|
-
throw new
|
|
201
|
+
throw new ToolError("No current project found. Please provide a projectId or configure a project API key.");
|
|
213
202
|
}
|
|
214
203
|
return currentProject;
|
|
215
204
|
}
|
|
216
205
|
}
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
222
|
-
const formattedBuilds = fetchedBuilds.map((b) => this.addStabilityData(b, stabilityTargets));
|
|
223
|
-
return { builds: formattedBuilds, nextUrl };
|
|
224
|
-
}
|
|
225
|
-
async getBuild(projectId, buildId) {
|
|
226
|
-
const cacheKey = `${cacheKeys.BUILD}_${buildId}`;
|
|
227
|
-
const build = this.cache.get(cacheKey);
|
|
228
|
-
if (build)
|
|
229
|
-
return build;
|
|
230
|
-
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId))
|
|
231
|
-
.body;
|
|
232
|
-
if (!fetchedBuild)
|
|
233
|
-
throw new Error(`No build for ${buildId} found.`);
|
|
234
|
-
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
235
|
-
const formattedBuild = this.addStabilityData(fetchedBuild, stabilityTargets);
|
|
236
|
-
this.cache.set(cacheKey, formattedBuild, 5 * 60);
|
|
237
|
-
return formattedBuild;
|
|
238
|
-
}
|
|
239
|
-
async listReleases(projectId, opts) {
|
|
240
|
-
const response = await this.projectApi.listReleases(projectId, opts);
|
|
241
|
-
const fetchedReleases = response.body || [];
|
|
242
|
-
const nextUrl = getNextUrlPathFromHeader(response.headers, this.apiEndpoint);
|
|
243
|
-
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
244
|
-
const formattedReleases = fetchedReleases.map((r) => this.addStabilityData(r, stabilityTargets));
|
|
245
|
-
return { releases: formattedReleases, nextUrl };
|
|
246
|
-
}
|
|
247
|
-
async getRelease(projectId, releaseId) {
|
|
248
|
-
const cacheKey = `${cacheKeys.RELEASE}_${releaseId}`;
|
|
249
|
-
const release = this.cache.get(cacheKey);
|
|
250
|
-
if (release)
|
|
251
|
-
return release;
|
|
252
|
-
const fetchedRelease = (await this.projectApi.getRelease(releaseId)).body;
|
|
253
|
-
if (!fetchedRelease)
|
|
254
|
-
throw new Error(`No release for ${releaseId} found.`);
|
|
255
|
-
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
256
|
-
const formattedRelease = this.addStabilityData(fetchedRelease, stabilityTargets);
|
|
257
|
-
this.cache.set(cacheKey, formattedRelease, 5 * 60);
|
|
258
|
-
return formattedRelease;
|
|
259
|
-
}
|
|
260
|
-
async listBuildsInRelease(releaseId) {
|
|
261
|
-
const cacheKey = `${cacheKeys.BUILDS_IN_RELEASE}_${releaseId}`;
|
|
262
|
-
const builds = this.cache.get(cacheKey);
|
|
263
|
-
if (builds)
|
|
264
|
-
return builds;
|
|
265
|
-
const fetchedBuilds = (await this.projectApi.listBuildsInRelease(releaseId)).body || [];
|
|
266
|
-
this.cache.set(cacheKey, fetchedBuilds, 5 * 60);
|
|
267
|
-
return fetchedBuilds;
|
|
268
|
-
}
|
|
269
|
-
async getProjectStabilityTargets(projectId) {
|
|
270
|
-
return await this.projectApi.getProjectStabilityTargets(projectId);
|
|
271
|
-
}
|
|
272
|
-
addStabilityData(source, stabilityTargets) {
|
|
273
|
-
const { stability_target_type, target_stability, critical_stability } = stabilityTargets;
|
|
274
|
-
const user_stability = source.accumulative_daily_users_seen === 0 // avoid division by zero
|
|
206
|
+
addStabilityData(source, project) {
|
|
207
|
+
const accumulativeDailyUsersSeen = source.accumulativeDailyUsersSeen || 0;
|
|
208
|
+
const accumulativeDailyUsersWithUnhandled = source.accumulativeDailyUsersWithUnhandled || 0;
|
|
209
|
+
const userStability = accumulativeDailyUsersSeen === 0 // avoid division by zero
|
|
275
210
|
? 0
|
|
276
|
-
: (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const
|
|
211
|
+
: (accumulativeDailyUsersSeen - accumulativeDailyUsersWithUnhandled) /
|
|
212
|
+
accumulativeDailyUsersSeen;
|
|
213
|
+
const totalSessionsCount = source.totalSessionsCount || 0;
|
|
214
|
+
const unhandledSessionsCount = source.unhandledSessionsCount || 0;
|
|
215
|
+
const sessionStability = totalSessionsCount === 0 // avoid division by zero
|
|
280
216
|
? 0
|
|
281
|
-
: (
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
const
|
|
217
|
+
: (totalSessionsCount - unhandledSessionsCount) / totalSessionsCount;
|
|
218
|
+
const stabilityMetric = project.stabilityTargetType === "user" ? userStability : sessionStability;
|
|
219
|
+
const targetStability = project.targetStability?.value || 0;
|
|
220
|
+
const criticalStability = project.criticalStability?.value || 0;
|
|
221
|
+
const meetsTargetStability = stabilityMetric >= targetStability;
|
|
222
|
+
const meetsCriticalStability = stabilityMetric >= criticalStability;
|
|
286
223
|
return {
|
|
287
224
|
...source,
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
225
|
+
userStability,
|
|
226
|
+
sessionStability,
|
|
227
|
+
stabilityTargetType: project.stabilityTargetType || "user",
|
|
228
|
+
targetStability,
|
|
229
|
+
criticalStability,
|
|
230
|
+
meetsTargetStability,
|
|
231
|
+
meetsCriticalStability,
|
|
295
232
|
};
|
|
296
233
|
}
|
|
297
234
|
registerTools(register, getInput) {
|
|
@@ -307,7 +244,7 @@ export class BugsnagClient {
|
|
|
307
244
|
],
|
|
308
245
|
parameters: [
|
|
309
246
|
{
|
|
310
|
-
name: "
|
|
247
|
+
name: "pageSize",
|
|
311
248
|
type: z.number(),
|
|
312
249
|
description: "Number of projects to return per page for pagination",
|
|
313
250
|
required: false,
|
|
@@ -325,7 +262,7 @@ export class BugsnagClient {
|
|
|
325
262
|
{
|
|
326
263
|
description: "Get first 10 projects",
|
|
327
264
|
parameters: {
|
|
328
|
-
|
|
265
|
+
pageSize: 10,
|
|
329
266
|
page: 1,
|
|
330
267
|
},
|
|
331
268
|
expectedOutput: "JSON array of project objects with IDs, names, and metadata",
|
|
@@ -347,8 +284,8 @@ export class BugsnagClient {
|
|
|
347
284
|
content: [{ type: "text", text: "No projects found." }],
|
|
348
285
|
};
|
|
349
286
|
}
|
|
350
|
-
if (args.
|
|
351
|
-
const pageSize = args.
|
|
287
|
+
if (args.pageSize || args.page) {
|
|
288
|
+
const pageSize = args.pageSize || 10;
|
|
352
289
|
const page = args.page || 1;
|
|
353
290
|
projects = projects.slice((page - 1) * pageSize, page * pageSize);
|
|
354
291
|
}
|
|
@@ -430,30 +367,22 @@ export class BugsnagClient {
|
|
|
430
367
|
}, async (args, _extra) => {
|
|
431
368
|
const project = await this.getInputProject(args.projectId);
|
|
432
369
|
if (!args.errorId)
|
|
433
|
-
throw new
|
|
370
|
+
throw new ToolError("Both projectId and errorId arguments are required");
|
|
434
371
|
const errorDetails = (await this.errorsApi.viewErrorOnProject(project.id, args.errorId)).body;
|
|
435
372
|
if (!errorDetails) {
|
|
436
|
-
throw new
|
|
373
|
+
throw new ToolError(`Error with ID ${args.errorId} not found in project ${project.id}.`);
|
|
437
374
|
}
|
|
438
|
-
// Build query parameters
|
|
439
|
-
const params = new URLSearchParams();
|
|
440
|
-
// Add sorting and pagination parameters to get the latest event
|
|
441
|
-
params.append("sort", "timestamp");
|
|
442
|
-
params.append("direction", "desc");
|
|
443
|
-
params.append("per_page", "1");
|
|
444
|
-
params.append("full_reports", "true");
|
|
445
375
|
const filters = {
|
|
446
376
|
error: [{ type: "eq", value: args.errorId }],
|
|
447
377
|
...args.filters,
|
|
448
378
|
};
|
|
449
|
-
const filtersQueryString = toQueryString(filters);
|
|
450
|
-
const listEventsQueryString = `?${params}&${filtersQueryString}`;
|
|
451
379
|
// Get the latest event for this error using the events endpoint with filters
|
|
452
380
|
let latestEvent = null;
|
|
453
381
|
try {
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
382
|
+
const latestEvents = (await this.errorsApi.listEventsOnProject(project.id, null, "timestamp", "desc", 1, filters, true)).body;
|
|
383
|
+
if (latestEvents && latestEvents.length > 0) {
|
|
384
|
+
latestEvent = latestEvents[0];
|
|
385
|
+
}
|
|
457
386
|
}
|
|
458
387
|
catch (e) {
|
|
459
388
|
console.warn("Failed to fetch latest event:", e);
|
|
@@ -462,9 +391,8 @@ export class BugsnagClient {
|
|
|
462
391
|
const content = {
|
|
463
392
|
error_details: errorDetails,
|
|
464
393
|
latest_event: latestEvent,
|
|
465
|
-
pivots: (await this.errorsApi.
|
|
466
|
-
|
|
467
|
-
url: await this.getErrorUrl(project, args.errorId, `?${filtersQueryString}`),
|
|
394
|
+
pivots: (await this.errorsApi.getPivotValuesOnAnError(project.id, args.errorId, filters, 5)).body || [],
|
|
395
|
+
url: await this.getErrorUrl(project, args.errorId, toUrlSearchParams(filters).toString()),
|
|
468
396
|
};
|
|
469
397
|
return {
|
|
470
398
|
content: [{ type: "text", text: JSON.stringify(content) }],
|
|
@@ -508,17 +436,17 @@ export class BugsnagClient {
|
|
|
508
436
|
],
|
|
509
437
|
}, async (args, _extra) => {
|
|
510
438
|
if (!args.link)
|
|
511
|
-
throw new
|
|
439
|
+
throw new ToolError("link argument is required");
|
|
512
440
|
const url = new URL(args.link);
|
|
513
441
|
const eventId = url.searchParams.get("event_id");
|
|
514
442
|
const projectSlug = url.pathname.split("/")[2];
|
|
515
443
|
if (!projectSlug || !eventId)
|
|
516
|
-
throw new
|
|
444
|
+
throw new ToolError("Both projectSlug and eventId must be present in the link");
|
|
517
445
|
// get the project id from list of projects
|
|
518
446
|
const projects = await this.getProjects();
|
|
519
447
|
const projectId = projects.find((p) => p.slug === projectSlug)?.id;
|
|
520
448
|
if (!projectId) {
|
|
521
|
-
throw new
|
|
449
|
+
throw new ToolError("Project with the specified slug not found.");
|
|
522
450
|
}
|
|
523
451
|
const response = await this.getEvent(eventId, projectId);
|
|
524
452
|
return {
|
|
@@ -573,15 +501,15 @@ export class BugsnagClient {
|
|
|
573
501
|
examples: ["desc"],
|
|
574
502
|
},
|
|
575
503
|
{
|
|
576
|
-
name: "
|
|
504
|
+
name: "perPage",
|
|
577
505
|
type: z.number().min(1).max(100).default(30),
|
|
578
506
|
description: "How many results to return per page.",
|
|
579
507
|
required: false,
|
|
580
508
|
examples: ["30", "50", "100"],
|
|
581
509
|
},
|
|
582
510
|
{
|
|
583
|
-
name: "
|
|
584
|
-
type: z.string()
|
|
511
|
+
name: "nextUrl",
|
|
512
|
+
type: z.string(),
|
|
585
513
|
description: "URL for retrieving the next page of results. Use the value in the previous response to get the next page when more results are available.",
|
|
586
514
|
required: false,
|
|
587
515
|
examples: [
|
|
@@ -622,17 +550,17 @@ export class BugsnagClient {
|
|
|
622
550
|
},
|
|
623
551
|
sort: "users",
|
|
624
552
|
direction: "desc",
|
|
625
|
-
|
|
553
|
+
perPage: 10,
|
|
626
554
|
},
|
|
627
555
|
expectedOutput: "JSON object with a list of errors in the 'data' field, a count of the current page of results in the 'count' field, and a total count of all results in the 'total' field",
|
|
628
556
|
},
|
|
629
557
|
{
|
|
630
558
|
description: "Get the next 50 results",
|
|
631
559
|
parameters: {
|
|
632
|
-
|
|
633
|
-
|
|
560
|
+
nextUrl: "https://api.bugsnag.com/projects/515fb9337c1074f6fd000003/errors?base=2025-08-29T13%3A11%3A37Z&direction=desc&filters%5Berror.status%5D%5B%5D%5Btype%5D=eq&filters%5Berror.status%5D%5B%5D%5Bvalue%5D=open&offset=10&per_page=10&sort=users",
|
|
561
|
+
perPage: 50,
|
|
634
562
|
},
|
|
635
|
-
expectedOutput: "JSON object with a list of errors
|
|
563
|
+
expectedOutput: "JSON object with a list of errors, with a URL to the next page if more results are available and a total count of all errors matched",
|
|
636
564
|
},
|
|
637
565
|
],
|
|
638
566
|
hints: [
|
|
@@ -642,8 +570,8 @@ export class BugsnagClient {
|
|
|
642
570
|
"Common time filters: event.since (from this time), event.before (until this time)",
|
|
643
571
|
"The 'event.since' filter and 'error.status' filters are always applied and if not specified are set to '30d' and 'open' respectively",
|
|
644
572
|
"There may not be any errors matching the filters - this is not a problem with the tool, in fact it might be a good thing that the user's application had no errors",
|
|
645
|
-
"This tool returns paged results. The '
|
|
646
|
-
"If the output contains a '
|
|
573
|
+
"This tool returns paged results. The 'page_error_count' field indicates the number of results returned in the current page, and the 'total_error_count' field indicates the total number of results across all pages.",
|
|
574
|
+
"If the output contains a 'next_url' value, there are more results available - call this tool again supplying the next URL as a parameter to retrieve the next page.",
|
|
647
575
|
"Do not modify the next URL as this can cause incorrect results. The only other parameter that can be used with 'next' is 'per_page' to control the page size.",
|
|
648
576
|
],
|
|
649
577
|
}, async (args, _extra) => {
|
|
@@ -651,37 +579,24 @@ export class BugsnagClient {
|
|
|
651
579
|
// Validate filter keys against cached event fields
|
|
652
580
|
if (args.filters) {
|
|
653
581
|
const eventFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS) || [];
|
|
654
|
-
const validKeys = new Set(eventFields.map((f) => f.
|
|
582
|
+
const validKeys = new Set(eventFields.map((f) => f.displayId));
|
|
655
583
|
for (const key of Object.keys(args.filters)) {
|
|
656
584
|
if (!validKeys.has(key)) {
|
|
657
|
-
throw new
|
|
585
|
+
throw new ToolError(`Invalid filter key: ${key}`);
|
|
658
586
|
}
|
|
659
587
|
}
|
|
660
588
|
}
|
|
661
|
-
const
|
|
589
|
+
const filters = {
|
|
662
590
|
"event.since": [{ type: "eq", value: "30d" }],
|
|
663
591
|
"error.status": [{ type: "eq", value: "open" }],
|
|
592
|
+
...args.filters,
|
|
664
593
|
};
|
|
665
|
-
const
|
|
666
|
-
filters: { ...defaultFilters, ...args.filters },
|
|
667
|
-
};
|
|
668
|
-
if (args.sort !== undefined)
|
|
669
|
-
options.sort = args.sort;
|
|
670
|
-
if (args.direction !== undefined)
|
|
671
|
-
options.direction = args.direction;
|
|
672
|
-
if (args.per_page !== undefined)
|
|
673
|
-
options.per_page = args.per_page;
|
|
674
|
-
if (args.next !== undefined)
|
|
675
|
-
options.next = args.next;
|
|
676
|
-
const response = await this.errorsApi.listProjectErrors(project.id, options);
|
|
677
|
-
const errors = response.body || [];
|
|
678
|
-
const totalCount = response.headers.get("X-Total-Count");
|
|
679
|
-
const linkHeader = response.headers.get("Link");
|
|
594
|
+
const response = await this.errorsApi.listProjectErrors(project.id, null, args.sort || "last_seen", args.direction || "desc", args.perPage || 30, filters, args.nextUrl);
|
|
680
595
|
const result = {
|
|
681
|
-
data:
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
596
|
+
data: response.body,
|
|
597
|
+
next_url: response.nextUrl ?? undefined,
|
|
598
|
+
data_count: response.body?.length,
|
|
599
|
+
total_count: response.totalCount ?? undefined,
|
|
685
600
|
};
|
|
686
601
|
return {
|
|
687
602
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
@@ -711,7 +626,7 @@ export class BugsnagClient {
|
|
|
711
626
|
}, async (_args, _extra) => {
|
|
712
627
|
const projectFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS);
|
|
713
628
|
if (!projectFields)
|
|
714
|
-
throw new
|
|
629
|
+
throw new ToolError("No event filters found in cache.");
|
|
715
630
|
return {
|
|
716
631
|
content: [{ type: "text", text: JSON.stringify(projectFields) }],
|
|
717
632
|
};
|
|
@@ -790,146 +705,24 @@ export class BugsnagClient {
|
|
|
790
705
|
severity = result.content.severity;
|
|
791
706
|
}
|
|
792
707
|
}
|
|
793
|
-
const result = await this.
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
return {
|
|
797
|
-
content: [
|
|
798
|
-
{ type: "text", text: JSON.stringify({ success: result }) },
|
|
799
|
-
],
|
|
800
|
-
};
|
|
801
|
-
});
|
|
802
|
-
register({
|
|
803
|
-
title: "List Builds",
|
|
804
|
-
summary: "List builds for a project with optional filtering by release stage",
|
|
805
|
-
purpose: "Retrieve a list of build summaries to analyze deployment history and associated errors",
|
|
806
|
-
useCases: [
|
|
807
|
-
"View recent builds to correlate with error spikes",
|
|
808
|
-
"Filter builds by stage (e.g. production, staging) for targeted analysis",
|
|
809
|
-
],
|
|
810
|
-
parameters: [
|
|
811
|
-
...(this.projectApiKey
|
|
812
|
-
? []
|
|
813
|
-
: [
|
|
814
|
-
{
|
|
815
|
-
name: "projectId",
|
|
816
|
-
type: z.string(),
|
|
817
|
-
description: "ID of the project to list builds for",
|
|
818
|
-
required: true,
|
|
819
|
-
},
|
|
820
|
-
]),
|
|
821
|
-
{
|
|
822
|
-
name: "releaseStage",
|
|
823
|
-
type: z.string(),
|
|
824
|
-
description: "Filter builds by this stage (e.g. production, staging)",
|
|
825
|
-
required: false,
|
|
826
|
-
examples: ["production", "staging"],
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
name: "nextUrl",
|
|
830
|
-
type: z.string(),
|
|
831
|
-
description: "URL for retrieving the next page of results. Use the value in the previous response to get the next page when more results are available. If provided, other parameters are ignored.",
|
|
832
|
-
required: false,
|
|
833
|
-
examples: [
|
|
834
|
-
"/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
835
|
-
],
|
|
836
|
-
},
|
|
837
|
-
],
|
|
838
|
-
examples: [
|
|
839
|
-
{
|
|
840
|
-
description: "List all builds for a project",
|
|
841
|
-
parameters: {},
|
|
842
|
-
expectedOutput: "JSON array of build objects with metadata",
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
description: "List production builds for a project",
|
|
846
|
-
parameters: {
|
|
847
|
-
releaseStage: "production",
|
|
848
|
-
},
|
|
849
|
-
expectedOutput: "JSON array of build objects in the production stage",
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
description: "Get the next page of results",
|
|
853
|
-
parameters: {
|
|
854
|
-
nextUrl: "/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
855
|
-
},
|
|
856
|
-
expectedOutput: "JSON array of build objects with metadata from the next page",
|
|
857
|
-
},
|
|
858
|
-
],
|
|
859
|
-
hints: ["For more detailed results use the Get Build tool"],
|
|
860
|
-
readOnly: true,
|
|
861
|
-
idempotent: true,
|
|
862
|
-
outputFormat: "JSON array of build summary objects with metadata",
|
|
863
|
-
}, async (args, _extra) => {
|
|
864
|
-
const project = await this.getInputProject(args.projectId);
|
|
865
|
-
const { builds, nextUrl } = await this.listBuilds(project.id, {
|
|
866
|
-
release_stage: args.releaseStage,
|
|
867
|
-
next_url: args.nextUrl,
|
|
708
|
+
const result = await this.errorsApi.updateErrorOnProject(project.id, errorId, {
|
|
709
|
+
operation: operation,
|
|
710
|
+
severity: severity,
|
|
868
711
|
});
|
|
869
712
|
return {
|
|
870
713
|
content: [
|
|
871
714
|
{
|
|
872
715
|
type: "text",
|
|
873
716
|
text: JSON.stringify({
|
|
874
|
-
|
|
875
|
-
next: nextUrl,
|
|
717
|
+
success: result.status === 200 || result.status === 204,
|
|
876
718
|
}),
|
|
877
719
|
},
|
|
878
720
|
],
|
|
879
721
|
};
|
|
880
722
|
});
|
|
881
|
-
register({
|
|
882
|
-
title: "Get Build",
|
|
883
|
-
summary: "Get more details for a specific build by its ID",
|
|
884
|
-
purpose: "Retrieve detailed information about a build for analysis and debugging",
|
|
885
|
-
useCases: [
|
|
886
|
-
"View build metadata such as version, source control info, and error counts",
|
|
887
|
-
"Analyze a specific build to correlate with error spikes or deployments",
|
|
888
|
-
"See the stability targets for a project and if the build meets them",
|
|
889
|
-
],
|
|
890
|
-
parameters: [
|
|
891
|
-
...(this.projectApiKey
|
|
892
|
-
? []
|
|
893
|
-
: [
|
|
894
|
-
{
|
|
895
|
-
name: "projectId",
|
|
896
|
-
type: z.string(),
|
|
897
|
-
description: "ID of the project containing the build",
|
|
898
|
-
required: true,
|
|
899
|
-
},
|
|
900
|
-
]),
|
|
901
|
-
{
|
|
902
|
-
name: "buildId",
|
|
903
|
-
type: z.string(),
|
|
904
|
-
description: "ID of the build to retrieve",
|
|
905
|
-
required: true,
|
|
906
|
-
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
907
|
-
},
|
|
908
|
-
],
|
|
909
|
-
examples: [
|
|
910
|
-
{
|
|
911
|
-
description: "Get details for a specific build",
|
|
912
|
-
parameters: {
|
|
913
|
-
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
914
|
-
},
|
|
915
|
-
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
916
|
-
},
|
|
917
|
-
],
|
|
918
|
-
hints: ["Build IDs can be found using the List builds tool"],
|
|
919
|
-
readOnly: true,
|
|
920
|
-
idempotent: true,
|
|
921
|
-
outputFormat: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
922
|
-
}, async (args, _extra) => {
|
|
923
|
-
if (!args.buildId)
|
|
924
|
-
throw new Error("buildId argument is required");
|
|
925
|
-
const build = await this.getBuild((await this.getInputProject(args.projectId)).id, args.buildId);
|
|
926
|
-
return {
|
|
927
|
-
content: [{ type: "text", text: JSON.stringify(build) }],
|
|
928
|
-
};
|
|
929
|
-
});
|
|
930
723
|
register({
|
|
931
724
|
title: "List Releases",
|
|
932
|
-
summary: "List releases for a project
|
|
725
|
+
summary: "List releases for a project",
|
|
933
726
|
purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
|
|
934
727
|
useCases: [
|
|
935
728
|
"View recent releases to correlate with error spikes",
|
|
@@ -948,18 +741,25 @@ export class BugsnagClient {
|
|
|
948
741
|
]),
|
|
949
742
|
{
|
|
950
743
|
name: "releaseStage",
|
|
951
|
-
type: z.string(),
|
|
952
|
-
description: "Filter releases by this stage (e.g. production, staging)",
|
|
744
|
+
type: z.string().default("production"),
|
|
745
|
+
description: "Filter releases by this stage (e.g. production, staging), defaults to 'production'",
|
|
953
746
|
required: false,
|
|
954
747
|
examples: ["production", "staging"],
|
|
955
748
|
},
|
|
956
749
|
{
|
|
957
750
|
name: "visibleOnly",
|
|
958
|
-
type: z.boolean().default(
|
|
959
|
-
description: "Whether to only include releases that are marked as visible
|
|
960
|
-
required:
|
|
751
|
+
type: z.boolean().default(false),
|
|
752
|
+
description: "Whether to only include releases that are marked as visible in the dashboard, defaults to false",
|
|
753
|
+
required: false,
|
|
961
754
|
examples: ["true", "false"],
|
|
962
755
|
},
|
|
756
|
+
{
|
|
757
|
+
name: "perPage",
|
|
758
|
+
type: z.number().min(1).max(100).default(30),
|
|
759
|
+
description: "How many results to return per page.",
|
|
760
|
+
required: false,
|
|
761
|
+
examples: ["30", "50", "100"],
|
|
762
|
+
},
|
|
963
763
|
{
|
|
964
764
|
name: "nextUrl",
|
|
965
765
|
type: z.string(),
|
|
@@ -972,16 +772,16 @@ export class BugsnagClient {
|
|
|
972
772
|
],
|
|
973
773
|
examples: [
|
|
974
774
|
{
|
|
975
|
-
description: "List
|
|
775
|
+
description: "List production releases for a project",
|
|
976
776
|
parameters: {},
|
|
977
|
-
expectedOutput: "JSON array of release objects
|
|
777
|
+
expectedOutput: "JSON array of release objects in the production stage",
|
|
978
778
|
},
|
|
979
779
|
{
|
|
980
|
-
description: "List
|
|
780
|
+
description: "List staging releases for a project",
|
|
981
781
|
parameters: {
|
|
982
|
-
releaseStage: "
|
|
782
|
+
releaseStage: "staging",
|
|
983
783
|
},
|
|
984
|
-
expectedOutput: "JSON array of release objects in the
|
|
784
|
+
expectedOutput: "JSON array of release objects in the staging stage",
|
|
985
785
|
},
|
|
986
786
|
{
|
|
987
787
|
description: "Get the next page of results",
|
|
@@ -991,23 +791,31 @@ export class BugsnagClient {
|
|
|
991
791
|
expectedOutput: "JSON array of release objects with metadata from the next page",
|
|
992
792
|
},
|
|
993
793
|
],
|
|
994
|
-
hints: [
|
|
794
|
+
hints: [
|
|
795
|
+
"Use the Get Release tool to get more details on a specific release, including the builds it contains",
|
|
796
|
+
"The release stage defaults to 'production' if not specified",
|
|
797
|
+
"Use visibleOnly to filter out releases that have been marked as hidden in the dashboard",
|
|
798
|
+
],
|
|
995
799
|
readOnly: true,
|
|
996
800
|
idempotent: true,
|
|
997
|
-
outputFormat: "JSON array of release summary objects with metadata",
|
|
801
|
+
outputFormat: "JSON array of release summary objects with metadata, with a URL to the next page if more results are available",
|
|
998
802
|
}, async (args, _extra) => {
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
803
|
+
const project = await this.getInputProject(args.projectId);
|
|
804
|
+
const response = await this.projectApi.listProjectReleaseGroups(project.id, args.releaseStage || "production", false, // Not top-only
|
|
805
|
+
args.visibleOnly || false, args.perPage || 30, args.nextUrl);
|
|
806
|
+
let releases = [];
|
|
807
|
+
if (response.body) {
|
|
808
|
+
releases = response.body.map((r) => this.addStabilityData(r, project));
|
|
809
|
+
}
|
|
1004
810
|
return {
|
|
1005
811
|
content: [
|
|
1006
812
|
{
|
|
1007
813
|
type: "text",
|
|
1008
814
|
text: JSON.stringify({
|
|
1009
|
-
releases,
|
|
1010
|
-
|
|
815
|
+
data: releases,
|
|
816
|
+
next_url: response.nextUrl ?? undefined,
|
|
817
|
+
data_count: releases.length,
|
|
818
|
+
total_count: response.totalCount ?? undefined,
|
|
1011
819
|
}),
|
|
1012
820
|
},
|
|
1013
821
|
],
|
|
@@ -1015,12 +823,12 @@ export class BugsnagClient {
|
|
|
1015
823
|
});
|
|
1016
824
|
register({
|
|
1017
825
|
title: "Get Release",
|
|
1018
|
-
summary: "Get more details for a specific release by its ID",
|
|
826
|
+
summary: "Get more details for a specific release by its ID, including source control information and associated builds",
|
|
1019
827
|
purpose: "Retrieve detailed information about a release for analysis and debugging",
|
|
1020
828
|
useCases: [
|
|
1021
829
|
"View release metadata such as version, source control info, and error counts",
|
|
1022
|
-
"Analyze
|
|
1023
|
-
"See the
|
|
830
|
+
"Analyze the stability data and targets for a release",
|
|
831
|
+
"See the builds that make up the release",
|
|
1024
832
|
],
|
|
1025
833
|
parameters: [
|
|
1026
834
|
...(this.projectApiKey
|
|
@@ -1056,19 +864,39 @@ export class BugsnagClient {
|
|
|
1056
864
|
outputFormat: "JSON object containing release details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
1057
865
|
}, async (args, _extra) => {
|
|
1058
866
|
if (!args.releaseId)
|
|
1059
|
-
throw new
|
|
1060
|
-
const
|
|
867
|
+
throw new ToolError("releaseId argument is required");
|
|
868
|
+
const project = await this.getInputProject(args.projectId);
|
|
869
|
+
const releaseResponse = await this.projectApi.getReleaseGroup(args.releaseId);
|
|
870
|
+
if (!releaseResponse.body)
|
|
871
|
+
throw new ToolError(`No release for ${args.releaseId} found.`);
|
|
872
|
+
const release = this.addStabilityData(releaseResponse.body, project);
|
|
873
|
+
let builds = [];
|
|
874
|
+
if (releaseResponse.body) {
|
|
875
|
+
const buildsResponse = await this.projectApi.listBuildsInRelease(args.releaseId);
|
|
876
|
+
if (buildsResponse.body) {
|
|
877
|
+
builds = buildsResponse.body.map((b) => this.addStabilityData(b, project));
|
|
878
|
+
}
|
|
879
|
+
}
|
|
1061
880
|
return {
|
|
1062
|
-
content: [
|
|
881
|
+
content: [
|
|
882
|
+
{
|
|
883
|
+
type: "text",
|
|
884
|
+
text: JSON.stringify({
|
|
885
|
+
release: release,
|
|
886
|
+
builds: builds,
|
|
887
|
+
}),
|
|
888
|
+
},
|
|
889
|
+
],
|
|
1063
890
|
};
|
|
1064
891
|
});
|
|
1065
892
|
register({
|
|
1066
|
-
title: "
|
|
1067
|
-
summary: "
|
|
1068
|
-
purpose: "Retrieve
|
|
893
|
+
title: "Get Build",
|
|
894
|
+
summary: "Get more details for a specific build by its ID",
|
|
895
|
+
purpose: "Retrieve detailed information about a build for analysis and debugging",
|
|
1069
896
|
useCases: [
|
|
1070
|
-
"View
|
|
1071
|
-
"Analyze
|
|
897
|
+
"View build metadata such as version, source control info, and error counts",
|
|
898
|
+
"Analyze a specific build to correlate with error spikes or deployments",
|
|
899
|
+
"See the stability targets for a project and if the build meets them",
|
|
1072
900
|
],
|
|
1073
901
|
parameters: [
|
|
1074
902
|
...(this.projectApiKey
|
|
@@ -1077,37 +905,41 @@ export class BugsnagClient {
|
|
|
1077
905
|
{
|
|
1078
906
|
name: "projectId",
|
|
1079
907
|
type: z.string(),
|
|
1080
|
-
description: "ID of the project containing the
|
|
908
|
+
description: "ID of the project containing the build",
|
|
1081
909
|
required: true,
|
|
1082
910
|
},
|
|
1083
911
|
]),
|
|
1084
912
|
{
|
|
1085
|
-
name: "
|
|
913
|
+
name: "buildId",
|
|
1086
914
|
type: z.string(),
|
|
1087
|
-
description: "ID of the
|
|
915
|
+
description: "ID of the build to retrieve",
|
|
1088
916
|
required: true,
|
|
1089
917
|
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
1090
918
|
},
|
|
1091
919
|
],
|
|
1092
920
|
examples: [
|
|
1093
921
|
{
|
|
1094
|
-
description: "
|
|
922
|
+
description: "Get details for a specific build",
|
|
1095
923
|
parameters: {
|
|
1096
|
-
|
|
924
|
+
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
1097
925
|
},
|
|
1098
|
-
expectedOutput: "JSON
|
|
926
|
+
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
1099
927
|
},
|
|
1100
928
|
],
|
|
1101
|
-
hints: ["
|
|
929
|
+
hints: ["Build IDs can be found using the List builds tool"],
|
|
1102
930
|
readOnly: true,
|
|
1103
931
|
idempotent: true,
|
|
1104
|
-
outputFormat: "JSON
|
|
932
|
+
outputFormat: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
1105
933
|
}, async (args, _extra) => {
|
|
1106
|
-
if (!args.
|
|
1107
|
-
throw new
|
|
1108
|
-
const
|
|
934
|
+
if (!args.buildId)
|
|
935
|
+
throw new ToolError("buildId argument is required");
|
|
936
|
+
const project = await this.getInputProject(args.projectId);
|
|
937
|
+
const response = await this.projectApi.getProjectReleaseById(project.id, args.buildId);
|
|
938
|
+
if (!response.body)
|
|
939
|
+
throw new ToolError(`No build for ${args.buildId} found.`);
|
|
940
|
+
const build = this.addStabilityData(response.body, project);
|
|
1109
941
|
return {
|
|
1110
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
942
|
+
content: [{ type: "text", text: JSON.stringify(build) }],
|
|
1111
943
|
};
|
|
1112
944
|
});
|
|
1113
945
|
}
|