@smartbear/mcp 0.4.0 → 0.6.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 +15 -121
- package/dist/{insight-hub → bugsnag}/client/api/CurrentUser.js +4 -4
- package/dist/{insight-hub → bugsnag}/client/api/Error.js +37 -4
- package/dist/bugsnag/client/api/Project.js +163 -0
- package/dist/{insight-hub → bugsnag}/client/api/base.js +39 -11
- package/dist/{insight-hub → bugsnag}/client/api/filters.js +2 -2
- package/dist/{insight-hub → bugsnag}/client.js +511 -29
- package/dist/common/info.js +1 -1
- package/dist/common/server.js +17 -5
- package/dist/index.js +11 -11
- package/dist/pactflow/client/ai.js +56 -6
- package/dist/pactflow/client/base.js +19 -1
- package/dist/pactflow/client/prompt-utils.js +89 -0
- package/dist/pactflow/client/prompts.js +133 -0
- package/dist/pactflow/client/tools.js +43 -2
- package/dist/pactflow/client/utils.js +70 -0
- package/dist/pactflow/client.js +192 -13
- package/package.json +9 -4
- package/dist/insight-hub/client/api/Project.js +0 -46
- package/dist/package.json +0 -60
- package/dist/tests/unit/common/server.test.js +0 -319
- package/dist/tests/unit/insight-hub/api-utilities.test.js +0 -31
- package/dist/tests/unit/insight-hub/client.test.js +0 -852
- package/dist/tests/unit/insight-hub/filters.test.js +0 -93
- package/dist/tests/unit/pactflow/ai.test.js +0 -21
- package/dist/tests/unit/pactflow/client.test.js +0 -67
- package/dist/tests/unit/pactflow/tools.test.js +0 -34
- package/dist/vitest.config.js +0 -57
- /package/dist/{insight-hub → bugsnag}/client/api/index.js +0 -0
- /package/dist/{insight-hub → bugsnag}/client/configuration.js +0 -0
- /package/dist/{insight-hub → bugsnag}/client/index.js +0 -0
|
@@ -2,16 +2,20 @@ 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
4
|
import { CurrentUserAPI, ErrorAPI, Configuration } from "./client/index.js";
|
|
5
|
-
import { ProjectAPI } from "./client/api/Project.js";
|
|
6
5
|
import { FilterObjectSchema, toQueryString } from "./client/api/filters.js";
|
|
6
|
+
import { ProjectAPI, } from "./client/api/Project.js";
|
|
7
|
+
import { getNextUrlPathFromHeader } from "./client/api/base.js";
|
|
7
8
|
const HUB_PREFIX = "00000";
|
|
8
9
|
const DEFAULT_DOMAIN = "bugsnag.com";
|
|
9
|
-
const HUB_DOMAIN = "
|
|
10
|
+
const HUB_DOMAIN = "bugsnag.smartbear.com";
|
|
10
11
|
const cacheKeys = {
|
|
11
|
-
ORG: "
|
|
12
|
-
PROJECTS: "
|
|
13
|
-
CURRENT_PROJECT: "
|
|
14
|
-
CURRENT_PROJECT_EVENT_FILTERS: "
|
|
12
|
+
ORG: "bugsnag_org",
|
|
13
|
+
PROJECTS: "bugsnag_projects",
|
|
14
|
+
CURRENT_PROJECT: "bugsnag_current_project",
|
|
15
|
+
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
|
|
15
19
|
};
|
|
16
20
|
// Exclude certain event fields from the project event filters to improve agent usage
|
|
17
21
|
const EXCLUDED_EVENT_FIELDS = new Set([
|
|
@@ -25,7 +29,7 @@ const PERMITTED_UPDATE_OPERATIONS = [
|
|
|
25
29
|
"discard",
|
|
26
30
|
"undiscard"
|
|
27
31
|
];
|
|
28
|
-
export class
|
|
32
|
+
export class BugsnagClient {
|
|
29
33
|
currentUserApi;
|
|
30
34
|
errorsApi;
|
|
31
35
|
cache;
|
|
@@ -33,8 +37,8 @@ export class InsightHubClient {
|
|
|
33
37
|
projectApiKey;
|
|
34
38
|
apiEndpoint;
|
|
35
39
|
appEndpoint;
|
|
36
|
-
name = "
|
|
37
|
-
prefix = "
|
|
40
|
+
name = "BugSnag";
|
|
41
|
+
prefix = "bugsnag";
|
|
38
42
|
constructor(token, projectApiKey, endpoint) {
|
|
39
43
|
this.apiEndpoint = this.getEndpoint("api", projectApiKey, endpoint);
|
|
40
44
|
this.appEndpoint = this.getEndpoint("app", projectApiKey, endpoint);
|
|
@@ -50,14 +54,32 @@ export class InsightHubClient {
|
|
|
50
54
|
});
|
|
51
55
|
this.currentUserApi = new CurrentUserAPI(config);
|
|
52
56
|
this.errorsApi = new ErrorAPI(config);
|
|
53
|
-
this.cache = new NodeCache(
|
|
57
|
+
this.cache = new NodeCache({
|
|
58
|
+
stdTTL: 24 * 60 * 60, // default cache TTL of 24 hours
|
|
59
|
+
});
|
|
54
60
|
this.projectApi = new ProjectAPI(config);
|
|
55
61
|
this.projectApiKey = projectApiKey;
|
|
56
62
|
}
|
|
57
63
|
async initialize() {
|
|
58
64
|
// Trigger caching of org and projects
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
try {
|
|
66
|
+
await this.getProjects();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// Swallow auth errors here to allow the tools to be registered for visibility, even if the token is invalid
|
|
70
|
+
console.error("Unable to connect to BugSnag APIs, the BugSnag tools will not work. Check your configured BugSnag auth token.", error);
|
|
71
|
+
}
|
|
72
|
+
if (this.projectApiKey) {
|
|
73
|
+
try {
|
|
74
|
+
await this.getCurrentProject();
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Clear the project API key to allow tools to work across all projects
|
|
78
|
+
this.projectApiKey = undefined;
|
|
79
|
+
console.error("Unable to find your configured BugSnag project, the BugSnag tools will continue to work across all projects in your organization. " +
|
|
80
|
+
"Check your configured BugSnag project API key.", error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
61
83
|
}
|
|
62
84
|
getHost(apiKey, subdomain) {
|
|
63
85
|
if (apiKey && apiKey.startsWith(HUB_PREFIX)) {
|
|
@@ -127,10 +149,7 @@ export class InsightHubClient {
|
|
|
127
149
|
let projects = this.cache.get(cacheKeys.PROJECTS);
|
|
128
150
|
if (!projects) {
|
|
129
151
|
const org = await this.getOrganization();
|
|
130
|
-
const
|
|
131
|
-
paginate: true
|
|
132
|
-
};
|
|
133
|
-
const response = await this.currentUserApi.getOrganizationProjects(org.id, options);
|
|
152
|
+
const response = await this.currentUserApi.getOrganizationProjects(org.id);
|
|
134
153
|
projects = response.body || [];
|
|
135
154
|
this.cache.set(cacheKeys.PROJECTS, projects);
|
|
136
155
|
}
|
|
@@ -192,6 +211,83 @@ export class InsightHubClient {
|
|
|
192
211
|
return currentProject;
|
|
193
212
|
}
|
|
194
213
|
}
|
|
214
|
+
async listBuilds(projectId, opts) {
|
|
215
|
+
const response = await this.projectApi.listBuilds(projectId, opts);
|
|
216
|
+
const fetchedBuilds = response.body || [];
|
|
217
|
+
const nextUrl = getNextUrlPathFromHeader(response.headers, this.apiEndpoint);
|
|
218
|
+
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
219
|
+
const formattedBuilds = fetchedBuilds.map((b) => this.addStabilityData(b, stabilityTargets));
|
|
220
|
+
return { builds: formattedBuilds, nextUrl };
|
|
221
|
+
}
|
|
222
|
+
async getBuild(projectId, buildId) {
|
|
223
|
+
const cacheKey = `${cacheKeys.BUILD}_${buildId}`;
|
|
224
|
+
const build = this.cache.get(cacheKey);
|
|
225
|
+
if (build)
|
|
226
|
+
return build;
|
|
227
|
+
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId)).body;
|
|
228
|
+
if (!fetchedBuild)
|
|
229
|
+
throw new Error(`No build for ${buildId} found.`);
|
|
230
|
+
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
231
|
+
const formattedBuild = this.addStabilityData(fetchedBuild, stabilityTargets);
|
|
232
|
+
this.cache.set(cacheKey, formattedBuild, 5 * 60);
|
|
233
|
+
return formattedBuild;
|
|
234
|
+
}
|
|
235
|
+
async listReleases(projectId, opts) {
|
|
236
|
+
const response = await this.projectApi.listReleases(projectId, opts);
|
|
237
|
+
const fetchedReleases = response.body || [];
|
|
238
|
+
const nextUrl = getNextUrlPathFromHeader(response.headers, this.apiEndpoint);
|
|
239
|
+
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
240
|
+
const formattedReleases = fetchedReleases.map((r) => this.addStabilityData(r, stabilityTargets));
|
|
241
|
+
return { releases: formattedReleases, nextUrl };
|
|
242
|
+
}
|
|
243
|
+
async getRelease(projectId, releaseId) {
|
|
244
|
+
const cacheKey = `${cacheKeys.RELEASE}_${releaseId}`;
|
|
245
|
+
const release = this.cache.get(cacheKey);
|
|
246
|
+
if (release)
|
|
247
|
+
return release;
|
|
248
|
+
const fetchedRelease = (await this.projectApi.getRelease(releaseId)).body;
|
|
249
|
+
if (!fetchedRelease)
|
|
250
|
+
throw new Error(`No release for ${releaseId} found.`);
|
|
251
|
+
const stabilityTargets = await this.getProjectStabilityTargets(projectId);
|
|
252
|
+
const formattedRelease = this.addStabilityData(fetchedRelease, stabilityTargets);
|
|
253
|
+
this.cache.set(cacheKey, formattedRelease, 5 * 60);
|
|
254
|
+
return formattedRelease;
|
|
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;
|
|
264
|
+
}
|
|
265
|
+
async getProjectStabilityTargets(projectId) {
|
|
266
|
+
return await this.projectApi.getProjectStabilityTargets(projectId);
|
|
267
|
+
}
|
|
268
|
+
addStabilityData(source, stabilityTargets) {
|
|
269
|
+
const { stability_target_type, target_stability, critical_stability } = stabilityTargets;
|
|
270
|
+
const user_stability = source.accumulative_daily_users_seen === 0 // avoid division by zero
|
|
271
|
+
? 0
|
|
272
|
+
: (source.accumulative_daily_users_seen - source.accumulative_daily_users_with_unhandled) /
|
|
273
|
+
source.accumulative_daily_users_seen;
|
|
274
|
+
const session_stability = source.total_sessions_count === 0 // avoid division by zero
|
|
275
|
+
? 0
|
|
276
|
+
: (source.total_sessions_count - source.unhandled_sessions_count) / source.total_sessions_count;
|
|
277
|
+
const stabilityMetric = stability_target_type === "user" ? user_stability : session_stability;
|
|
278
|
+
const meets_target_stability = stabilityMetric >= target_stability.value;
|
|
279
|
+
const meets_critical_stability = stabilityMetric >= critical_stability.value;
|
|
280
|
+
return {
|
|
281
|
+
...source,
|
|
282
|
+
user_stability,
|
|
283
|
+
session_stability,
|
|
284
|
+
stability_target_type,
|
|
285
|
+
target_stability: target_stability.value,
|
|
286
|
+
critical_stability: critical_stability.value,
|
|
287
|
+
meets_target_stability,
|
|
288
|
+
meets_critical_stability,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
195
291
|
registerTools(register, getInput) {
|
|
196
292
|
if (!this.projectApiKey) {
|
|
197
293
|
register({
|
|
@@ -318,7 +414,7 @@ export class InsightHubClient {
|
|
|
318
414
|
}
|
|
319
415
|
],
|
|
320
416
|
hints: [
|
|
321
|
-
"Error IDs can be found using the List Errors tool",
|
|
417
|
+
"Error IDs can be found using the List Project Errors tool",
|
|
322
418
|
"Use this after filtering errors to get detailed information about specific errors",
|
|
323
419
|
"If you used a filter to get this error, you can pass the same filters here to restrict the results or apply further filters",
|
|
324
420
|
"The URL provided in the response points should be shown to the user in all cases as it allows them to view the error in the dashboard and perform further analysis",
|
|
@@ -378,7 +474,7 @@ export class InsightHubClient {
|
|
|
378
474
|
{
|
|
379
475
|
name: "link",
|
|
380
476
|
type: z.string(),
|
|
381
|
-
description: "Full URL to the event details page in the
|
|
477
|
+
description: "Full URL to the event details page in the BugSnag dashboard (web interface)",
|
|
382
478
|
required: true,
|
|
383
479
|
examples: [
|
|
384
480
|
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000"
|
|
@@ -399,7 +495,7 @@ export class InsightHubClient {
|
|
|
399
495
|
],
|
|
400
496
|
hints: [
|
|
401
497
|
"The URL must contain both project slug in the path and event_id in query parameters",
|
|
402
|
-
"This is useful when users share
|
|
498
|
+
"This is useful when users share BugSnag dashboard URLs and you need to extract the event data"
|
|
403
499
|
]
|
|
404
500
|
}, async (args, _extra) => {
|
|
405
501
|
if (!args.link)
|
|
@@ -420,10 +516,9 @@ export class InsightHubClient {
|
|
|
420
516
|
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
421
517
|
};
|
|
422
518
|
});
|
|
423
|
-
// Dynamically infer the filters schema from cached project event fields
|
|
424
519
|
register({
|
|
425
520
|
title: "List Project Errors",
|
|
426
|
-
summary: "List and search errors in a project using customizable filters",
|
|
521
|
+
summary: "List and search errors in a project using customizable filters and pagination",
|
|
427
522
|
purpose: "Retrieve filtered list of errors from a project for analysis, debugging, and reporting",
|
|
428
523
|
useCases: [
|
|
429
524
|
"Debug recent application errors by filtering for open errors in the last 7 days",
|
|
@@ -434,8 +529,11 @@ export class InsightHubClient {
|
|
|
434
529
|
parameters: [
|
|
435
530
|
{
|
|
436
531
|
name: "filters",
|
|
437
|
-
type: FilterObjectSchema
|
|
438
|
-
|
|
532
|
+
type: FilterObjectSchema.default({
|
|
533
|
+
"event.since": [{ type: "eq", value: "30d" }],
|
|
534
|
+
"error.status": [{ type: "eq", value: "open" }]
|
|
535
|
+
}),
|
|
536
|
+
description: "Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields",
|
|
439
537
|
required: false,
|
|
440
538
|
examples: [
|
|
441
539
|
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
@@ -449,6 +547,35 @@ export class InsightHubClient {
|
|
|
449
547
|
"Relative time periods: h (hours), d (days)"
|
|
450
548
|
]
|
|
451
549
|
},
|
|
550
|
+
{
|
|
551
|
+
name: "sort",
|
|
552
|
+
type: z.enum(["first_seen", "last_seen", "events", "users", "unsorted"]).default("last_seen"),
|
|
553
|
+
description: "Field to sort the errors by",
|
|
554
|
+
required: false,
|
|
555
|
+
examples: ["last_seen"]
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: "direction",
|
|
559
|
+
type: z.enum(["asc", "desc"]).default("desc"),
|
|
560
|
+
description: "Sort direction for ordering results",
|
|
561
|
+
required: false,
|
|
562
|
+
examples: ["desc"]
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
name: "per_page",
|
|
566
|
+
type: z.number().min(1).max(100).default(30),
|
|
567
|
+
description: "How many results to return per page.",
|
|
568
|
+
required: false,
|
|
569
|
+
examples: ["30", "50", "100"]
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
name: "next",
|
|
573
|
+
type: z.string().url(),
|
|
574
|
+
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
|
+
required: false,
|
|
576
|
+
examples: ["https://api.bugsnag.com/projects/515fb9337c1074f6fd000003/errors?offset=30&per_page=30&sort=last_seen"],
|
|
577
|
+
constraints: ["Only values provided in the output from this tool can be used. Do not attempt to construct it manually."]
|
|
578
|
+
},
|
|
452
579
|
...(this.projectApiKey ? [] : [
|
|
453
580
|
{
|
|
454
581
|
name: "projectId",
|
|
@@ -467,7 +594,28 @@ export class InsightHubClient {
|
|
|
467
594
|
"event.since": [{ "type": "eq", "value": "24h" }]
|
|
468
595
|
}
|
|
469
596
|
},
|
|
470
|
-
expectedOutput: "JSON object with a list of errors in the 'data' field, and
|
|
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"
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
description: "Get the 10 open errors with the most users affected in the last 30 days",
|
|
601
|
+
parameters: {
|
|
602
|
+
filters: {
|
|
603
|
+
"event.since": [{ "type": "eq", "value": "30d" }],
|
|
604
|
+
"error.status": [{ "type": "eq", "value": "open" }]
|
|
605
|
+
},
|
|
606
|
+
sort: "users",
|
|
607
|
+
direction: "desc",
|
|
608
|
+
per_page: 10
|
|
609
|
+
},
|
|
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"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
description: "Get the next 50 results",
|
|
614
|
+
parameters: {
|
|
615
|
+
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
|
|
617
|
+
},
|
|
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"
|
|
471
619
|
}
|
|
472
620
|
],
|
|
473
621
|
hints: [
|
|
@@ -475,13 +623,17 @@ export class InsightHubClient {
|
|
|
475
623
|
"Combine multiple filters to narrow results - filters are applied with AND logic",
|
|
476
624
|
"For time filters: use relative format (7d, 24h) for recent periods or ISO 8601 UTC format (2018-05-20T00:00:00Z) for specific dates",
|
|
477
625
|
"Common time filters: event.since (from this time), event.before (until this time)",
|
|
478
|
-
"
|
|
626
|
+
"The 'event.since' filter and 'error.status' filters are always applied and if not specified are set to '30d' and 'open' respectively",
|
|
627
|
+
"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 '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
|
+
"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."
|
|
479
631
|
]
|
|
480
632
|
}, async (args, _extra) => {
|
|
481
633
|
const project = await this.getInputProject(args.projectId);
|
|
482
|
-
//
|
|
483
|
-
const eventFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS) || [];
|
|
634
|
+
// Validate filter keys against cached event fields
|
|
484
635
|
if (args.filters) {
|
|
636
|
+
const eventFields = this.cache.get(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS) || [];
|
|
485
637
|
const validKeys = new Set(eventFields.map(f => f.display_id));
|
|
486
638
|
for (const key of Object.keys(args.filters)) {
|
|
487
639
|
if (!validKeys.has(key)) {
|
|
@@ -489,11 +641,30 @@ export class InsightHubClient {
|
|
|
489
641
|
}
|
|
490
642
|
}
|
|
491
643
|
}
|
|
492
|
-
const
|
|
644
|
+
const defaultFilters = {
|
|
645
|
+
"event.since": [{ "type": "eq", "value": "30d" }],
|
|
646
|
+
"error.status": [{ "type": "eq", "value": "open" }]
|
|
647
|
+
};
|
|
648
|
+
const options = {
|
|
649
|
+
filters: { ...defaultFilters, ...args.filters }
|
|
650
|
+
};
|
|
651
|
+
if (args.sort !== undefined)
|
|
652
|
+
options.sort = args.sort;
|
|
653
|
+
if (args.direction !== undefined)
|
|
654
|
+
options.direction = args.direction;
|
|
655
|
+
if (args.per_page !== undefined)
|
|
656
|
+
options.per_page = args.per_page;
|
|
657
|
+
if (args.next !== undefined)
|
|
658
|
+
options.next = args.next;
|
|
659
|
+
const response = await this.errorsApi.listProjectErrors(project.id, options);
|
|
493
660
|
const errors = response.body || [];
|
|
661
|
+
const totalCount = response.headers.get('X-Total-Count');
|
|
662
|
+
const linkHeader = response.headers.get('Link');
|
|
494
663
|
const result = {
|
|
495
664
|
data: errors,
|
|
496
665
|
count: errors.length,
|
|
666
|
+
total: totalCount ? parseInt(totalCount) : undefined,
|
|
667
|
+
next: linkHeader?.match(/<([^>]+)>/)?.[1],
|
|
497
668
|
};
|
|
498
669
|
return {
|
|
499
670
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
@@ -572,7 +743,7 @@ export class InsightHubClient {
|
|
|
572
743
|
}
|
|
573
744
|
],
|
|
574
745
|
hints: [
|
|
575
|
-
"Only use valid operations -
|
|
746
|
+
"Only use valid operations - BugSnag may reject invalid values"
|
|
576
747
|
],
|
|
577
748
|
readOnly: false,
|
|
578
749
|
idempotent: false,
|
|
@@ -605,6 +776,317 @@ export class InsightHubClient {
|
|
|
605
776
|
content: [{ type: "text", text: JSON.stringify({ success: result }) }],
|
|
606
777
|
};
|
|
607
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,
|
|
845
|
+
});
|
|
846
|
+
return {
|
|
847
|
+
content: [
|
|
848
|
+
{
|
|
849
|
+
type: "text",
|
|
850
|
+
text: JSON.stringify({
|
|
851
|
+
builds,
|
|
852
|
+
next: nextUrl,
|
|
853
|
+
}),
|
|
854
|
+
}
|
|
855
|
+
],
|
|
856
|
+
};
|
|
857
|
+
});
|
|
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
|
+
register({
|
|
908
|
+
title: "List Releases",
|
|
909
|
+
summary: "List releases for a project with optional filtering by release stage",
|
|
910
|
+
purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
|
|
911
|
+
useCases: [
|
|
912
|
+
"View recent releases to correlate with error spikes",
|
|
913
|
+
"Filter releases by stage (e.g. production, staging) for targeted analysis",
|
|
914
|
+
],
|
|
915
|
+
parameters: [
|
|
916
|
+
...(this.projectApiKey
|
|
917
|
+
? []
|
|
918
|
+
: [
|
|
919
|
+
{
|
|
920
|
+
name: "projectId",
|
|
921
|
+
type: z.string(),
|
|
922
|
+
description: "ID of the project to list releases for",
|
|
923
|
+
required: true,
|
|
924
|
+
},
|
|
925
|
+
]),
|
|
926
|
+
{
|
|
927
|
+
name: "releaseStage",
|
|
928
|
+
type: z.string(),
|
|
929
|
+
description: "Filter releases by this stage (e.g. production, staging)",
|
|
930
|
+
required: false,
|
|
931
|
+
examples: ["production", "staging"],
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
name: "visibleOnly",
|
|
935
|
+
type: z.boolean().default(true),
|
|
936
|
+
description: "Whether to only include releases that are marked as visible (default: true)",
|
|
937
|
+
required: true,
|
|
938
|
+
examples: ["true", "false"],
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: "nextUrl",
|
|
942
|
+
type: z.string(),
|
|
943
|
+
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.",
|
|
944
|
+
required: false,
|
|
945
|
+
examples: [
|
|
946
|
+
"/projects/515fb9337c1074f6fd000003/releases?offset=30&per_page=30",
|
|
947
|
+
],
|
|
948
|
+
},
|
|
949
|
+
],
|
|
950
|
+
examples: [
|
|
951
|
+
{
|
|
952
|
+
description: "List all releases for a project",
|
|
953
|
+
parameters: {},
|
|
954
|
+
expectedOutput: "JSON array of release objects with metadata",
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
description: "List production releases for a project",
|
|
958
|
+
parameters: {
|
|
959
|
+
releaseStage: "production",
|
|
960
|
+
},
|
|
961
|
+
expectedOutput: "JSON array of release objects in the production stage",
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
description: "Get the next page of results",
|
|
965
|
+
parameters: {
|
|
966
|
+
nextUrl: "/projects/515fb9337c1074f6fd000003/releases?offset=30&per_page=30",
|
|
967
|
+
},
|
|
968
|
+
expectedOutput: "JSON array of release objects with metadata from the next page",
|
|
969
|
+
},
|
|
970
|
+
],
|
|
971
|
+
hints: ["For more detailed results use the Get Release tool"],
|
|
972
|
+
readOnly: true,
|
|
973
|
+
idempotent: true,
|
|
974
|
+
outputFormat: "JSON array of release summary objects with metadata",
|
|
975
|
+
}, async (args, _extra) => {
|
|
976
|
+
const { releases, nextUrl } = await this.listReleases((await this.getInputProject(args.projectId)).id, {
|
|
977
|
+
release_stage_name: args.releaseStage ?? "production",
|
|
978
|
+
visible_only: args.visibleOnly,
|
|
979
|
+
next_url: args.nextUrl ?? null,
|
|
980
|
+
});
|
|
981
|
+
return {
|
|
982
|
+
content: [
|
|
983
|
+
{
|
|
984
|
+
type: "text",
|
|
985
|
+
text: JSON.stringify({
|
|
986
|
+
releases,
|
|
987
|
+
next: nextUrl ?? null,
|
|
988
|
+
}),
|
|
989
|
+
},
|
|
990
|
+
],
|
|
991
|
+
};
|
|
992
|
+
});
|
|
993
|
+
register({
|
|
994
|
+
title: "Get Release",
|
|
995
|
+
summary: "Get more details for a specific release by its ID",
|
|
996
|
+
purpose: "Retrieve detailed information about a release for analysis and debugging",
|
|
997
|
+
useCases: [
|
|
998
|
+
"View release metadata such as version, source control info, and error counts",
|
|
999
|
+
"Analyze a specific release to correlate with error spikes or deployments",
|
|
1000
|
+
"See the stability targets for a project and if the release meets them",
|
|
1001
|
+
],
|
|
1002
|
+
parameters: [
|
|
1003
|
+
...(this.projectApiKey
|
|
1004
|
+
? []
|
|
1005
|
+
: [
|
|
1006
|
+
{
|
|
1007
|
+
name: "projectId",
|
|
1008
|
+
type: z.string(),
|
|
1009
|
+
description: "ID of the project containing the release",
|
|
1010
|
+
required: true,
|
|
1011
|
+
},
|
|
1012
|
+
]),
|
|
1013
|
+
{
|
|
1014
|
+
name: "releaseId",
|
|
1015
|
+
type: z.string(),
|
|
1016
|
+
description: "ID of the release to retrieve",
|
|
1017
|
+
required: true,
|
|
1018
|
+
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
1019
|
+
},
|
|
1020
|
+
],
|
|
1021
|
+
examples: [
|
|
1022
|
+
{
|
|
1023
|
+
description: "Get details for a specific release",
|
|
1024
|
+
parameters: {
|
|
1025
|
+
releaseId: "5f8d0d55c9e77c0017a1b2c3",
|
|
1026
|
+
},
|
|
1027
|
+
expectedOutput: "JSON object with release details including version, source control info, error counts and stability data.",
|
|
1028
|
+
},
|
|
1029
|
+
],
|
|
1030
|
+
hints: ["Release IDs can be found using the List releases tool"],
|
|
1031
|
+
readOnly: true,
|
|
1032
|
+
idempotent: true,
|
|
1033
|
+
outputFormat: "JSON object containing release details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
1034
|
+
}, async (args, _extra) => {
|
|
1035
|
+
if (!args.releaseId)
|
|
1036
|
+
throw new Error("releaseId argument is required");
|
|
1037
|
+
const release = await this.getRelease((await this.getInputProject(args.projectId)).id, args.releaseId);
|
|
1038
|
+
return {
|
|
1039
|
+
content: [{ type: "text", text: JSON.stringify(release) }],
|
|
1040
|
+
};
|
|
1041
|
+
});
|
|
1042
|
+
register({
|
|
1043
|
+
title: "List Builds in Release",
|
|
1044
|
+
summary: "List builds associated with a specific release",
|
|
1045
|
+
purpose: "Retrieve a list of builds for a given release to analyze deployment history and associated errors",
|
|
1046
|
+
useCases: [
|
|
1047
|
+
"View builds within a release to correlate with error spikes",
|
|
1048
|
+
"Analyze the composition of a release by examining its builds",
|
|
1049
|
+
],
|
|
1050
|
+
parameters: [
|
|
1051
|
+
...(this.projectApiKey
|
|
1052
|
+
? []
|
|
1053
|
+
: [
|
|
1054
|
+
{
|
|
1055
|
+
name: "projectId",
|
|
1056
|
+
type: z.string(),
|
|
1057
|
+
description: "ID of the project containing the release",
|
|
1058
|
+
required: true,
|
|
1059
|
+
},
|
|
1060
|
+
]),
|
|
1061
|
+
{
|
|
1062
|
+
name: "releaseId",
|
|
1063
|
+
type: z.string(),
|
|
1064
|
+
description: "ID of the release to list builds for",
|
|
1065
|
+
required: true,
|
|
1066
|
+
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
1067
|
+
},
|
|
1068
|
+
],
|
|
1069
|
+
examples: [
|
|
1070
|
+
{
|
|
1071
|
+
description: "List all builds in a specific release",
|
|
1072
|
+
parameters: {
|
|
1073
|
+
releaseId: "5f8d0d55c9e77c0017a1b2c3",
|
|
1074
|
+
},
|
|
1075
|
+
expectedOutput: "JSON array of build objects with metadata",
|
|
1076
|
+
},
|
|
1077
|
+
],
|
|
1078
|
+
hints: ["Release IDs can be found using the List releases tool"],
|
|
1079
|
+
readOnly: true,
|
|
1080
|
+
idempotent: true,
|
|
1081
|
+
outputFormat: "JSON array of build summary objects with metadata",
|
|
1082
|
+
}, async (args, _extra) => {
|
|
1083
|
+
if (!args.releaseId)
|
|
1084
|
+
throw new Error("releaseId argument is required");
|
|
1085
|
+
const builds = await this.listBuildsInRelease(args.releaseId);
|
|
1086
|
+
return {
|
|
1087
|
+
content: [{ type: "text", text: JSON.stringify(builds) }],
|
|
1088
|
+
};
|
|
1089
|
+
});
|
|
608
1090
|
}
|
|
609
1091
|
registerResources(register) {
|
|
610
1092
|
register("event", "{id}", async (uri, variables, _extra) => {
|