@smartbear/mcp 0.6.0 → 0.7.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 +20 -3
- package/dist/api-hub/client/api.js +253 -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 +55 -0
- package/dist/api-hub/client/tools.js +86 -0
- package/dist/api-hub/client.js +64 -404
- package/dist/bugsnag/client/api/CurrentUser.js +16 -10
- package/dist/bugsnag/client/api/Error.js +35 -35
- package/dist/bugsnag/client/api/Project.js +21 -9
- package/dist/bugsnag/client/api/base.js +7 -4
- package/dist/bugsnag/client/api/filters.js +9 -9
- package/dist/bugsnag/client.js +165 -140
- package/dist/common/info.js +1 -1
- package/dist/common/server.js +35 -27
- package/dist/index.js +11 -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 +10 -10
- package/dist/pactflow/client/utils.js +1 -1
- package/dist/pactflow/client.js +16 -9
- 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/package.json +6 -5
package/dist/bugsnag/client.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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 { CurrentUserAPI, ErrorAPI, Configuration } from "./client/index.js";
|
|
5
|
-
import { FilterObjectSchema, toQueryString } from "./client/api/filters.js";
|
|
6
|
-
import { ProjectAPI, } from "./client/api/Project.js";
|
|
7
4
|
import { getNextUrlPathFromHeader } from "./client/api/base.js";
|
|
5
|
+
import { FilterObjectSchema, toQueryString, } from "./client/api/filters.js";
|
|
6
|
+
import { ProjectAPI, } from "./client/api/Project.js";
|
|
7
|
+
import { Configuration, CurrentUserAPI, ErrorAPI } from "./client/index.js";
|
|
8
8
|
const HUB_PREFIX = "00000";
|
|
9
9
|
const DEFAULT_DOMAIN = "bugsnag.com";
|
|
10
10
|
const HUB_DOMAIN = "bugsnag.smartbear.com";
|
|
@@ -15,11 +15,11 @@ const cacheKeys = {
|
|
|
15
15
|
CURRENT_PROJECT_EVENT_FILTERS: "bugsnag_current_project_event_filters",
|
|
16
16
|
BUILD: "bugsnag_build", // + buildId
|
|
17
17
|
RELEASE: "bugsnag_release", // + releaseId
|
|
18
|
-
BUILDS_IN_RELEASE: "bugsnag_builds_in_release" // + releaseId
|
|
18
|
+
BUILDS_IN_RELEASE: "bugsnag_builds_in_release", // + releaseId
|
|
19
19
|
};
|
|
20
20
|
// Exclude certain event fields from the project event filters to improve agent usage
|
|
21
21
|
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
|
|
22
|
+
"search", // This is searches multiple fields and is more a convenience for humans, we're removing to avoid over-matching
|
|
23
23
|
]);
|
|
24
24
|
const PERMITTED_UPDATE_OPERATIONS = [
|
|
25
25
|
"override_severity",
|
|
@@ -27,7 +27,7 @@ const PERMITTED_UPDATE_OPERATIONS = [
|
|
|
27
27
|
"fix",
|
|
28
28
|
"ignore",
|
|
29
29
|
"discard",
|
|
30
|
-
"undiscard"
|
|
30
|
+
"undiscard",
|
|
31
31
|
];
|
|
32
32
|
export class BugsnagClient {
|
|
33
33
|
currentUserApi;
|
|
@@ -82,7 +82,7 @@ export class BugsnagClient {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
getHost(apiKey, subdomain) {
|
|
85
|
-
if (apiKey
|
|
85
|
+
if (apiKey?.startsWith(HUB_PREFIX)) {
|
|
86
86
|
return `https://${subdomain}.${HUB_DOMAIN}`;
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
@@ -95,7 +95,7 @@ export class BugsnagClient {
|
|
|
95
95
|
getEndpoint(subdomain, apiKey, endpoint) {
|
|
96
96
|
let subDomainEndpoint;
|
|
97
97
|
if (!endpoint) {
|
|
98
|
-
if (apiKey
|
|
98
|
+
if (apiKey?.startsWith(HUB_PREFIX)) {
|
|
99
99
|
subDomainEndpoint = `https://${subdomain}.${HUB_DOMAIN}`;
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
@@ -105,7 +105,8 @@ export class BugsnagClient {
|
|
|
105
105
|
else {
|
|
106
106
|
// check if the endpoint matches either the HUB_DOMAIN or DEFAULT_DOMAIN
|
|
107
107
|
const url = new URL(endpoint);
|
|
108
|
-
if (url.hostname.endsWith(HUB_DOMAIN) ||
|
|
108
|
+
if (url.hostname.endsWith(HUB_DOMAIN) ||
|
|
109
|
+
url.hostname.endsWith(DEFAULT_DOMAIN)) {
|
|
109
110
|
// For known domains (Hub or Bugsnag), always use HTTPS and standard format
|
|
110
111
|
if (url.hostname.endsWith(HUB_DOMAIN)) {
|
|
111
112
|
subDomainEndpoint = `https://${subdomain}.${HUB_DOMAIN}`;
|
|
@@ -124,7 +125,7 @@ export class BugsnagClient {
|
|
|
124
125
|
async getDashboardUrl(project) {
|
|
125
126
|
return `${this.appEndpoint}/${(await this.getOrganization()).slug}/${project.slug}`;
|
|
126
127
|
}
|
|
127
|
-
async getErrorUrl(project, errorId, queryString =
|
|
128
|
+
async getErrorUrl(project, errorId, queryString = "") {
|
|
128
129
|
const dashboardUrl = await this.getDashboardUrl(project);
|
|
129
130
|
return `${dashboardUrl}/errors/${errorId}${queryString}`;
|
|
130
131
|
}
|
|
@@ -165,7 +166,7 @@ export class BugsnagClient {
|
|
|
165
166
|
const projects = await this.getProjects();
|
|
166
167
|
project = projects.find((p) => p.api_key === this.projectApiKey) ?? null;
|
|
167
168
|
if (!project) {
|
|
168
|
-
throw new Error(
|
|
169
|
+
throw new Error("Unable to find project with the configured API key.");
|
|
169
170
|
}
|
|
170
171
|
this.cache.set(cacheKeys.CURRENT_PROJECT, project);
|
|
171
172
|
if (project) {
|
|
@@ -179,24 +180,26 @@ export class BugsnagClient {
|
|
|
179
180
|
if (!filtersResponse || filtersResponse.length === 0) {
|
|
180
181
|
throw new Error(`No event fields found for project ${project.name}.`);
|
|
181
182
|
}
|
|
182
|
-
filtersResponse = filtersResponse.filter(field => !EXCLUDED_EVENT_FIELDS.has(field.display_id));
|
|
183
|
+
filtersResponse = filtersResponse.filter((field) => !EXCLUDED_EVENT_FIELDS.has(field.display_id));
|
|
183
184
|
return filtersResponse;
|
|
184
185
|
}
|
|
185
186
|
async getEvent(eventId, projectId) {
|
|
186
|
-
const projectIds = projectId
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
const projectIds = projectId
|
|
188
|
+
? [projectId]
|
|
189
|
+
: (await this.getProjects()).map((p) => p.id);
|
|
190
|
+
const projectEvents = await Promise.all(projectIds.map((projectId) => this.errorsApi.viewEventById(projectId, eventId).catch((_e) => null)));
|
|
191
|
+
return projectEvents.find((event) => event && !!event.body)?.body || null;
|
|
189
192
|
}
|
|
190
193
|
async updateError(projectId, errorId, operation, options) {
|
|
191
194
|
const errorUpdateRequest = {
|
|
192
195
|
operation: operation,
|
|
193
|
-
...options
|
|
196
|
+
...options,
|
|
194
197
|
};
|
|
195
198
|
const response = await this.errorsApi.updateErrorOnProject(projectId, errorId, errorUpdateRequest);
|
|
196
199
|
return response.status === 200 || response.status === 204;
|
|
197
200
|
}
|
|
198
201
|
async getInputProject(projectId) {
|
|
199
|
-
if (typeof projectId ===
|
|
202
|
+
if (typeof projectId === "string") {
|
|
200
203
|
const maybeProject = await this.getProject(projectId);
|
|
201
204
|
if (!maybeProject) {
|
|
202
205
|
throw new Error(`Project with ID ${projectId} not found.`);
|
|
@@ -206,7 +209,7 @@ export class BugsnagClient {
|
|
|
206
209
|
else {
|
|
207
210
|
const currentProject = await this.getCurrentProject();
|
|
208
211
|
if (!currentProject) {
|
|
209
|
-
throw new Error(
|
|
212
|
+
throw new Error("No current project found. Please provide a projectId or configure a project API key.");
|
|
210
213
|
}
|
|
211
214
|
return currentProject;
|
|
212
215
|
}
|
|
@@ -224,7 +227,8 @@ export class BugsnagClient {
|
|
|
224
227
|
const build = this.cache.get(cacheKey);
|
|
225
228
|
if (build)
|
|
226
229
|
return build;
|
|
227
|
-
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId))
|
|
230
|
+
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId))
|
|
231
|
+
.body;
|
|
228
232
|
if (!fetchedBuild)
|
|
229
233
|
throw new Error(`No build for ${buildId} found.`);
|
|
230
234
|
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
@@ -269,11 +273,13 @@ export class BugsnagClient {
|
|
|
269
273
|
const { stability_target_type, target_stability, critical_stability } = stabilityTargets;
|
|
270
274
|
const user_stability = source.accumulative_daily_users_seen === 0 // avoid division by zero
|
|
271
275
|
? 0
|
|
272
|
-
: (source.accumulative_daily_users_seen -
|
|
276
|
+
: (source.accumulative_daily_users_seen -
|
|
277
|
+
source.accumulative_daily_users_with_unhandled) /
|
|
273
278
|
source.accumulative_daily_users_seen;
|
|
274
279
|
const session_stability = source.total_sessions_count === 0 // avoid division by zero
|
|
275
280
|
? 0
|
|
276
|
-
: (source.total_sessions_count - source.unhandled_sessions_count) /
|
|
281
|
+
: (source.total_sessions_count - source.unhandled_sessions_count) /
|
|
282
|
+
source.total_sessions_count;
|
|
277
283
|
const stabilityMetric = stability_target_type === "user" ? user_stability : session_stability;
|
|
278
284
|
const meets_target_stability = stabilityMetric >= target_stability.value;
|
|
279
285
|
const meets_critical_stability = stabilityMetric >= critical_stability.value;
|
|
@@ -297,7 +303,7 @@ export class BugsnagClient {
|
|
|
297
303
|
useCases: [
|
|
298
304
|
"Browse available projects when no specific project API key is configured",
|
|
299
305
|
"Find project IDs needed for other tools",
|
|
300
|
-
"Get an overview of all projects in the organization"
|
|
306
|
+
"Get an overview of all projects in the organization",
|
|
301
307
|
],
|
|
302
308
|
parameters: [
|
|
303
309
|
{
|
|
@@ -305,35 +311,35 @@ export class BugsnagClient {
|
|
|
305
311
|
type: z.number(),
|
|
306
312
|
description: "Number of projects to return per page for pagination",
|
|
307
313
|
required: false,
|
|
308
|
-
examples: ["10", "25", "50"]
|
|
314
|
+
examples: ["10", "25", "50"],
|
|
309
315
|
},
|
|
310
316
|
{
|
|
311
317
|
name: "page",
|
|
312
318
|
type: z.number(),
|
|
313
319
|
description: "Page number to return (starts from 1)",
|
|
314
320
|
required: false,
|
|
315
|
-
examples: ["1", "2", "3"]
|
|
316
|
-
}
|
|
321
|
+
examples: ["1", "2", "3"],
|
|
322
|
+
},
|
|
317
323
|
],
|
|
318
324
|
examples: [
|
|
319
325
|
{
|
|
320
326
|
description: "Get first 10 projects",
|
|
321
327
|
parameters: {
|
|
322
328
|
page_size: 10,
|
|
323
|
-
page: 1
|
|
329
|
+
page: 1,
|
|
324
330
|
},
|
|
325
331
|
expectedOutput: "JSON array of project objects with IDs, names, and metadata",
|
|
326
332
|
},
|
|
327
333
|
{
|
|
328
334
|
description: "Get all projects (no pagination)",
|
|
329
335
|
parameters: {},
|
|
330
|
-
expectedOutput: "JSON array of all available projects"
|
|
331
|
-
}
|
|
336
|
+
expectedOutput: "JSON array of all available projects",
|
|
337
|
+
},
|
|
332
338
|
],
|
|
333
339
|
hints: [
|
|
334
340
|
"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
|
-
]
|
|
341
|
+
"Project IDs from this list can be used with other tools when no project API key is configured",
|
|
342
|
+
],
|
|
337
343
|
}, async (args, _extra) => {
|
|
338
344
|
let projects = await this.getProjects();
|
|
339
345
|
if (!projects || projects.length === 0) {
|
|
@@ -363,7 +369,7 @@ export class BugsnagClient {
|
|
|
363
369
|
"Investigate a specific error found through the List Project Errors tool",
|
|
364
370
|
"Understand which types of user are affected by the error using summarized event data",
|
|
365
371
|
"Get error details for debugging and root cause analysis",
|
|
366
|
-
"Retrieve error metadata for incident reports and documentation"
|
|
372
|
+
"Retrieve error metadata for incident reports and documentation",
|
|
367
373
|
],
|
|
368
374
|
parameters: [
|
|
369
375
|
{
|
|
@@ -371,16 +377,18 @@ export class BugsnagClient {
|
|
|
371
377
|
type: z.string(),
|
|
372
378
|
required: true,
|
|
373
379
|
description: "Unique identifier of the error to retrieve",
|
|
374
|
-
examples: ["6863e2af8c857c0a5023b411"]
|
|
380
|
+
examples: ["6863e2af8c857c0a5023b411"],
|
|
375
381
|
},
|
|
376
|
-
...(this.projectApiKey
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
382
|
+
...(this.projectApiKey
|
|
383
|
+
? []
|
|
384
|
+
: [
|
|
385
|
+
{
|
|
386
|
+
name: "projectId",
|
|
387
|
+
type: z.string(),
|
|
388
|
+
required: true,
|
|
389
|
+
description: "ID of the project containing the error",
|
|
390
|
+
},
|
|
391
|
+
]),
|
|
384
392
|
{
|
|
385
393
|
name: "filters",
|
|
386
394
|
type: FilterObjectSchema,
|
|
@@ -390,14 +398,14 @@ export class BugsnagClient {
|
|
|
390
398
|
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
391
399
|
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
392
400
|
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
393
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}'
|
|
401
|
+
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
394
402
|
],
|
|
395
403
|
constraints: [
|
|
396
404
|
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
397
405
|
"ISO 8601 times must be in UTC and use extended format",
|
|
398
|
-
"Relative time periods: h (hours), d (days)"
|
|
399
|
-
]
|
|
400
|
-
}
|
|
406
|
+
"Relative time periods: h (hours), d (days)",
|
|
407
|
+
],
|
|
408
|
+
},
|
|
401
409
|
],
|
|
402
410
|
outputFormat: "JSON object containing: " +
|
|
403
411
|
" - error_details: Aggregated data about the error, including first and last seen occurrence" +
|
|
@@ -408,10 +416,10 @@ export class BugsnagClient {
|
|
|
408
416
|
{
|
|
409
417
|
description: "Get details for a specific error",
|
|
410
418
|
parameters: {
|
|
411
|
-
errorId: "6863e2af8c857c0a5023b411"
|
|
419
|
+
errorId: "6863e2af8c857c0a5023b411",
|
|
412
420
|
},
|
|
413
|
-
expectedOutput: "JSON object with error details including message, stack trace, occurrence count, and metadata"
|
|
414
|
-
}
|
|
421
|
+
expectedOutput: "JSON object with error details including message, stack trace, occurrence count, and metadata",
|
|
422
|
+
},
|
|
415
423
|
],
|
|
416
424
|
hints: [
|
|
417
425
|
"Error IDs can be found using the List Project Errors tool",
|
|
@@ -430,13 +438,13 @@ export class BugsnagClient {
|
|
|
430
438
|
// Build query parameters
|
|
431
439
|
const params = new URLSearchParams();
|
|
432
440
|
// Add sorting and pagination parameters to get the latest event
|
|
433
|
-
params.append(
|
|
434
|
-
params.append(
|
|
435
|
-
params.append(
|
|
436
|
-
params.append(
|
|
441
|
+
params.append("sort", "timestamp");
|
|
442
|
+
params.append("direction", "desc");
|
|
443
|
+
params.append("per_page", "1");
|
|
444
|
+
params.append("full_reports", "true");
|
|
437
445
|
const filters = {
|
|
438
|
-
|
|
439
|
-
...args.filters
|
|
446
|
+
error: [{ type: "eq", value: args.errorId }],
|
|
447
|
+
...args.filters,
|
|
440
448
|
};
|
|
441
449
|
const filtersQueryString = toQueryString(filters);
|
|
442
450
|
const listEventsQueryString = `?${params}&${filtersQueryString}`;
|
|
@@ -454,11 +462,12 @@ export class BugsnagClient {
|
|
|
454
462
|
const content = {
|
|
455
463
|
error_details: errorDetails,
|
|
456
464
|
latest_event: latestEvent,
|
|
457
|
-
pivots: (await this.errorsApi.listErrorPivots(project.id, args.errorId))
|
|
465
|
+
pivots: (await this.errorsApi.listErrorPivots(project.id, args.errorId))
|
|
466
|
+
.body || [],
|
|
458
467
|
url: await this.getErrorUrl(project, args.errorId, `?${filtersQueryString}`),
|
|
459
468
|
};
|
|
460
469
|
return {
|
|
461
|
-
content: [{ type: "text", text: JSON.stringify(content) }]
|
|
470
|
+
content: [{ type: "text", text: JSON.stringify(content) }],
|
|
462
471
|
};
|
|
463
472
|
});
|
|
464
473
|
register({
|
|
@@ -468,7 +477,7 @@ export class BugsnagClient {
|
|
|
468
477
|
useCases: [
|
|
469
478
|
"Get event details when given a dashboard URL from a user or notification",
|
|
470
479
|
"Extract event information from shared links or browser URLs",
|
|
471
|
-
"Quick lookup of event details without needing separate project and event IDs"
|
|
480
|
+
"Quick lookup of event details without needing separate project and event IDs",
|
|
472
481
|
],
|
|
473
482
|
parameters: [
|
|
474
483
|
{
|
|
@@ -477,32 +486,32 @@ export class BugsnagClient {
|
|
|
477
486
|
description: "Full URL to the event details page in the BugSnag dashboard (web interface)",
|
|
478
487
|
required: true,
|
|
479
488
|
examples: [
|
|
480
|
-
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000"
|
|
489
|
+
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000",
|
|
481
490
|
],
|
|
482
491
|
constraints: [
|
|
483
|
-
"Must be a valid dashboard URL containing project slug and event_id parameter"
|
|
484
|
-
]
|
|
485
|
-
}
|
|
492
|
+
"Must be a valid dashboard URL containing project slug and event_id parameter",
|
|
493
|
+
],
|
|
494
|
+
},
|
|
486
495
|
],
|
|
487
496
|
examples: [
|
|
488
497
|
{
|
|
489
498
|
description: "Get event details from a dashboard URL",
|
|
490
499
|
parameters: {
|
|
491
|
-
link: "https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000"
|
|
500
|
+
link: "https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000",
|
|
492
501
|
},
|
|
493
|
-
expectedOutput: "JSON object with complete event details including stack trace, metadata, and context"
|
|
494
|
-
}
|
|
502
|
+
expectedOutput: "JSON object with complete event details including stack trace, metadata, and context",
|
|
503
|
+
},
|
|
495
504
|
],
|
|
496
505
|
hints: [
|
|
497
506
|
"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
|
-
]
|
|
507
|
+
"This is useful when users share BugSnag dashboard URLs and you need to extract the event data",
|
|
508
|
+
],
|
|
500
509
|
}, async (args, _extra) => {
|
|
501
510
|
if (!args.link)
|
|
502
511
|
throw new Error("link argument is required");
|
|
503
512
|
const url = new URL(args.link);
|
|
504
513
|
const eventId = url.searchParams.get("event_id");
|
|
505
|
-
const projectSlug = url.pathname.split(
|
|
514
|
+
const projectSlug = url.pathname.split("/")[2];
|
|
506
515
|
if (!projectSlug || !eventId)
|
|
507
516
|
throw new Error("Both projectSlug and eventId must be present in the link");
|
|
508
517
|
// get the project id from list of projects
|
|
@@ -524,14 +533,14 @@ export class BugsnagClient {
|
|
|
524
533
|
"Debug recent application errors by filtering for open errors in the last 7 days",
|
|
525
534
|
"Generate error reports for stakeholders by filtering specific error types or severity levels",
|
|
526
535
|
"Monitor error trends over time using date range filters",
|
|
527
|
-
"Find errors affecting specific users or environments using metadata filters"
|
|
536
|
+
"Find errors affecting specific users or environments using metadata filters",
|
|
528
537
|
],
|
|
529
538
|
parameters: [
|
|
530
539
|
{
|
|
531
540
|
name: "filters",
|
|
532
541
|
type: FilterObjectSchema.default({
|
|
533
542
|
"event.since": [{ type: "eq", value: "30d" }],
|
|
534
|
-
"error.status": [{ type: "eq", value: "open" }]
|
|
543
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
535
544
|
}),
|
|
536
545
|
description: "Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields",
|
|
537
546
|
required: false,
|
|
@@ -539,84 +548,92 @@ export class BugsnagClient {
|
|
|
539
548
|
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
540
549
|
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
541
550
|
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
542
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}'
|
|
551
|
+
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
543
552
|
],
|
|
544
553
|
constraints: [
|
|
545
554
|
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
546
555
|
"ISO 8601 times must be in UTC and use extended format",
|
|
547
|
-
"Relative time periods: h (hours), d (days)"
|
|
548
|
-
]
|
|
556
|
+
"Relative time periods: h (hours), d (days)",
|
|
557
|
+
],
|
|
549
558
|
},
|
|
550
559
|
{
|
|
551
560
|
name: "sort",
|
|
552
|
-
type: z
|
|
561
|
+
type: z
|
|
562
|
+
.enum(["first_seen", "last_seen", "events", "users", "unsorted"])
|
|
563
|
+
.default("last_seen"),
|
|
553
564
|
description: "Field to sort the errors by",
|
|
554
565
|
required: false,
|
|
555
|
-
examples: ["last_seen"]
|
|
566
|
+
examples: ["last_seen"],
|
|
556
567
|
},
|
|
557
568
|
{
|
|
558
569
|
name: "direction",
|
|
559
570
|
type: z.enum(["asc", "desc"]).default("desc"),
|
|
560
571
|
description: "Sort direction for ordering results",
|
|
561
572
|
required: false,
|
|
562
|
-
examples: ["desc"]
|
|
573
|
+
examples: ["desc"],
|
|
563
574
|
},
|
|
564
575
|
{
|
|
565
576
|
name: "per_page",
|
|
566
577
|
type: z.number().min(1).max(100).default(30),
|
|
567
578
|
description: "How many results to return per page.",
|
|
568
579
|
required: false,
|
|
569
|
-
examples: ["30", "50", "100"]
|
|
580
|
+
examples: ["30", "50", "100"],
|
|
570
581
|
},
|
|
571
582
|
{
|
|
572
583
|
name: "next",
|
|
573
584
|
type: z.string().url(),
|
|
574
585
|
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
586
|
required: false,
|
|
576
|
-
examples: [
|
|
577
|
-
|
|
587
|
+
examples: [
|
|
588
|
+
"https://api.bugsnag.com/projects/515fb9337c1074f6fd000003/errors?offset=30&per_page=30&sort=last_seen",
|
|
589
|
+
],
|
|
590
|
+
constraints: [
|
|
591
|
+
"Only values provided in the output from this tool can be used. Do not attempt to construct it manually.",
|
|
592
|
+
],
|
|
578
593
|
},
|
|
579
|
-
...(this.projectApiKey
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
594
|
+
...(this.projectApiKey
|
|
595
|
+
? []
|
|
596
|
+
: [
|
|
597
|
+
{
|
|
598
|
+
name: "projectId",
|
|
599
|
+
type: z.string(),
|
|
600
|
+
description: "ID of the project to query for errors",
|
|
601
|
+
required: true,
|
|
602
|
+
},
|
|
603
|
+
]),
|
|
587
604
|
],
|
|
588
605
|
examples: [
|
|
589
606
|
{
|
|
590
607
|
description: "Find errors affecting a specific user in the last 24 hours",
|
|
591
608
|
parameters: {
|
|
592
609
|
filters: {
|
|
593
|
-
"user.email": [{
|
|
594
|
-
"event.since": [{
|
|
595
|
-
}
|
|
610
|
+
"user.email": [{ type: "eq", value: "user@example.com" }],
|
|
611
|
+
"event.since": [{ type: "eq", value: "24h" }],
|
|
612
|
+
},
|
|
596
613
|
},
|
|
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"
|
|
614
|
+
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
615
|
},
|
|
599
616
|
{
|
|
600
617
|
description: "Get the 10 open errors with the most users affected in the last 30 days",
|
|
601
618
|
parameters: {
|
|
602
619
|
filters: {
|
|
603
|
-
"event.since": [{
|
|
604
|
-
"error.status": [{
|
|
620
|
+
"event.since": [{ type: "eq", value: "30d" }],
|
|
621
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
605
622
|
},
|
|
606
623
|
sort: "users",
|
|
607
624
|
direction: "desc",
|
|
608
|
-
per_page: 10
|
|
625
|
+
per_page: 10,
|
|
609
626
|
},
|
|
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"
|
|
627
|
+
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
628
|
},
|
|
612
629
|
{
|
|
613
630
|
description: "Get the next 50 results",
|
|
614
631
|
parameters: {
|
|
615
632
|
next: "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",
|
|
616
|
-
per_page: 50
|
|
633
|
+
per_page: 50,
|
|
617
634
|
},
|
|
618
|
-
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"
|
|
619
|
-
}
|
|
635
|
+
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",
|
|
636
|
+
},
|
|
620
637
|
],
|
|
621
638
|
hints: [
|
|
622
639
|
"Use list_project_event_filters tool first to discover valid filter field names for your project",
|
|
@@ -627,14 +644,14 @@ export class BugsnagClient {
|
|
|
627
644
|
"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
645
|
"This tool returns paged results. The 'count' field indicates the number of results returned in the current page, and the 'total' field indicates the total number of results across all pages.",
|
|
629
646
|
"If the output contains a 'next' value, there are more results available - call this tool again supplying the next URL as a parameter to retrieve the next page.",
|
|
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
|
-
]
|
|
647
|
+
"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
|
+
],
|
|
632
649
|
}, async (args, _extra) => {
|
|
633
650
|
const project = await this.getInputProject(args.projectId);
|
|
634
651
|
// Validate filter keys against cached event fields
|
|
635
652
|
if (args.filters) {
|
|
636
653
|
const eventFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS) || [];
|
|
637
|
-
const validKeys = new Set(eventFields.map(f => f.display_id));
|
|
654
|
+
const validKeys = new Set(eventFields.map((f) => f.display_id));
|
|
638
655
|
for (const key of Object.keys(args.filters)) {
|
|
639
656
|
if (!validKeys.has(key)) {
|
|
640
657
|
throw new Error(`Invalid filter key: ${key}`);
|
|
@@ -642,11 +659,11 @@ export class BugsnagClient {
|
|
|
642
659
|
}
|
|
643
660
|
}
|
|
644
661
|
const defaultFilters = {
|
|
645
|
-
"event.since": [{
|
|
646
|
-
"error.status": [{
|
|
662
|
+
"event.since": [{ type: "eq", value: "30d" }],
|
|
663
|
+
"error.status": [{ type: "eq", value: "open" }],
|
|
647
664
|
};
|
|
648
665
|
const options = {
|
|
649
|
-
filters: { ...defaultFilters, ...args.filters }
|
|
666
|
+
filters: { ...defaultFilters, ...args.filters },
|
|
650
667
|
};
|
|
651
668
|
if (args.sort !== undefined)
|
|
652
669
|
options.sort = args.sort;
|
|
@@ -658,12 +675,12 @@ export class BugsnagClient {
|
|
|
658
675
|
options.next = args.next;
|
|
659
676
|
const response = await this.errorsApi.listProjectErrors(project.id, options);
|
|
660
677
|
const errors = response.body || [];
|
|
661
|
-
const totalCount = response.headers.get(
|
|
662
|
-
const linkHeader = response.headers.get(
|
|
678
|
+
const totalCount = response.headers.get("X-Total-Count");
|
|
679
|
+
const linkHeader = response.headers.get("Link");
|
|
663
680
|
const result = {
|
|
664
681
|
data: errors,
|
|
665
682
|
count: errors.length,
|
|
666
|
-
total: totalCount ? parseInt(totalCount) : undefined,
|
|
683
|
+
total: totalCount ? parseInt(totalCount, 10) : undefined,
|
|
667
684
|
next: linkHeader?.match(/<([^>]+)>/)?.[1],
|
|
668
685
|
};
|
|
669
686
|
return {
|
|
@@ -677,20 +694,20 @@ export class BugsnagClient {
|
|
|
677
694
|
useCases: [
|
|
678
695
|
"Discover what filter fields are available before searching for errors",
|
|
679
696
|
"Find the correct field names for filtering by user, environment, or custom metadata",
|
|
680
|
-
"Understand filter options and data types for building complex queries"
|
|
697
|
+
"Understand filter options and data types for building complex queries",
|
|
681
698
|
],
|
|
682
699
|
parameters: [],
|
|
683
700
|
examples: [
|
|
684
701
|
{
|
|
685
702
|
description: "Get all available filter fields",
|
|
686
703
|
parameters: {},
|
|
687
|
-
expectedOutput: "JSON array of EventField objects containing display_id, custom flag, and filter/pivot options"
|
|
688
|
-
}
|
|
704
|
+
expectedOutput: "JSON array of EventField objects containing display_id, custom flag, and filter/pivot options",
|
|
705
|
+
},
|
|
689
706
|
],
|
|
690
707
|
hints: [
|
|
691
708
|
"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
|
-
]
|
|
709
|
+
"Look for display_id field in the response - these are the field names to use in filters",
|
|
710
|
+
],
|
|
694
711
|
}, async (_args, _extra) => {
|
|
695
712
|
const projectFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS);
|
|
696
713
|
if (!projectFields)
|
|
@@ -706,52 +723,54 @@ export class BugsnagClient {
|
|
|
706
723
|
useCases: [
|
|
707
724
|
"Mark an error as open, fixed or ignored",
|
|
708
725
|
"Discard or un-discard an error",
|
|
709
|
-
"Update the severity of an error"
|
|
726
|
+
"Update the severity of an error",
|
|
710
727
|
],
|
|
711
728
|
parameters: [
|
|
712
|
-
...(this.projectApiKey
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
729
|
+
...(this.projectApiKey
|
|
730
|
+
? []
|
|
731
|
+
: [
|
|
732
|
+
{
|
|
733
|
+
name: "projectId",
|
|
734
|
+
type: z.string(),
|
|
735
|
+
description: "ID of the project that contains the error to be updated",
|
|
736
|
+
required: true,
|
|
737
|
+
},
|
|
738
|
+
]),
|
|
720
739
|
{
|
|
721
740
|
name: "errorId",
|
|
722
741
|
type: z.string(),
|
|
723
742
|
description: "ID of the error to update",
|
|
724
743
|
required: true,
|
|
725
|
-
examples: ["6863e2af8c857c0a5023b411"]
|
|
744
|
+
examples: ["6863e2af8c857c0a5023b411"],
|
|
726
745
|
},
|
|
727
746
|
{
|
|
728
747
|
name: "operation",
|
|
729
748
|
type: z.enum(PERMITTED_UPDATE_OPERATIONS),
|
|
730
749
|
description: "The operation to apply to the error",
|
|
731
750
|
required: true,
|
|
732
|
-
examples: ["fix", "open", "ignore", "discard", "undiscard"]
|
|
733
|
-
}
|
|
751
|
+
examples: ["fix", "open", "ignore", "discard", "undiscard"],
|
|
752
|
+
},
|
|
734
753
|
],
|
|
735
754
|
examples: [
|
|
736
755
|
{
|
|
737
756
|
description: "Mark an error as fixed",
|
|
738
757
|
parameters: {
|
|
739
758
|
errorId: "6863e2af8c857c0a5023b411",
|
|
740
|
-
operation: "fix"
|
|
759
|
+
operation: "fix",
|
|
741
760
|
},
|
|
742
|
-
expectedOutput: "Success response indicating the error was marked as fixed"
|
|
743
|
-
}
|
|
761
|
+
expectedOutput: "Success response indicating the error was marked as fixed",
|
|
762
|
+
},
|
|
744
763
|
],
|
|
745
764
|
hints: [
|
|
746
|
-
"Only use valid operations - BugSnag may reject invalid values"
|
|
765
|
+
"Only use valid operations - BugSnag may reject invalid values",
|
|
747
766
|
],
|
|
748
767
|
readOnly: false,
|
|
749
768
|
idempotent: false,
|
|
750
769
|
}, async (args, _extra) => {
|
|
751
770
|
const { errorId, operation } = args;
|
|
752
771
|
const project = await this.getInputProject(args.projectId);
|
|
753
|
-
let severity
|
|
754
|
-
if (operation ===
|
|
772
|
+
let severity;
|
|
773
|
+
if (operation === "override_severity") {
|
|
755
774
|
// illicit the severity from the user
|
|
756
775
|
const result = await getInput({
|
|
757
776
|
message: "Please provide the new severity for the error (e.g. 'info', 'warning', 'error', 'critical')",
|
|
@@ -760,20 +779,24 @@ export class BugsnagClient {
|
|
|
760
779
|
properties: {
|
|
761
780
|
severity: {
|
|
762
781
|
type: "string",
|
|
763
|
-
enum: [
|
|
764
|
-
description: "The new severity level for the error"
|
|
765
|
-
}
|
|
766
|
-
}
|
|
782
|
+
enum: ["info", "warning", "error"],
|
|
783
|
+
description: "The new severity level for the error",
|
|
784
|
+
},
|
|
785
|
+
},
|
|
767
786
|
},
|
|
768
|
-
required: ["severity"]
|
|
787
|
+
required: ["severity"],
|
|
769
788
|
});
|
|
770
789
|
if (result.action === "accept" && result.content?.severity) {
|
|
771
790
|
severity = result.content.severity;
|
|
772
791
|
}
|
|
773
792
|
}
|
|
774
|
-
const result = await this.updateError(project.id, errorId, operation, {
|
|
793
|
+
const result = await this.updateError(project.id, errorId, operation, {
|
|
794
|
+
severity,
|
|
795
|
+
});
|
|
775
796
|
return {
|
|
776
|
-
content: [
|
|
797
|
+
content: [
|
|
798
|
+
{ type: "text", text: JSON.stringify({ success: result }) },
|
|
799
|
+
],
|
|
777
800
|
};
|
|
778
801
|
});
|
|
779
802
|
register({
|
|
@@ -831,7 +854,7 @@ export class BugsnagClient {
|
|
|
831
854
|
nextUrl: "/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
832
855
|
},
|
|
833
856
|
expectedOutput: "JSON array of build objects with metadata from the next page",
|
|
834
|
-
}
|
|
857
|
+
},
|
|
835
858
|
],
|
|
836
859
|
hints: ["For more detailed results use the Get Build tool"],
|
|
837
860
|
readOnly: true,
|
|
@@ -851,7 +874,7 @@ export class BugsnagClient {
|
|
|
851
874
|
builds,
|
|
852
875
|
next: nextUrl,
|
|
853
876
|
}),
|
|
854
|
-
}
|
|
877
|
+
},
|
|
855
878
|
],
|
|
856
879
|
};
|
|
857
880
|
});
|
|
@@ -1091,10 +1114,12 @@ export class BugsnagClient {
|
|
|
1091
1114
|
registerResources(register) {
|
|
1092
1115
|
register("event", "{id}", async (uri, variables, _extra) => {
|
|
1093
1116
|
return {
|
|
1094
|
-
contents: [
|
|
1117
|
+
contents: [
|
|
1118
|
+
{
|
|
1095
1119
|
uri: uri.href,
|
|
1096
|
-
text: JSON.stringify(await this.getEvent(variables.id))
|
|
1097
|
-
}
|
|
1120
|
+
text: JSON.stringify(await this.getEvent(variables.id)),
|
|
1121
|
+
},
|
|
1122
|
+
],
|
|
1098
1123
|
};
|
|
1099
1124
|
});
|
|
1100
1125
|
}
|