@smartbear/mcp 0.6.0 → 0.8.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 +37 -3
- package/dist/api-hub/client/api.js +387 -0
- package/dist/api-hub/client/configuration.js +27 -0
- package/dist/api-hub/client/index.js +5 -0
- package/dist/api-hub/client/portal-types.js +131 -0
- package/dist/api-hub/client/registry-types.js +69 -0
- package/dist/api-hub/client/tools.js +98 -0
- package/dist/api-hub/client.js +70 -404
- package/dist/bugsnag/client/api/CurrentUser.js +19 -13
- package/dist/bugsnag/client/api/Error.js +45 -57
- package/dist/bugsnag/client/api/Project.js +35 -30
- package/dist/bugsnag/client/api/base.js +24 -9
- package/dist/bugsnag/client/api/filters.js +9 -9
- package/dist/bugsnag/client.js +281 -373
- package/dist/common/info.js +1 -1
- package/dist/common/server.js +39 -28
- package/dist/index.js +18 -4
- package/dist/pactflow/client/ai.js +20 -20
- package/dist/pactflow/client/base.js +48 -13
- package/dist/pactflow/client/prompts.js +10 -12
- package/dist/pactflow/client/tools.js +18 -18
- package/dist/pactflow/client/utils.js +1 -1
- package/dist/pactflow/client.js +23 -15
- package/dist/qmetry/client/api/client-api.js +39 -0
- package/dist/qmetry/client/handlers.js +11 -0
- package/dist/qmetry/client/project.js +27 -0
- package/dist/qmetry/client/testcase.js +104 -0
- package/dist/qmetry/client/tools.js +222 -0
- package/dist/qmetry/client.js +95 -0
- package/dist/qmetry/config/constants.js +12 -0
- package/dist/qmetry/config/rest-endpoints.js +11 -0
- package/dist/qmetry/types/common.js +174 -0
- package/dist/qmetry/types/testcase.js +19 -0
- package/dist/reflect/client.js +14 -14
- package/dist/zephyr/client.js +16 -0
- package/dist/zephyr/common/api-client.js +27 -0
- package/dist/zephyr/common/auth-service.js +14 -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 +8 -6
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 { FilterObjectSchema, toQueryString } from "./client/api/filters.js";
|
|
4
|
+
import { FilterObjectSchema, toQueryString, } from "./client/api/filters.js";
|
|
6
5
|
import { ProjectAPI, } from "./client/api/Project.js";
|
|
7
|
-
import {
|
|
6
|
+
import { Configuration, CurrentUserAPI, ErrorAPI } from "./client/index.js";
|
|
8
7
|
const HUB_PREFIX = "00000";
|
|
9
8
|
const DEFAULT_DOMAIN = "bugsnag.com";
|
|
10
9
|
const HUB_DOMAIN = "bugsnag.smartbear.com";
|
|
@@ -13,13 +12,10 @@ 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([
|
|
22
|
-
"search" // This is searches multiple fields and is more a convenience for humans, we're removing to avoid over-matching
|
|
18
|
+
"search", // This is searches multiple fields and is more a convenience for humans, we're removing to avoid over-matching
|
|
23
19
|
]);
|
|
24
20
|
const PERMITTED_UPDATE_OPERATIONS = [
|
|
25
21
|
"override_severity",
|
|
@@ -27,7 +23,7 @@ const PERMITTED_UPDATE_OPERATIONS = [
|
|
|
27
23
|
"fix",
|
|
28
24
|
"ignore",
|
|
29
25
|
"discard",
|
|
30
|
-
"undiscard"
|
|
26
|
+
"undiscard",
|
|
31
27
|
];
|
|
32
28
|
export class BugsnagClient {
|
|
33
29
|
currentUserApi;
|
|
@@ -82,7 +78,7 @@ export class BugsnagClient {
|
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
getHost(apiKey, subdomain) {
|
|
85
|
-
if (apiKey
|
|
81
|
+
if (apiKey?.startsWith(HUB_PREFIX)) {
|
|
86
82
|
return `https://${subdomain}.${HUB_DOMAIN}`;
|
|
87
83
|
}
|
|
88
84
|
else {
|
|
@@ -95,7 +91,7 @@ export class BugsnagClient {
|
|
|
95
91
|
getEndpoint(subdomain, apiKey, endpoint) {
|
|
96
92
|
let subDomainEndpoint;
|
|
97
93
|
if (!endpoint) {
|
|
98
|
-
if (apiKey
|
|
94
|
+
if (apiKey?.startsWith(HUB_PREFIX)) {
|
|
99
95
|
subDomainEndpoint = `https://${subdomain}.${HUB_DOMAIN}`;
|
|
100
96
|
}
|
|
101
97
|
else {
|
|
@@ -105,7 +101,8 @@ export class BugsnagClient {
|
|
|
105
101
|
else {
|
|
106
102
|
// check if the endpoint matches either the HUB_DOMAIN or DEFAULT_DOMAIN
|
|
107
103
|
const url = new URL(endpoint);
|
|
108
|
-
if (url.hostname.endsWith(HUB_DOMAIN) ||
|
|
104
|
+
if (url.hostname.endsWith(HUB_DOMAIN) ||
|
|
105
|
+
url.hostname.endsWith(DEFAULT_DOMAIN)) {
|
|
109
106
|
// For known domains (Hub or Bugsnag), always use HTTPS and standard format
|
|
110
107
|
if (url.hostname.endsWith(HUB_DOMAIN)) {
|
|
111
108
|
subDomainEndpoint = `https://${subdomain}.${HUB_DOMAIN}`;
|
|
@@ -124,7 +121,7 @@ export class BugsnagClient {
|
|
|
124
121
|
async getDashboardUrl(project) {
|
|
125
122
|
return `${this.appEndpoint}/${(await this.getOrganization()).slug}/${project.slug}`;
|
|
126
123
|
}
|
|
127
|
-
async getErrorUrl(project, errorId, queryString =
|
|
124
|
+
async getErrorUrl(project, errorId, queryString = "") {
|
|
128
125
|
const dashboardUrl = await this.getDashboardUrl(project);
|
|
129
126
|
return `${dashboardUrl}/errors/${errorId}${queryString}`;
|
|
130
127
|
}
|
|
@@ -165,7 +162,7 @@ export class BugsnagClient {
|
|
|
165
162
|
const projects = await this.getProjects();
|
|
166
163
|
project = projects.find((p) => p.api_key === this.projectApiKey) ?? null;
|
|
167
164
|
if (!project) {
|
|
168
|
-
throw new Error(
|
|
165
|
+
throw new Error("Unable to find project with the configured API key.");
|
|
169
166
|
}
|
|
170
167
|
this.cache.set(cacheKeys.CURRENT_PROJECT, project);
|
|
171
168
|
if (project) {
|
|
@@ -179,24 +176,26 @@ export class BugsnagClient {
|
|
|
179
176
|
if (!filtersResponse || filtersResponse.length === 0) {
|
|
180
177
|
throw new Error(`No event fields found for project ${project.name}.`);
|
|
181
178
|
}
|
|
182
|
-
filtersResponse = filtersResponse.filter(field => !EXCLUDED_EVENT_FIELDS.has(field.display_id));
|
|
179
|
+
filtersResponse = filtersResponse.filter((field) => !EXCLUDED_EVENT_FIELDS.has(field.display_id));
|
|
183
180
|
return filtersResponse;
|
|
184
181
|
}
|
|
185
182
|
async getEvent(eventId, projectId) {
|
|
186
|
-
const projectIds = projectId
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
const projectIds = projectId
|
|
184
|
+
? [projectId]
|
|
185
|
+
: (await this.getProjects()).map((p) => p.id);
|
|
186
|
+
const projectEvents = await Promise.all(projectIds.map((projectId) => this.errorsApi.viewEventById(projectId, eventId).catch((_e) => null)));
|
|
187
|
+
return projectEvents.find((event) => event && !!event.body)?.body || null;
|
|
189
188
|
}
|
|
190
189
|
async updateError(projectId, errorId, operation, options) {
|
|
191
190
|
const errorUpdateRequest = {
|
|
192
191
|
operation: operation,
|
|
193
|
-
...options
|
|
192
|
+
...options,
|
|
194
193
|
};
|
|
195
194
|
const response = await this.errorsApi.updateErrorOnProject(projectId, errorId, errorUpdateRequest);
|
|
196
195
|
return response.status === 200 || response.status === 204;
|
|
197
196
|
}
|
|
198
197
|
async getInputProject(projectId) {
|
|
199
|
-
if (typeof projectId ===
|
|
198
|
+
if (typeof projectId === "string") {
|
|
200
199
|
const maybeProject = await this.getProject(projectId);
|
|
201
200
|
if (!maybeProject) {
|
|
202
201
|
throw new Error(`Project with ID ${projectId} not found.`);
|
|
@@ -206,84 +205,90 @@ export class BugsnagClient {
|
|
|
206
205
|
else {
|
|
207
206
|
const currentProject = await this.getCurrentProject();
|
|
208
207
|
if (!currentProject) {
|
|
209
|
-
throw new Error(
|
|
208
|
+
throw new Error("No current project found. Please provide a projectId or configure a project API key.");
|
|
210
209
|
}
|
|
211
210
|
return currentProject;
|
|
212
211
|
}
|
|
213
212
|
}
|
|
214
213
|
async listBuilds(projectId, opts) {
|
|
215
214
|
const response = await this.projectApi.listBuilds(projectId, opts);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
215
|
+
if (!response.body || response.body.length === 0) {
|
|
216
|
+
return { ...response, body: [] };
|
|
217
|
+
}
|
|
218
|
+
const project = await this.getProject(projectId);
|
|
219
|
+
if (!project)
|
|
220
|
+
throw new Error(`Project with ID ${projectId} not found.`);
|
|
221
|
+
return {
|
|
222
|
+
...response,
|
|
223
|
+
body: response.body.map((b) => this.addStabilityData(b, project)),
|
|
224
|
+
};
|
|
221
225
|
}
|
|
222
226
|
async getBuild(projectId, buildId) {
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
if (build)
|
|
226
|
-
return build;
|
|
227
|
-
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId)).body;
|
|
228
|
-
if (!fetchedBuild)
|
|
227
|
+
const response = await this.projectApi.getBuild(projectId, buildId);
|
|
228
|
+
if (!response.body)
|
|
229
229
|
throw new Error(`No build for ${buildId} found.`);
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return
|
|
230
|
+
const project = await this.getProject(projectId);
|
|
231
|
+
if (!project)
|
|
232
|
+
throw new Error(`Project with ID ${projectId} not found.`);
|
|
233
|
+
return { ...response, body: this.addStabilityData(response.body, project) };
|
|
234
234
|
}
|
|
235
235
|
async listReleases(projectId, opts) {
|
|
236
236
|
const response = await this.projectApi.listReleases(projectId, opts);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
|
|
237
|
+
if (!response.body || response.body.length === 0) {
|
|
238
|
+
return { ...response, body: [] };
|
|
239
|
+
}
|
|
240
|
+
const project = await this.getProject(projectId);
|
|
241
|
+
if (!project)
|
|
242
|
+
throw new Error(`Project with ID ${projectId} not found.`);
|
|
243
|
+
return {
|
|
244
|
+
...response,
|
|
245
|
+
body: response.body.map((r) => this.addStabilityData(r, project)),
|
|
246
|
+
};
|
|
242
247
|
}
|
|
243
248
|
async getRelease(projectId, releaseId) {
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
if (release)
|
|
247
|
-
return release;
|
|
248
|
-
const fetchedRelease = (await this.projectApi.getRelease(releaseId)).body;
|
|
249
|
-
if (!fetchedRelease)
|
|
249
|
+
const response = await this.projectApi.getRelease(releaseId);
|
|
250
|
+
if (!response.body)
|
|
250
251
|
throw new Error(`No release for ${releaseId} found.`);
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return
|
|
255
|
-
}
|
|
256
|
-
async listBuildsInRelease(releaseId) {
|
|
257
|
-
const cacheKey = `${cacheKeys.BUILDS_IN_RELEASE}_${releaseId}`;
|
|
258
|
-
const builds = this.cache.get(cacheKey);
|
|
259
|
-
if (builds)
|
|
260
|
-
return builds;
|
|
261
|
-
const fetchedBuilds = (await this.projectApi.listBuildsInRelease(releaseId)).body || [];
|
|
262
|
-
this.cache.set(cacheKey, fetchedBuilds, 5 * 60);
|
|
263
|
-
return fetchedBuilds;
|
|
252
|
+
const project = await this.getProject(projectId);
|
|
253
|
+
if (!project)
|
|
254
|
+
throw new Error(`Project with ID ${projectId} not found.`);
|
|
255
|
+
return { ...response, body: this.addStabilityData(response.body, project) };
|
|
264
256
|
}
|
|
265
|
-
async
|
|
266
|
-
|
|
257
|
+
async listBuildsInRelease(projectId, releaseId) {
|
|
258
|
+
const response = await this.projectApi.listBuildsInRelease(releaseId);
|
|
259
|
+
if (!response.body || response.body.length === 0) {
|
|
260
|
+
return { ...response, body: [] };
|
|
261
|
+
}
|
|
262
|
+
const project = await this.getProject(projectId);
|
|
263
|
+
if (!project)
|
|
264
|
+
throw new Error(`Project with ID ${projectId} not found.`);
|
|
265
|
+
return {
|
|
266
|
+
...response,
|
|
267
|
+
body: response.body.map((b) => this.addStabilityData(b, project)),
|
|
268
|
+
};
|
|
267
269
|
}
|
|
268
|
-
addStabilityData(source,
|
|
269
|
-
const { stability_target_type, target_stability, critical_stability } = stabilityTargets;
|
|
270
|
+
addStabilityData(source, project) {
|
|
270
271
|
const user_stability = source.accumulative_daily_users_seen === 0 // avoid division by zero
|
|
271
272
|
? 0
|
|
272
|
-
: (source.accumulative_daily_users_seen -
|
|
273
|
+
: (source.accumulative_daily_users_seen -
|
|
274
|
+
source.accumulative_daily_users_with_unhandled) /
|
|
273
275
|
source.accumulative_daily_users_seen;
|
|
274
276
|
const session_stability = source.total_sessions_count === 0 // avoid division by zero
|
|
275
277
|
? 0
|
|
276
|
-
: (source.total_sessions_count - source.unhandled_sessions_count) /
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
278
|
+
: (source.total_sessions_count - source.unhandled_sessions_count) /
|
|
279
|
+
source.total_sessions_count;
|
|
280
|
+
const stabilityMetric = project.stability_target_type === "user"
|
|
281
|
+
? user_stability
|
|
282
|
+
: session_stability;
|
|
283
|
+
const meets_target_stability = stabilityMetric >= project.target_stability.value;
|
|
284
|
+
const meets_critical_stability = stabilityMetric >= project.critical_stability.value;
|
|
280
285
|
return {
|
|
281
286
|
...source,
|
|
282
287
|
user_stability,
|
|
283
288
|
session_stability,
|
|
284
|
-
stability_target_type,
|
|
285
|
-
target_stability: target_stability.value,
|
|
286
|
-
critical_stability: critical_stability.value,
|
|
289
|
+
stability_target_type: project.stability_target_type,
|
|
290
|
+
target_stability: project.target_stability.value,
|
|
291
|
+
critical_stability: project.critical_stability.value,
|
|
287
292
|
meets_target_stability,
|
|
288
293
|
meets_critical_stability,
|
|
289
294
|
};
|
|
@@ -297,43 +302,43 @@ export class BugsnagClient {
|
|
|
297
302
|
useCases: [
|
|
298
303
|
"Browse available projects when no specific project API key is configured",
|
|
299
304
|
"Find project IDs needed for other tools",
|
|
300
|
-
"Get an overview of all projects in the organization"
|
|
305
|
+
"Get an overview of all projects in the organization",
|
|
301
306
|
],
|
|
302
307
|
parameters: [
|
|
303
308
|
{
|
|
304
|
-
name: "
|
|
309
|
+
name: "pageSize",
|
|
305
310
|
type: z.number(),
|
|
306
311
|
description: "Number of projects to return per page for pagination",
|
|
307
312
|
required: false,
|
|
308
|
-
examples: ["10", "25", "50"]
|
|
313
|
+
examples: ["10", "25", "50"],
|
|
309
314
|
},
|
|
310
315
|
{
|
|
311
316
|
name: "page",
|
|
312
317
|
type: z.number(),
|
|
313
318
|
description: "Page number to return (starts from 1)",
|
|
314
319
|
required: false,
|
|
315
|
-
examples: ["1", "2", "3"]
|
|
316
|
-
}
|
|
320
|
+
examples: ["1", "2", "3"],
|
|
321
|
+
},
|
|
317
322
|
],
|
|
318
323
|
examples: [
|
|
319
324
|
{
|
|
320
325
|
description: "Get first 10 projects",
|
|
321
326
|
parameters: {
|
|
322
|
-
|
|
323
|
-
page: 1
|
|
327
|
+
pageSize: 10,
|
|
328
|
+
page: 1,
|
|
324
329
|
},
|
|
325
330
|
expectedOutput: "JSON array of project objects with IDs, names, and metadata",
|
|
326
331
|
},
|
|
327
332
|
{
|
|
328
333
|
description: "Get all projects (no pagination)",
|
|
329
334
|
parameters: {},
|
|
330
|
-
expectedOutput: "JSON array of all available projects"
|
|
331
|
-
}
|
|
335
|
+
expectedOutput: "JSON array of all available projects",
|
|
336
|
+
},
|
|
332
337
|
],
|
|
333
338
|
hints: [
|
|
334
339
|
"Use pagination for organizations with many projects to avoid large responses",
|
|
335
|
-
"Project IDs from this list can be used with other tools when no project API key is configured"
|
|
336
|
-
]
|
|
340
|
+
"Project IDs from this list can be used with other tools when no project API key is configured",
|
|
341
|
+
],
|
|
337
342
|
}, async (args, _extra) => {
|
|
338
343
|
let projects = await this.getProjects();
|
|
339
344
|
if (!projects || projects.length === 0) {
|
|
@@ -341,8 +346,8 @@ export class BugsnagClient {
|
|
|
341
346
|
content: [{ type: "text", text: "No projects found." }],
|
|
342
347
|
};
|
|
343
348
|
}
|
|
344
|
-
if (args.
|
|
345
|
-
const pageSize = args.
|
|
349
|
+
if (args.pageSize || args.page) {
|
|
350
|
+
const pageSize = args.pageSize || 10;
|
|
346
351
|
const page = args.page || 1;
|
|
347
352
|
projects = projects.slice((page - 1) * pageSize, page * pageSize);
|
|
348
353
|
}
|
|
@@ -363,7 +368,7 @@ export class BugsnagClient {
|
|
|
363
368
|
"Investigate a specific error found through the List Project Errors tool",
|
|
364
369
|
"Understand which types of user are affected by the error using summarized event data",
|
|
365
370
|
"Get error details for debugging and root cause analysis",
|
|
366
|
-
"Retrieve error metadata for incident reports and documentation"
|
|
371
|
+
"Retrieve error metadata for incident reports and documentation",
|
|
367
372
|
],
|
|
368
373
|
parameters: [
|
|
369
374
|
{
|
|
@@ -371,16 +376,18 @@ export class BugsnagClient {
|
|
|
371
376
|
type: z.string(),
|
|
372
377
|
required: true,
|
|
373
378
|
description: "Unique identifier of the error to retrieve",
|
|
374
|
-
examples: ["6863e2af8c857c0a5023b411"]
|
|
379
|
+
examples: ["6863e2af8c857c0a5023b411"],
|
|
375
380
|
},
|
|
376
|
-
...(this.projectApiKey
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
381
|
+
...(this.projectApiKey
|
|
382
|
+
? []
|
|
383
|
+
: [
|
|
384
|
+
{
|
|
385
|
+
name: "projectId",
|
|
386
|
+
type: z.string(),
|
|
387
|
+
required: true,
|
|
388
|
+
description: "ID of the project containing the error",
|
|
389
|
+
},
|
|
390
|
+
]),
|
|
384
391
|
{
|
|
385
392
|
name: "filters",
|
|
386
393
|
type: FilterObjectSchema,
|
|
@@ -390,14 +397,14 @@ export class BugsnagClient {
|
|
|
390
397
|
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
391
398
|
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
392
399
|
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
393
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}'
|
|
400
|
+
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
394
401
|
],
|
|
395
402
|
constraints: [
|
|
396
403
|
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
397
404
|
"ISO 8601 times must be in UTC and use extended format",
|
|
398
|
-
"Relative time periods: h (hours), d (days)"
|
|
399
|
-
]
|
|
400
|
-
}
|
|
405
|
+
"Relative time periods: h (hours), d (days)",
|
|
406
|
+
],
|
|
407
|
+
},
|
|
401
408
|
],
|
|
402
409
|
outputFormat: "JSON object containing: " +
|
|
403
410
|
" - error_details: Aggregated data about the error, including first and last seen occurrence" +
|
|
@@ -408,10 +415,10 @@ export class BugsnagClient {
|
|
|
408
415
|
{
|
|
409
416
|
description: "Get details for a specific error",
|
|
410
417
|
parameters: {
|
|
411
|
-
errorId: "6863e2af8c857c0a5023b411"
|
|
418
|
+
errorId: "6863e2af8c857c0a5023b411",
|
|
412
419
|
},
|
|
413
|
-
expectedOutput: "JSON object with error details including message, stack trace, occurrence count, and metadata"
|
|
414
|
-
}
|
|
420
|
+
expectedOutput: "JSON object with error details including message, stack trace, occurrence count, and metadata",
|
|
421
|
+
},
|
|
415
422
|
],
|
|
416
423
|
hints: [
|
|
417
424
|
"Error IDs can be found using the List Project Errors tool",
|
|
@@ -430,22 +437,20 @@ export class BugsnagClient {
|
|
|
430
437
|
// Build query parameters
|
|
431
438
|
const params = new URLSearchParams();
|
|
432
439
|
// Add sorting and pagination parameters to get the latest event
|
|
433
|
-
params.append(
|
|
434
|
-
params.append(
|
|
435
|
-
params.append(
|
|
436
|
-
params.append(
|
|
440
|
+
params.append("sort", "timestamp");
|
|
441
|
+
params.append("direction", "desc");
|
|
442
|
+
params.append("per_page", "1");
|
|
443
|
+
params.append("full_reports", "true");
|
|
437
444
|
const filters = {
|
|
438
|
-
|
|
439
|
-
...args.filters
|
|
445
|
+
error: [{ type: "eq", value: args.errorId }],
|
|
446
|
+
...args.filters,
|
|
440
447
|
};
|
|
441
448
|
const filtersQueryString = toQueryString(filters);
|
|
442
449
|
const listEventsQueryString = `?${params}&${filtersQueryString}`;
|
|
443
450
|
// Get the latest event for this error using the events endpoint with filters
|
|
444
451
|
let latestEvent = null;
|
|
445
452
|
try {
|
|
446
|
-
|
|
447
|
-
const events = eventsResponse.body || [];
|
|
448
|
-
latestEvent = events[0] || null;
|
|
453
|
+
latestEvent = (await this.errorsApi.getLatestEventOnProject(project.id, listEventsQueryString)).body;
|
|
449
454
|
}
|
|
450
455
|
catch (e) {
|
|
451
456
|
console.warn("Failed to fetch latest event:", e);
|
|
@@ -454,11 +459,12 @@ export class BugsnagClient {
|
|
|
454
459
|
const content = {
|
|
455
460
|
error_details: errorDetails,
|
|
456
461
|
latest_event: latestEvent,
|
|
457
|
-
pivots: (await this.errorsApi.listErrorPivots(project.id, args.errorId))
|
|
462
|
+
pivots: (await this.errorsApi.listErrorPivots(project.id, args.errorId))
|
|
463
|
+
.body || [],
|
|
458
464
|
url: await this.getErrorUrl(project, args.errorId, `?${filtersQueryString}`),
|
|
459
465
|
};
|
|
460
466
|
return {
|
|
461
|
-
content: [{ type: "text", text: JSON.stringify(content) }]
|
|
467
|
+
content: [{ type: "text", text: JSON.stringify(content) }],
|
|
462
468
|
};
|
|
463
469
|
});
|
|
464
470
|
register({
|
|
@@ -468,7 +474,7 @@ export class BugsnagClient {
|
|
|
468
474
|
useCases: [
|
|
469
475
|
"Get event details when given a dashboard URL from a user or notification",
|
|
470
476
|
"Extract event information from shared links or browser URLs",
|
|
471
|
-
"Quick lookup of event details without needing separate project and event IDs"
|
|
477
|
+
"Quick lookup of event details without needing separate project and event IDs",
|
|
472
478
|
],
|
|
473
479
|
parameters: [
|
|
474
480
|
{
|
|
@@ -477,32 +483,32 @@ export class BugsnagClient {
|
|
|
477
483
|
description: "Full URL to the event details page in the BugSnag dashboard (web interface)",
|
|
478
484
|
required: true,
|
|
479
485
|
examples: [
|
|
480
|
-
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000"
|
|
486
|
+
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000",
|
|
481
487
|
],
|
|
482
488
|
constraints: [
|
|
483
|
-
"Must be a valid dashboard URL containing project slug and event_id parameter"
|
|
484
|
-
]
|
|
485
|
-
}
|
|
489
|
+
"Must be a valid dashboard URL containing project slug and event_id parameter",
|
|
490
|
+
],
|
|
491
|
+
},
|
|
486
492
|
],
|
|
487
493
|
examples: [
|
|
488
494
|
{
|
|
489
495
|
description: "Get event details from a dashboard URL",
|
|
490
496
|
parameters: {
|
|
491
|
-
link: "https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000"
|
|
497
|
+
link: "https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000",
|
|
492
498
|
},
|
|
493
|
-
expectedOutput: "JSON object with complete event details including stack trace, metadata, and context"
|
|
494
|
-
}
|
|
499
|
+
expectedOutput: "JSON object with complete event details including stack trace, metadata, and context",
|
|
500
|
+
},
|
|
495
501
|
],
|
|
496
502
|
hints: [
|
|
497
503
|
"The URL must contain both project slug in the path and event_id in query parameters",
|
|
498
|
-
"This is useful when users share BugSnag dashboard URLs and you need to extract the event data"
|
|
499
|
-
]
|
|
504
|
+
"This is useful when users share BugSnag dashboard URLs and you need to extract the event data",
|
|
505
|
+
],
|
|
500
506
|
}, async (args, _extra) => {
|
|
501
507
|
if (!args.link)
|
|
502
508
|
throw new Error("link argument is required");
|
|
503
509
|
const url = new URL(args.link);
|
|
504
510
|
const eventId = url.searchParams.get("event_id");
|
|
505
|
-
const projectSlug = url.pathname.split(
|
|
511
|
+
const projectSlug = url.pathname.split("/")[2];
|
|
506
512
|
if (!projectSlug || !eventId)
|
|
507
513
|
throw new Error("Both projectSlug and eventId must be present in the link");
|
|
508
514
|
// get the project id from list of projects
|
|
@@ -524,14 +530,14 @@ export class BugsnagClient {
|
|
|
524
530
|
"Debug recent application errors by filtering for open errors in the last 7 days",
|
|
525
531
|
"Generate error reports for stakeholders by filtering specific error types or severity levels",
|
|
526
532
|
"Monitor error trends over time using date range filters",
|
|
527
|
-
"Find errors affecting specific users or environments using metadata filters"
|
|
533
|
+
"Find errors affecting specific users or environments using metadata filters",
|
|
528
534
|
],
|
|
529
535
|
parameters: [
|
|
530
536
|
{
|
|
531
537
|
name: "filters",
|
|
532
538
|
type: FilterObjectSchema.default({
|
|
533
539
|
"event.since": [{ type: "eq", value: "30d" }],
|
|
534
|
-
"error.status": [{ type: "eq", value: "open" }]
|
|
540
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
535
541
|
}),
|
|
536
542
|
description: "Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields",
|
|
537
543
|
required: false,
|
|
@@ -539,84 +545,92 @@ export class BugsnagClient {
|
|
|
539
545
|
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
540
546
|
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
541
547
|
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
542
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}'
|
|
548
|
+
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
543
549
|
],
|
|
544
550
|
constraints: [
|
|
545
551
|
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
546
552
|
"ISO 8601 times must be in UTC and use extended format",
|
|
547
|
-
"Relative time periods: h (hours), d (days)"
|
|
548
|
-
]
|
|
553
|
+
"Relative time periods: h (hours), d (days)",
|
|
554
|
+
],
|
|
549
555
|
},
|
|
550
556
|
{
|
|
551
557
|
name: "sort",
|
|
552
|
-
type: z
|
|
558
|
+
type: z
|
|
559
|
+
.enum(["first_seen", "last_seen", "events", "users", "unsorted"])
|
|
560
|
+
.default("last_seen"),
|
|
553
561
|
description: "Field to sort the errors by",
|
|
554
562
|
required: false,
|
|
555
|
-
examples: ["last_seen"]
|
|
563
|
+
examples: ["last_seen"],
|
|
556
564
|
},
|
|
557
565
|
{
|
|
558
566
|
name: "direction",
|
|
559
567
|
type: z.enum(["asc", "desc"]).default("desc"),
|
|
560
568
|
description: "Sort direction for ordering results",
|
|
561
569
|
required: false,
|
|
562
|
-
examples: ["desc"]
|
|
570
|
+
examples: ["desc"],
|
|
563
571
|
},
|
|
564
572
|
{
|
|
565
|
-
name: "
|
|
573
|
+
name: "perPage",
|
|
566
574
|
type: z.number().min(1).max(100).default(30),
|
|
567
575
|
description: "How many results to return per page.",
|
|
568
576
|
required: false,
|
|
569
|
-
examples: ["30", "50", "100"]
|
|
577
|
+
examples: ["30", "50", "100"],
|
|
570
578
|
},
|
|
571
579
|
{
|
|
572
|
-
name: "
|
|
580
|
+
name: "nextUrl",
|
|
573
581
|
type: z.string().url(),
|
|
574
582
|
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.",
|
|
575
583
|
required: false,
|
|
576
|
-
examples: [
|
|
577
|
-
|
|
584
|
+
examples: [
|
|
585
|
+
"https://api.bugsnag.com/projects/515fb9337c1074f6fd000003/errors?offset=30&per_page=30&sort=last_seen",
|
|
586
|
+
],
|
|
587
|
+
constraints: [
|
|
588
|
+
"Only values provided in the output from this tool can be used. Do not attempt to construct it manually.",
|
|
589
|
+
],
|
|
578
590
|
},
|
|
579
|
-
...(this.projectApiKey
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
591
|
+
...(this.projectApiKey
|
|
592
|
+
? []
|
|
593
|
+
: [
|
|
594
|
+
{
|
|
595
|
+
name: "projectId",
|
|
596
|
+
type: z.string(),
|
|
597
|
+
description: "ID of the project to query for errors",
|
|
598
|
+
required: true,
|
|
599
|
+
},
|
|
600
|
+
]),
|
|
587
601
|
],
|
|
588
602
|
examples: [
|
|
589
603
|
{
|
|
590
604
|
description: "Find errors affecting a specific user in the last 24 hours",
|
|
591
605
|
parameters: {
|
|
592
606
|
filters: {
|
|
593
|
-
"user.email": [{
|
|
594
|
-
"event.since": [{
|
|
595
|
-
}
|
|
607
|
+
"user.email": [{ type: "eq", value: "user@example.com" }],
|
|
608
|
+
"event.since": [{ type: "eq", value: "24h" }],
|
|
609
|
+
},
|
|
596
610
|
},
|
|
597
|
-
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"
|
|
611
|
+
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",
|
|
598
612
|
},
|
|
599
613
|
{
|
|
600
614
|
description: "Get the 10 open errors with the most users affected in the last 30 days",
|
|
601
615
|
parameters: {
|
|
602
616
|
filters: {
|
|
603
|
-
"event.since": [{
|
|
604
|
-
"error.status": [{
|
|
617
|
+
"event.since": [{ type: "eq", value: "30d" }],
|
|
618
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
605
619
|
},
|
|
606
620
|
sort: "users",
|
|
607
621
|
direction: "desc",
|
|
608
|
-
|
|
622
|
+
perPage: 10,
|
|
609
623
|
},
|
|
610
|
-
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"
|
|
624
|
+
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",
|
|
611
625
|
},
|
|
612
626
|
{
|
|
613
627
|
description: "Get the next 50 results",
|
|
614
628
|
parameters: {
|
|
615
|
-
|
|
616
|
-
|
|
629
|
+
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",
|
|
630
|
+
perPage: 50,
|
|
617
631
|
},
|
|
618
|
-
expectedOutput: "JSON object with a list of errors
|
|
619
|
-
}
|
|
632
|
+
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",
|
|
633
|
+
},
|
|
620
634
|
],
|
|
621
635
|
hints: [
|
|
622
636
|
"Use list_project_event_filters tool first to discover valid filter field names for your project",
|
|
@@ -625,16 +639,16 @@ export class BugsnagClient {
|
|
|
625
639
|
"Common time filters: event.since (from this time), event.before (until this time)",
|
|
626
640
|
"The 'event.since' filter and 'error.status' filters are always applied and if not specified are set to '30d' and 'open' respectively",
|
|
627
641
|
"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",
|
|
628
|
-
"This tool returns paged results. The '
|
|
629
|
-
"If the output contains a '
|
|
630
|
-
"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."
|
|
631
|
-
]
|
|
642
|
+
"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.",
|
|
643
|
+
"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.",
|
|
644
|
+
"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.",
|
|
645
|
+
],
|
|
632
646
|
}, async (args, _extra) => {
|
|
633
647
|
const project = await this.getInputProject(args.projectId);
|
|
634
648
|
// Validate filter keys against cached event fields
|
|
635
649
|
if (args.filters) {
|
|
636
650
|
const eventFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS) || [];
|
|
637
|
-
const validKeys = new Set(eventFields.map(f => f.display_id));
|
|
651
|
+
const validKeys = new Set(eventFields.map((f) => f.display_id));
|
|
638
652
|
for (const key of Object.keys(args.filters)) {
|
|
639
653
|
if (!validKeys.has(key)) {
|
|
640
654
|
throw new Error(`Invalid filter key: ${key}`);
|
|
@@ -642,29 +656,26 @@ export class BugsnagClient {
|
|
|
642
656
|
}
|
|
643
657
|
}
|
|
644
658
|
const defaultFilters = {
|
|
645
|
-
"event.since": [{
|
|
646
|
-
"error.status": [{
|
|
659
|
+
"event.since": [{ type: "eq", value: "30d" }],
|
|
660
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
647
661
|
};
|
|
648
662
|
const options = {
|
|
649
|
-
filters: { ...defaultFilters, ...args.filters }
|
|
663
|
+
filters: { ...defaultFilters, ...args.filters },
|
|
650
664
|
};
|
|
651
665
|
if (args.sort !== undefined)
|
|
652
666
|
options.sort = args.sort;
|
|
653
667
|
if (args.direction !== undefined)
|
|
654
668
|
options.direction = args.direction;
|
|
655
|
-
if (args.
|
|
656
|
-
options.per_page = args.
|
|
657
|
-
if (args.
|
|
658
|
-
options.
|
|
669
|
+
if (args.perPage !== undefined)
|
|
670
|
+
options.per_page = args.perPage;
|
|
671
|
+
if (args.nextUrl !== undefined)
|
|
672
|
+
options.next_url = args.nextUrl;
|
|
659
673
|
const response = await this.errorsApi.listProjectErrors(project.id, options);
|
|
660
|
-
const errors = response.body || [];
|
|
661
|
-
const totalCount = response.headers.get('X-Total-Count');
|
|
662
|
-
const linkHeader = response.headers.get('Link');
|
|
663
674
|
const result = {
|
|
664
|
-
data:
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
675
|
+
data: response.body,
|
|
676
|
+
next_url: response.nextUrl ?? undefined,
|
|
677
|
+
data_count: response.body?.length,
|
|
678
|
+
total_count: response.totalCount ?? undefined,
|
|
668
679
|
};
|
|
669
680
|
return {
|
|
670
681
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
@@ -677,20 +688,20 @@ export class BugsnagClient {
|
|
|
677
688
|
useCases: [
|
|
678
689
|
"Discover what filter fields are available before searching for errors",
|
|
679
690
|
"Find the correct field names for filtering by user, environment, or custom metadata",
|
|
680
|
-
"Understand filter options and data types for building complex queries"
|
|
691
|
+
"Understand filter options and data types for building complex queries",
|
|
681
692
|
],
|
|
682
693
|
parameters: [],
|
|
683
694
|
examples: [
|
|
684
695
|
{
|
|
685
696
|
description: "Get all available filter fields",
|
|
686
697
|
parameters: {},
|
|
687
|
-
expectedOutput: "JSON array of EventField objects containing display_id, custom flag, and filter/pivot options"
|
|
688
|
-
}
|
|
698
|
+
expectedOutput: "JSON array of EventField objects containing display_id, custom flag, and filter/pivot options",
|
|
699
|
+
},
|
|
689
700
|
],
|
|
690
701
|
hints: [
|
|
691
702
|
"Use this tool before the List Errors or Get Error tools to understand available filters",
|
|
692
|
-
"Look for display_id field in the response - these are the field names to use in filters"
|
|
693
|
-
]
|
|
703
|
+
"Look for display_id field in the response - these are the field names to use in filters",
|
|
704
|
+
],
|
|
694
705
|
}, async (_args, _extra) => {
|
|
695
706
|
const projectFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS);
|
|
696
707
|
if (!projectFields)
|
|
@@ -706,52 +717,54 @@ export class BugsnagClient {
|
|
|
706
717
|
useCases: [
|
|
707
718
|
"Mark an error as open, fixed or ignored",
|
|
708
719
|
"Discard or un-discard an error",
|
|
709
|
-
"Update the severity of an error"
|
|
720
|
+
"Update the severity of an error",
|
|
710
721
|
],
|
|
711
722
|
parameters: [
|
|
712
|
-
...(this.projectApiKey
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
723
|
+
...(this.projectApiKey
|
|
724
|
+
? []
|
|
725
|
+
: [
|
|
726
|
+
{
|
|
727
|
+
name: "projectId",
|
|
728
|
+
type: z.string(),
|
|
729
|
+
description: "ID of the project that contains the error to be updated",
|
|
730
|
+
required: true,
|
|
731
|
+
},
|
|
732
|
+
]),
|
|
720
733
|
{
|
|
721
734
|
name: "errorId",
|
|
722
735
|
type: z.string(),
|
|
723
736
|
description: "ID of the error to update",
|
|
724
737
|
required: true,
|
|
725
|
-
examples: ["6863e2af8c857c0a5023b411"]
|
|
738
|
+
examples: ["6863e2af8c857c0a5023b411"],
|
|
726
739
|
},
|
|
727
740
|
{
|
|
728
741
|
name: "operation",
|
|
729
742
|
type: z.enum(PERMITTED_UPDATE_OPERATIONS),
|
|
730
743
|
description: "The operation to apply to the error",
|
|
731
744
|
required: true,
|
|
732
|
-
examples: ["fix", "open", "ignore", "discard", "undiscard"]
|
|
733
|
-
}
|
|
745
|
+
examples: ["fix", "open", "ignore", "discard", "undiscard"],
|
|
746
|
+
},
|
|
734
747
|
],
|
|
735
748
|
examples: [
|
|
736
749
|
{
|
|
737
750
|
description: "Mark an error as fixed",
|
|
738
751
|
parameters: {
|
|
739
752
|
errorId: "6863e2af8c857c0a5023b411",
|
|
740
|
-
operation: "fix"
|
|
753
|
+
operation: "fix",
|
|
741
754
|
},
|
|
742
|
-
expectedOutput: "Success response indicating the error was marked as fixed"
|
|
743
|
-
}
|
|
755
|
+
expectedOutput: "Success response indicating the error was marked as fixed",
|
|
756
|
+
},
|
|
744
757
|
],
|
|
745
758
|
hints: [
|
|
746
|
-
"Only use valid operations - BugSnag may reject invalid values"
|
|
759
|
+
"Only use valid operations - BugSnag may reject invalid values",
|
|
747
760
|
],
|
|
748
761
|
readOnly: false,
|
|
749
762
|
idempotent: false,
|
|
750
763
|
}, async (args, _extra) => {
|
|
751
764
|
const { errorId, operation } = args;
|
|
752
765
|
const project = await this.getInputProject(args.projectId);
|
|
753
|
-
let severity
|
|
754
|
-
if (operation ===
|
|
766
|
+
let severity;
|
|
767
|
+
if (operation === "override_severity") {
|
|
755
768
|
// illicit the severity from the user
|
|
756
769
|
const result = await getInput({
|
|
757
770
|
message: "Please provide the new severity for the error (e.g. 'info', 'warning', 'error', 'critical')",
|
|
@@ -760,153 +773,29 @@ export class BugsnagClient {
|
|
|
760
773
|
properties: {
|
|
761
774
|
severity: {
|
|
762
775
|
type: "string",
|
|
763
|
-
enum: [
|
|
764
|
-
description: "The new severity level for the error"
|
|
765
|
-
}
|
|
766
|
-
}
|
|
776
|
+
enum: ["info", "warning", "error"],
|
|
777
|
+
description: "The new severity level for the error",
|
|
778
|
+
},
|
|
779
|
+
},
|
|
767
780
|
},
|
|
768
|
-
required: ["severity"]
|
|
781
|
+
required: ["severity"],
|
|
769
782
|
});
|
|
770
783
|
if (result.action === "accept" && result.content?.severity) {
|
|
771
784
|
severity = result.content.severity;
|
|
772
785
|
}
|
|
773
786
|
}
|
|
774
|
-
const result = await this.updateError(project.id, errorId, operation, {
|
|
775
|
-
|
|
776
|
-
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
|
|
777
|
-
};
|
|
778
|
-
});
|
|
779
|
-
register({
|
|
780
|
-
title: "List Builds",
|
|
781
|
-
summary: "List builds for a project with optional filtering by release stage",
|
|
782
|
-
purpose: "Retrieve a list of build summaries to analyze deployment history and associated errors",
|
|
783
|
-
useCases: [
|
|
784
|
-
"View recent builds to correlate with error spikes",
|
|
785
|
-
"Filter builds by stage (e.g. production, staging) for targeted analysis",
|
|
786
|
-
],
|
|
787
|
-
parameters: [
|
|
788
|
-
...(this.projectApiKey
|
|
789
|
-
? []
|
|
790
|
-
: [
|
|
791
|
-
{
|
|
792
|
-
name: "projectId",
|
|
793
|
-
type: z.string(),
|
|
794
|
-
description: "ID of the project to list builds for",
|
|
795
|
-
required: true,
|
|
796
|
-
},
|
|
797
|
-
]),
|
|
798
|
-
{
|
|
799
|
-
name: "releaseStage",
|
|
800
|
-
type: z.string(),
|
|
801
|
-
description: "Filter builds by this stage (e.g. production, staging)",
|
|
802
|
-
required: false,
|
|
803
|
-
examples: ["production", "staging"],
|
|
804
|
-
},
|
|
805
|
-
{
|
|
806
|
-
name: "nextUrl",
|
|
807
|
-
type: z.string(),
|
|
808
|
-
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.",
|
|
809
|
-
required: false,
|
|
810
|
-
examples: [
|
|
811
|
-
"/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
812
|
-
],
|
|
813
|
-
},
|
|
814
|
-
],
|
|
815
|
-
examples: [
|
|
816
|
-
{
|
|
817
|
-
description: "List all builds for a project",
|
|
818
|
-
parameters: {},
|
|
819
|
-
expectedOutput: "JSON array of build objects with metadata",
|
|
820
|
-
},
|
|
821
|
-
{
|
|
822
|
-
description: "List production builds for a project",
|
|
823
|
-
parameters: {
|
|
824
|
-
releaseStage: "production",
|
|
825
|
-
},
|
|
826
|
-
expectedOutput: "JSON array of build objects in the production stage",
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
description: "Get the next page of results",
|
|
830
|
-
parameters: {
|
|
831
|
-
nextUrl: "/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
832
|
-
},
|
|
833
|
-
expectedOutput: "JSON array of build objects with metadata from the next page",
|
|
834
|
-
}
|
|
835
|
-
],
|
|
836
|
-
hints: ["For more detailed results use the Get Build tool"],
|
|
837
|
-
readOnly: true,
|
|
838
|
-
idempotent: true,
|
|
839
|
-
outputFormat: "JSON array of build summary objects with metadata",
|
|
840
|
-
}, async (args, _extra) => {
|
|
841
|
-
const project = await this.getInputProject(args.projectId);
|
|
842
|
-
const { builds, nextUrl } = await this.listBuilds(project.id, {
|
|
843
|
-
release_stage: args.releaseStage,
|
|
844
|
-
next_url: args.nextUrl,
|
|
787
|
+
const result = await this.updateError(project.id, errorId, operation, {
|
|
788
|
+
severity,
|
|
845
789
|
});
|
|
846
790
|
return {
|
|
847
791
|
content: [
|
|
848
|
-
{
|
|
849
|
-
type: "text",
|
|
850
|
-
text: JSON.stringify({
|
|
851
|
-
builds,
|
|
852
|
-
next: nextUrl,
|
|
853
|
-
}),
|
|
854
|
-
}
|
|
792
|
+
{ type: "text", text: JSON.stringify({ success: result }) },
|
|
855
793
|
],
|
|
856
794
|
};
|
|
857
795
|
});
|
|
858
|
-
register({
|
|
859
|
-
title: "Get Build",
|
|
860
|
-
summary: "Get more details for a specific build by its ID",
|
|
861
|
-
purpose: "Retrieve detailed information about a build for analysis and debugging",
|
|
862
|
-
useCases: [
|
|
863
|
-
"View build metadata such as version, source control info, and error counts",
|
|
864
|
-
"Analyze a specific build to correlate with error spikes or deployments",
|
|
865
|
-
"See the stability targets for a project and if the build meets them",
|
|
866
|
-
],
|
|
867
|
-
parameters: [
|
|
868
|
-
...(this.projectApiKey
|
|
869
|
-
? []
|
|
870
|
-
: [
|
|
871
|
-
{
|
|
872
|
-
name: "projectId",
|
|
873
|
-
type: z.string(),
|
|
874
|
-
description: "ID of the project containing the build",
|
|
875
|
-
required: true,
|
|
876
|
-
},
|
|
877
|
-
]),
|
|
878
|
-
{
|
|
879
|
-
name: "buildId",
|
|
880
|
-
type: z.string(),
|
|
881
|
-
description: "ID of the build to retrieve",
|
|
882
|
-
required: true,
|
|
883
|
-
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
884
|
-
},
|
|
885
|
-
],
|
|
886
|
-
examples: [
|
|
887
|
-
{
|
|
888
|
-
description: "Get details for a specific build",
|
|
889
|
-
parameters: {
|
|
890
|
-
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
891
|
-
},
|
|
892
|
-
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
893
|
-
},
|
|
894
|
-
],
|
|
895
|
-
hints: ["Build IDs can be found using the List builds tool"],
|
|
896
|
-
readOnly: true,
|
|
897
|
-
idempotent: true,
|
|
898
|
-
outputFormat: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
899
|
-
}, async (args, _extra) => {
|
|
900
|
-
if (!args.buildId)
|
|
901
|
-
throw new Error("buildId argument is required");
|
|
902
|
-
const build = await this.getBuild((await this.getInputProject(args.projectId)).id, args.buildId);
|
|
903
|
-
return {
|
|
904
|
-
content: [{ type: "text", text: JSON.stringify(build) }],
|
|
905
|
-
};
|
|
906
|
-
});
|
|
907
796
|
register({
|
|
908
797
|
title: "List Releases",
|
|
909
|
-
summary: "List releases for a project
|
|
798
|
+
summary: "List releases for a project",
|
|
910
799
|
purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
|
|
911
800
|
useCases: [
|
|
912
801
|
"View recent releases to correlate with error spikes",
|
|
@@ -925,16 +814,16 @@ export class BugsnagClient {
|
|
|
925
814
|
]),
|
|
926
815
|
{
|
|
927
816
|
name: "releaseStage",
|
|
928
|
-
type: z.string(),
|
|
929
|
-
description: "Filter releases by this stage (e.g. production, staging)",
|
|
817
|
+
type: z.string().default("production"),
|
|
818
|
+
description: "Filter releases by this stage (e.g. production, staging), defaults to 'production'",
|
|
930
819
|
required: false,
|
|
931
820
|
examples: ["production", "staging"],
|
|
932
821
|
},
|
|
933
822
|
{
|
|
934
823
|
name: "visibleOnly",
|
|
935
|
-
type: z.boolean().default(
|
|
936
|
-
description: "Whether to only include releases that are marked as visible
|
|
937
|
-
required:
|
|
824
|
+
type: z.boolean().default(false),
|
|
825
|
+
description: "Whether to only include releases that are marked as visible in the dashboard, defaults to false",
|
|
826
|
+
required: false,
|
|
938
827
|
examples: ["true", "false"],
|
|
939
828
|
},
|
|
940
829
|
{
|
|
@@ -949,16 +838,16 @@ export class BugsnagClient {
|
|
|
949
838
|
],
|
|
950
839
|
examples: [
|
|
951
840
|
{
|
|
952
|
-
description: "List
|
|
841
|
+
description: "List production releases for a project",
|
|
953
842
|
parameters: {},
|
|
954
|
-
expectedOutput: "JSON array of release objects
|
|
843
|
+
expectedOutput: "JSON array of release objects in the production stage",
|
|
955
844
|
},
|
|
956
845
|
{
|
|
957
|
-
description: "List
|
|
846
|
+
description: "List staging releases for a project",
|
|
958
847
|
parameters: {
|
|
959
|
-
releaseStage: "
|
|
848
|
+
releaseStage: "staging",
|
|
960
849
|
},
|
|
961
|
-
expectedOutput: "JSON array of release objects in the
|
|
850
|
+
expectedOutput: "JSON array of release objects in the staging stage",
|
|
962
851
|
},
|
|
963
852
|
{
|
|
964
853
|
description: "Get the next page of results",
|
|
@@ -968,23 +857,29 @@ export class BugsnagClient {
|
|
|
968
857
|
expectedOutput: "JSON array of release objects with metadata from the next page",
|
|
969
858
|
},
|
|
970
859
|
],
|
|
971
|
-
hints: [
|
|
860
|
+
hints: [
|
|
861
|
+
"Use the Get Release tool to get more details on a specific release, including the builds it contains",
|
|
862
|
+
"The release stage defaults to 'production' if not specified",
|
|
863
|
+
"Use visibleOnly to filter out releases that have been marked as hidden in the dashboard",
|
|
864
|
+
],
|
|
972
865
|
readOnly: true,
|
|
973
866
|
idempotent: true,
|
|
974
|
-
outputFormat: "JSON array of release summary objects with metadata",
|
|
867
|
+
outputFormat: "JSON array of release summary objects with metadata, with a URL to the next page if more results are available",
|
|
975
868
|
}, async (args, _extra) => {
|
|
976
|
-
const
|
|
977
|
-
release_stage_name: args.releaseStage
|
|
869
|
+
const response = await this.listReleases((await this.getInputProject(args.projectId)).id, {
|
|
870
|
+
release_stage_name: args.releaseStage,
|
|
978
871
|
visible_only: args.visibleOnly,
|
|
979
|
-
next_url: args.nextUrl
|
|
872
|
+
next_url: args.nextUrl,
|
|
980
873
|
});
|
|
981
874
|
return {
|
|
982
875
|
content: [
|
|
983
876
|
{
|
|
984
877
|
type: "text",
|
|
985
878
|
text: JSON.stringify({
|
|
986
|
-
|
|
987
|
-
|
|
879
|
+
data: response.body,
|
|
880
|
+
next_url: response.nextUrl ?? undefined,
|
|
881
|
+
data_count: response.body?.length,
|
|
882
|
+
total_count: response.totalCount ?? undefined,
|
|
988
883
|
}),
|
|
989
884
|
},
|
|
990
885
|
],
|
|
@@ -992,12 +887,12 @@ export class BugsnagClient {
|
|
|
992
887
|
});
|
|
993
888
|
register({
|
|
994
889
|
title: "Get Release",
|
|
995
|
-
summary: "Get more details for a specific release by its ID",
|
|
890
|
+
summary: "Get more details for a specific release by its ID, including source control information and associated builds",
|
|
996
891
|
purpose: "Retrieve detailed information about a release for analysis and debugging",
|
|
997
892
|
useCases: [
|
|
998
893
|
"View release metadata such as version, source control info, and error counts",
|
|
999
|
-
"Analyze
|
|
1000
|
-
"See the
|
|
894
|
+
"Analyze the stability data and targets for a release",
|
|
895
|
+
"See the builds that make up the release",
|
|
1001
896
|
],
|
|
1002
897
|
parameters: [
|
|
1003
898
|
...(this.projectApiKey
|
|
@@ -1034,18 +929,29 @@ export class BugsnagClient {
|
|
|
1034
929
|
}, async (args, _extra) => {
|
|
1035
930
|
if (!args.releaseId)
|
|
1036
931
|
throw new Error("releaseId argument is required");
|
|
1037
|
-
const
|
|
932
|
+
const project = await this.getInputProject(args.projectId);
|
|
933
|
+
const releaseResponse = await this.getRelease(project.id, args.releaseId);
|
|
934
|
+
const buildsResponse = await this.listBuildsInRelease(project.id, args.releaseId);
|
|
1038
935
|
return {
|
|
1039
|
-
content: [
|
|
936
|
+
content: [
|
|
937
|
+
{
|
|
938
|
+
type: "text",
|
|
939
|
+
text: JSON.stringify({
|
|
940
|
+
release: releaseResponse.body,
|
|
941
|
+
builds: buildsResponse.body,
|
|
942
|
+
}),
|
|
943
|
+
},
|
|
944
|
+
],
|
|
1040
945
|
};
|
|
1041
946
|
});
|
|
1042
947
|
register({
|
|
1043
|
-
title: "
|
|
1044
|
-
summary: "
|
|
1045
|
-
purpose: "Retrieve
|
|
948
|
+
title: "Get Build",
|
|
949
|
+
summary: "Get more details for a specific build by its ID",
|
|
950
|
+
purpose: "Retrieve detailed information about a build for analysis and debugging",
|
|
1046
951
|
useCases: [
|
|
1047
|
-
"View
|
|
1048
|
-
"Analyze
|
|
952
|
+
"View build metadata such as version, source control info, and error counts",
|
|
953
|
+
"Analyze a specific build to correlate with error spikes or deployments",
|
|
954
|
+
"See the stability targets for a project and if the build meets them",
|
|
1049
955
|
],
|
|
1050
956
|
parameters: [
|
|
1051
957
|
...(this.projectApiKey
|
|
@@ -1054,47 +960,49 @@ export class BugsnagClient {
|
|
|
1054
960
|
{
|
|
1055
961
|
name: "projectId",
|
|
1056
962
|
type: z.string(),
|
|
1057
|
-
description: "ID of the project containing the
|
|
963
|
+
description: "ID of the project containing the build",
|
|
1058
964
|
required: true,
|
|
1059
965
|
},
|
|
1060
966
|
]),
|
|
1061
967
|
{
|
|
1062
|
-
name: "
|
|
968
|
+
name: "buildId",
|
|
1063
969
|
type: z.string(),
|
|
1064
|
-
description: "ID of the
|
|
970
|
+
description: "ID of the build to retrieve",
|
|
1065
971
|
required: true,
|
|
1066
972
|
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
1067
973
|
},
|
|
1068
974
|
],
|
|
1069
975
|
examples: [
|
|
1070
976
|
{
|
|
1071
|
-
description: "
|
|
977
|
+
description: "Get details for a specific build",
|
|
1072
978
|
parameters: {
|
|
1073
|
-
|
|
979
|
+
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
1074
980
|
},
|
|
1075
|
-
expectedOutput: "JSON
|
|
981
|
+
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
1076
982
|
},
|
|
1077
983
|
],
|
|
1078
|
-
hints: ["
|
|
984
|
+
hints: ["Build IDs can be found using the List builds tool"],
|
|
1079
985
|
readOnly: true,
|
|
1080
986
|
idempotent: true,
|
|
1081
|
-
outputFormat: "JSON
|
|
987
|
+
outputFormat: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
1082
988
|
}, async (args, _extra) => {
|
|
1083
|
-
if (!args.
|
|
1084
|
-
throw new Error("
|
|
1085
|
-
const
|
|
989
|
+
if (!args.buildId)
|
|
990
|
+
throw new Error("buildId argument is required");
|
|
991
|
+
const response = await this.getBuild((await this.getInputProject(args.projectId)).id, args.buildId);
|
|
1086
992
|
return {
|
|
1087
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
993
|
+
content: [{ type: "text", text: JSON.stringify(response.body) }],
|
|
1088
994
|
};
|
|
1089
995
|
});
|
|
1090
996
|
}
|
|
1091
997
|
registerResources(register) {
|
|
1092
998
|
register("event", "{id}", async (uri, variables, _extra) => {
|
|
1093
999
|
return {
|
|
1094
|
-
contents: [
|
|
1000
|
+
contents: [
|
|
1001
|
+
{
|
|
1095
1002
|
uri: uri.href,
|
|
1096
|
-
text: JSON.stringify(await this.getEvent(variables.id))
|
|
1097
|
-
}
|
|
1003
|
+
text: JSON.stringify(await this.getEvent(variables.id)),
|
|
1004
|
+
},
|
|
1005
|
+
],
|
|
1098
1006
|
};
|
|
1099
1007
|
});
|
|
1100
1008
|
}
|