@smartbear/mcp 0.7.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 +19 -2
- package/dist/api-hub/client/api.js +154 -20
- package/dist/api-hub/client/registry-types.js +14 -0
- package/dist/api-hub/client/tools.js +13 -1
- package/dist/api-hub/client.js +6 -0
- package/dist/bugsnag/client/api/CurrentUser.js +5 -5
- package/dist/bugsnag/client/api/Error.js +12 -24
- package/dist/bugsnag/client/api/Project.js +16 -23
- package/dist/bugsnag/client/api/base.js +17 -5
- package/dist/bugsnag/client.js +131 -248
- package/dist/common/server.js +4 -1
- package/dist/index.js +8 -1
- package/dist/pactflow/client/tools.js +9 -9
- package/dist/pactflow/client.js +7 -6
- package/dist/zephyr/client.js +16 -0
- package/dist/zephyr/common/api-client.js +27 -0
- package/dist/zephyr/common/auth-service.js +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 +3 -2
package/dist/bugsnag/client.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
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 { getNextUrlPathFromHeader } from "./client/api/base.js";
|
|
5
4
|
import { FilterObjectSchema, toQueryString, } from "./client/api/filters.js";
|
|
6
5
|
import { ProjectAPI, } from "./client/api/Project.js";
|
|
7
6
|
import { Configuration, CurrentUserAPI, ErrorAPI } from "./client/index.js";
|
|
@@ -13,9 +12,6 @@ const cacheKeys = {
|
|
|
13
12
|
PROJECTS: "bugsnag_projects",
|
|
14
13
|
CURRENT_PROJECT: "bugsnag_current_project",
|
|
15
14
|
CURRENT_PROJECT_EVENT_FILTERS: "bugsnag_current_project_event_filters",
|
|
16
|
-
BUILD: "bugsnag_build", // + buildId
|
|
17
|
-
RELEASE: "bugsnag_release", // + releaseId
|
|
18
|
-
BUILDS_IN_RELEASE: "bugsnag_builds_in_release", // + releaseId
|
|
19
15
|
};
|
|
20
16
|
// Exclude certain event fields from the project event filters to improve agent usage
|
|
21
17
|
const EXCLUDED_EVENT_FIELDS = new Set([
|
|
@@ -216,61 +212,62 @@ export class BugsnagClient {
|
|
|
216
212
|
}
|
|
217
213
|
async listBuilds(projectId, opts) {
|
|
218
214
|
const response = await this.projectApi.listBuilds(projectId, opts);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
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
|
+
};
|
|
224
225
|
}
|
|
225
226
|
async getBuild(projectId, buildId) {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
if (build)
|
|
229
|
-
return build;
|
|
230
|
-
const fetchedBuild = (await this.projectApi.getBuild(projectId, buildId))
|
|
231
|
-
.body;
|
|
232
|
-
if (!fetchedBuild)
|
|
227
|
+
const response = await this.projectApi.getBuild(projectId, buildId);
|
|
228
|
+
if (!response.body)
|
|
233
229
|
throw new Error(`No build for ${buildId} found.`);
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
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) };
|
|
238
234
|
}
|
|
239
235
|
async listReleases(projectId, opts) {
|
|
240
236
|
const response = await this.projectApi.listReleases(projectId, opts);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
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
|
+
};
|
|
246
247
|
}
|
|
247
248
|
async getRelease(projectId, releaseId) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
if (release)
|
|
251
|
-
return release;
|
|
252
|
-
const fetchedRelease = (await this.projectApi.getRelease(releaseId)).body;
|
|
253
|
-
if (!fetchedRelease)
|
|
249
|
+
const response = await this.projectApi.getRelease(releaseId);
|
|
250
|
+
if (!response.body)
|
|
254
251
|
throw new Error(`No release for ${releaseId} found.`);
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return
|
|
259
|
-
}
|
|
260
|
-
async listBuildsInRelease(releaseId) {
|
|
261
|
-
const cacheKey = `${cacheKeys.BUILDS_IN_RELEASE}_${releaseId}`;
|
|
262
|
-
const builds = this.cache.get(cacheKey);
|
|
263
|
-
if (builds)
|
|
264
|
-
return builds;
|
|
265
|
-
const fetchedBuilds = (await this.projectApi.listBuildsInRelease(releaseId)).body || [];
|
|
266
|
-
this.cache.set(cacheKey, fetchedBuilds, 5 * 60);
|
|
267
|
-
return fetchedBuilds;
|
|
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) };
|
|
268
256
|
}
|
|
269
|
-
async
|
|
270
|
-
|
|
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
|
+
};
|
|
271
269
|
}
|
|
272
|
-
addStabilityData(source,
|
|
273
|
-
const { stability_target_type, target_stability, critical_stability } = stabilityTargets;
|
|
270
|
+
addStabilityData(source, project) {
|
|
274
271
|
const user_stability = source.accumulative_daily_users_seen === 0 // avoid division by zero
|
|
275
272
|
? 0
|
|
276
273
|
: (source.accumulative_daily_users_seen -
|
|
@@ -280,16 +277,18 @@ export class BugsnagClient {
|
|
|
280
277
|
? 0
|
|
281
278
|
: (source.total_sessions_count - source.unhandled_sessions_count) /
|
|
282
279
|
source.total_sessions_count;
|
|
283
|
-
const stabilityMetric = stability_target_type === "user"
|
|
284
|
-
|
|
285
|
-
|
|
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;
|
|
286
285
|
return {
|
|
287
286
|
...source,
|
|
288
287
|
user_stability,
|
|
289
288
|
session_stability,
|
|
290
|
-
stability_target_type,
|
|
291
|
-
target_stability: target_stability.value,
|
|
292
|
-
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,
|
|
293
292
|
meets_target_stability,
|
|
294
293
|
meets_critical_stability,
|
|
295
294
|
};
|
|
@@ -307,7 +306,7 @@ export class BugsnagClient {
|
|
|
307
306
|
],
|
|
308
307
|
parameters: [
|
|
309
308
|
{
|
|
310
|
-
name: "
|
|
309
|
+
name: "pageSize",
|
|
311
310
|
type: z.number(),
|
|
312
311
|
description: "Number of projects to return per page for pagination",
|
|
313
312
|
required: false,
|
|
@@ -325,7 +324,7 @@ export class BugsnagClient {
|
|
|
325
324
|
{
|
|
326
325
|
description: "Get first 10 projects",
|
|
327
326
|
parameters: {
|
|
328
|
-
|
|
327
|
+
pageSize: 10,
|
|
329
328
|
page: 1,
|
|
330
329
|
},
|
|
331
330
|
expectedOutput: "JSON array of project objects with IDs, names, and metadata",
|
|
@@ -347,8 +346,8 @@ export class BugsnagClient {
|
|
|
347
346
|
content: [{ type: "text", text: "No projects found." }],
|
|
348
347
|
};
|
|
349
348
|
}
|
|
350
|
-
if (args.
|
|
351
|
-
const pageSize = args.
|
|
349
|
+
if (args.pageSize || args.page) {
|
|
350
|
+
const pageSize = args.pageSize || 10;
|
|
352
351
|
const page = args.page || 1;
|
|
353
352
|
projects = projects.slice((page - 1) * pageSize, page * pageSize);
|
|
354
353
|
}
|
|
@@ -451,9 +450,7 @@ export class BugsnagClient {
|
|
|
451
450
|
// Get the latest event for this error using the events endpoint with filters
|
|
452
451
|
let latestEvent = null;
|
|
453
452
|
try {
|
|
454
|
-
|
|
455
|
-
const events = eventsResponse.body || [];
|
|
456
|
-
latestEvent = events[0] || null;
|
|
453
|
+
latestEvent = (await this.errorsApi.getLatestEventOnProject(project.id, listEventsQueryString)).body;
|
|
457
454
|
}
|
|
458
455
|
catch (e) {
|
|
459
456
|
console.warn("Failed to fetch latest event:", e);
|
|
@@ -573,14 +570,14 @@ export class BugsnagClient {
|
|
|
573
570
|
examples: ["desc"],
|
|
574
571
|
},
|
|
575
572
|
{
|
|
576
|
-
name: "
|
|
573
|
+
name: "perPage",
|
|
577
574
|
type: z.number().min(1).max(100).default(30),
|
|
578
575
|
description: "How many results to return per page.",
|
|
579
576
|
required: false,
|
|
580
577
|
examples: ["30", "50", "100"],
|
|
581
578
|
},
|
|
582
579
|
{
|
|
583
|
-
name: "
|
|
580
|
+
name: "nextUrl",
|
|
584
581
|
type: z.string().url(),
|
|
585
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.",
|
|
586
583
|
required: false,
|
|
@@ -622,17 +619,17 @@ export class BugsnagClient {
|
|
|
622
619
|
},
|
|
623
620
|
sort: "users",
|
|
624
621
|
direction: "desc",
|
|
625
|
-
|
|
622
|
+
perPage: 10,
|
|
626
623
|
},
|
|
627
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",
|
|
628
625
|
},
|
|
629
626
|
{
|
|
630
627
|
description: "Get the next 50 results",
|
|
631
628
|
parameters: {
|
|
632
|
-
|
|
633
|
-
|
|
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,
|
|
634
631
|
},
|
|
635
|
-
expectedOutput: "JSON object with a list of errors
|
|
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",
|
|
636
633
|
},
|
|
637
634
|
],
|
|
638
635
|
hints: [
|
|
@@ -642,8 +639,8 @@ export class BugsnagClient {
|
|
|
642
639
|
"Common time filters: event.since (from this time), event.before (until this time)",
|
|
643
640
|
"The 'event.since' filter and 'error.status' filters are always applied and if not specified are set to '30d' and 'open' respectively",
|
|
644
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",
|
|
645
|
-
"This tool returns paged results. The '
|
|
646
|
-
"If the output contains a '
|
|
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.",
|
|
647
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.",
|
|
648
645
|
],
|
|
649
646
|
}, async (args, _extra) => {
|
|
@@ -669,19 +666,16 @@ export class BugsnagClient {
|
|
|
669
666
|
options.sort = args.sort;
|
|
670
667
|
if (args.direction !== undefined)
|
|
671
668
|
options.direction = args.direction;
|
|
672
|
-
if (args.
|
|
673
|
-
options.per_page = args.
|
|
674
|
-
if (args.
|
|
675
|
-
options.
|
|
669
|
+
if (args.perPage !== undefined)
|
|
670
|
+
options.per_page = args.perPage;
|
|
671
|
+
if (args.nextUrl !== undefined)
|
|
672
|
+
options.next_url = args.nextUrl;
|
|
676
673
|
const response = await this.errorsApi.listProjectErrors(project.id, options);
|
|
677
|
-
const errors = response.body || [];
|
|
678
|
-
const totalCount = response.headers.get("X-Total-Count");
|
|
679
|
-
const linkHeader = response.headers.get("Link");
|
|
680
674
|
const result = {
|
|
681
|
-
data:
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
675
|
+
data: response.body,
|
|
676
|
+
next_url: response.nextUrl ?? undefined,
|
|
677
|
+
data_count: response.body?.length,
|
|
678
|
+
total_count: response.totalCount ?? undefined,
|
|
685
679
|
};
|
|
686
680
|
return {
|
|
687
681
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
@@ -799,137 +793,9 @@ export class BugsnagClient {
|
|
|
799
793
|
],
|
|
800
794
|
};
|
|
801
795
|
});
|
|
802
|
-
register({
|
|
803
|
-
title: "List Builds",
|
|
804
|
-
summary: "List builds for a project with optional filtering by release stage",
|
|
805
|
-
purpose: "Retrieve a list of build summaries to analyze deployment history and associated errors",
|
|
806
|
-
useCases: [
|
|
807
|
-
"View recent builds to correlate with error spikes",
|
|
808
|
-
"Filter builds by stage (e.g. production, staging) for targeted analysis",
|
|
809
|
-
],
|
|
810
|
-
parameters: [
|
|
811
|
-
...(this.projectApiKey
|
|
812
|
-
? []
|
|
813
|
-
: [
|
|
814
|
-
{
|
|
815
|
-
name: "projectId",
|
|
816
|
-
type: z.string(),
|
|
817
|
-
description: "ID of the project to list builds for",
|
|
818
|
-
required: true,
|
|
819
|
-
},
|
|
820
|
-
]),
|
|
821
|
-
{
|
|
822
|
-
name: "releaseStage",
|
|
823
|
-
type: z.string(),
|
|
824
|
-
description: "Filter builds by this stage (e.g. production, staging)",
|
|
825
|
-
required: false,
|
|
826
|
-
examples: ["production", "staging"],
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
name: "nextUrl",
|
|
830
|
-
type: z.string(),
|
|
831
|
-
description: "URL for retrieving the next page of results. Use the value in the previous response to get the next page when more results are available. If provided, other parameters are ignored.",
|
|
832
|
-
required: false,
|
|
833
|
-
examples: [
|
|
834
|
-
"/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
835
|
-
],
|
|
836
|
-
},
|
|
837
|
-
],
|
|
838
|
-
examples: [
|
|
839
|
-
{
|
|
840
|
-
description: "List all builds for a project",
|
|
841
|
-
parameters: {},
|
|
842
|
-
expectedOutput: "JSON array of build objects with metadata",
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
description: "List production builds for a project",
|
|
846
|
-
parameters: {
|
|
847
|
-
releaseStage: "production",
|
|
848
|
-
},
|
|
849
|
-
expectedOutput: "JSON array of build objects in the production stage",
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
description: "Get the next page of results",
|
|
853
|
-
parameters: {
|
|
854
|
-
nextUrl: "/projects/515fb9337c1074f6fd000003/builds?offset=30&per_page=30",
|
|
855
|
-
},
|
|
856
|
-
expectedOutput: "JSON array of build objects with metadata from the next page",
|
|
857
|
-
},
|
|
858
|
-
],
|
|
859
|
-
hints: ["For more detailed results use the Get Build tool"],
|
|
860
|
-
readOnly: true,
|
|
861
|
-
idempotent: true,
|
|
862
|
-
outputFormat: "JSON array of build summary objects with metadata",
|
|
863
|
-
}, async (args, _extra) => {
|
|
864
|
-
const project = await this.getInputProject(args.projectId);
|
|
865
|
-
const { builds, nextUrl } = await this.listBuilds(project.id, {
|
|
866
|
-
release_stage: args.releaseStage,
|
|
867
|
-
next_url: args.nextUrl,
|
|
868
|
-
});
|
|
869
|
-
return {
|
|
870
|
-
content: [
|
|
871
|
-
{
|
|
872
|
-
type: "text",
|
|
873
|
-
text: JSON.stringify({
|
|
874
|
-
builds,
|
|
875
|
-
next: nextUrl,
|
|
876
|
-
}),
|
|
877
|
-
},
|
|
878
|
-
],
|
|
879
|
-
};
|
|
880
|
-
});
|
|
881
|
-
register({
|
|
882
|
-
title: "Get Build",
|
|
883
|
-
summary: "Get more details for a specific build by its ID",
|
|
884
|
-
purpose: "Retrieve detailed information about a build for analysis and debugging",
|
|
885
|
-
useCases: [
|
|
886
|
-
"View build metadata such as version, source control info, and error counts",
|
|
887
|
-
"Analyze a specific build to correlate with error spikes or deployments",
|
|
888
|
-
"See the stability targets for a project and if the build meets them",
|
|
889
|
-
],
|
|
890
|
-
parameters: [
|
|
891
|
-
...(this.projectApiKey
|
|
892
|
-
? []
|
|
893
|
-
: [
|
|
894
|
-
{
|
|
895
|
-
name: "projectId",
|
|
896
|
-
type: z.string(),
|
|
897
|
-
description: "ID of the project containing the build",
|
|
898
|
-
required: true,
|
|
899
|
-
},
|
|
900
|
-
]),
|
|
901
|
-
{
|
|
902
|
-
name: "buildId",
|
|
903
|
-
type: z.string(),
|
|
904
|
-
description: "ID of the build to retrieve",
|
|
905
|
-
required: true,
|
|
906
|
-
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
907
|
-
},
|
|
908
|
-
],
|
|
909
|
-
examples: [
|
|
910
|
-
{
|
|
911
|
-
description: "Get details for a specific build",
|
|
912
|
-
parameters: {
|
|
913
|
-
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
914
|
-
},
|
|
915
|
-
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
916
|
-
},
|
|
917
|
-
],
|
|
918
|
-
hints: ["Build IDs can be found using the List builds tool"],
|
|
919
|
-
readOnly: true,
|
|
920
|
-
idempotent: true,
|
|
921
|
-
outputFormat: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
922
|
-
}, async (args, _extra) => {
|
|
923
|
-
if (!args.buildId)
|
|
924
|
-
throw new Error("buildId argument is required");
|
|
925
|
-
const build = await this.getBuild((await this.getInputProject(args.projectId)).id, args.buildId);
|
|
926
|
-
return {
|
|
927
|
-
content: [{ type: "text", text: JSON.stringify(build) }],
|
|
928
|
-
};
|
|
929
|
-
});
|
|
930
796
|
register({
|
|
931
797
|
title: "List Releases",
|
|
932
|
-
summary: "List releases for a project
|
|
798
|
+
summary: "List releases for a project",
|
|
933
799
|
purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
|
|
934
800
|
useCases: [
|
|
935
801
|
"View recent releases to correlate with error spikes",
|
|
@@ -948,16 +814,16 @@ export class BugsnagClient {
|
|
|
948
814
|
]),
|
|
949
815
|
{
|
|
950
816
|
name: "releaseStage",
|
|
951
|
-
type: z.string(),
|
|
952
|
-
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'",
|
|
953
819
|
required: false,
|
|
954
820
|
examples: ["production", "staging"],
|
|
955
821
|
},
|
|
956
822
|
{
|
|
957
823
|
name: "visibleOnly",
|
|
958
|
-
type: z.boolean().default(
|
|
959
|
-
description: "Whether to only include releases that are marked as visible
|
|
960
|
-
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,
|
|
961
827
|
examples: ["true", "false"],
|
|
962
828
|
},
|
|
963
829
|
{
|
|
@@ -972,16 +838,16 @@ export class BugsnagClient {
|
|
|
972
838
|
],
|
|
973
839
|
examples: [
|
|
974
840
|
{
|
|
975
|
-
description: "List
|
|
841
|
+
description: "List production releases for a project",
|
|
976
842
|
parameters: {},
|
|
977
|
-
expectedOutput: "JSON array of release objects
|
|
843
|
+
expectedOutput: "JSON array of release objects in the production stage",
|
|
978
844
|
},
|
|
979
845
|
{
|
|
980
|
-
description: "List
|
|
846
|
+
description: "List staging releases for a project",
|
|
981
847
|
parameters: {
|
|
982
|
-
releaseStage: "
|
|
848
|
+
releaseStage: "staging",
|
|
983
849
|
},
|
|
984
|
-
expectedOutput: "JSON array of release objects in the
|
|
850
|
+
expectedOutput: "JSON array of release objects in the staging stage",
|
|
985
851
|
},
|
|
986
852
|
{
|
|
987
853
|
description: "Get the next page of results",
|
|
@@ -991,23 +857,29 @@ export class BugsnagClient {
|
|
|
991
857
|
expectedOutput: "JSON array of release objects with metadata from the next page",
|
|
992
858
|
},
|
|
993
859
|
],
|
|
994
|
-
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
|
+
],
|
|
995
865
|
readOnly: true,
|
|
996
866
|
idempotent: true,
|
|
997
|
-
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",
|
|
998
868
|
}, async (args, _extra) => {
|
|
999
|
-
const
|
|
1000
|
-
release_stage_name: args.releaseStage
|
|
869
|
+
const response = await this.listReleases((await this.getInputProject(args.projectId)).id, {
|
|
870
|
+
release_stage_name: args.releaseStage,
|
|
1001
871
|
visible_only: args.visibleOnly,
|
|
1002
|
-
next_url: args.nextUrl
|
|
872
|
+
next_url: args.nextUrl,
|
|
1003
873
|
});
|
|
1004
874
|
return {
|
|
1005
875
|
content: [
|
|
1006
876
|
{
|
|
1007
877
|
type: "text",
|
|
1008
878
|
text: JSON.stringify({
|
|
1009
|
-
|
|
1010
|
-
|
|
879
|
+
data: response.body,
|
|
880
|
+
next_url: response.nextUrl ?? undefined,
|
|
881
|
+
data_count: response.body?.length,
|
|
882
|
+
total_count: response.totalCount ?? undefined,
|
|
1011
883
|
}),
|
|
1012
884
|
},
|
|
1013
885
|
],
|
|
@@ -1015,12 +887,12 @@ export class BugsnagClient {
|
|
|
1015
887
|
});
|
|
1016
888
|
register({
|
|
1017
889
|
title: "Get Release",
|
|
1018
|
-
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",
|
|
1019
891
|
purpose: "Retrieve detailed information about a release for analysis and debugging",
|
|
1020
892
|
useCases: [
|
|
1021
893
|
"View release metadata such as version, source control info, and error counts",
|
|
1022
|
-
"Analyze
|
|
1023
|
-
"See the
|
|
894
|
+
"Analyze the stability data and targets for a release",
|
|
895
|
+
"See the builds that make up the release",
|
|
1024
896
|
],
|
|
1025
897
|
parameters: [
|
|
1026
898
|
...(this.projectApiKey
|
|
@@ -1057,18 +929,29 @@ export class BugsnagClient {
|
|
|
1057
929
|
}, async (args, _extra) => {
|
|
1058
930
|
if (!args.releaseId)
|
|
1059
931
|
throw new Error("releaseId argument is required");
|
|
1060
|
-
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);
|
|
1061
935
|
return {
|
|
1062
|
-
content: [
|
|
936
|
+
content: [
|
|
937
|
+
{
|
|
938
|
+
type: "text",
|
|
939
|
+
text: JSON.stringify({
|
|
940
|
+
release: releaseResponse.body,
|
|
941
|
+
builds: buildsResponse.body,
|
|
942
|
+
}),
|
|
943
|
+
},
|
|
944
|
+
],
|
|
1063
945
|
};
|
|
1064
946
|
});
|
|
1065
947
|
register({
|
|
1066
|
-
title: "
|
|
1067
|
-
summary: "
|
|
1068
|
-
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",
|
|
1069
951
|
useCases: [
|
|
1070
|
-
"View
|
|
1071
|
-
"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",
|
|
1072
955
|
],
|
|
1073
956
|
parameters: [
|
|
1074
957
|
...(this.projectApiKey
|
|
@@ -1077,37 +960,37 @@ export class BugsnagClient {
|
|
|
1077
960
|
{
|
|
1078
961
|
name: "projectId",
|
|
1079
962
|
type: z.string(),
|
|
1080
|
-
description: "ID of the project containing the
|
|
963
|
+
description: "ID of the project containing the build",
|
|
1081
964
|
required: true,
|
|
1082
965
|
},
|
|
1083
966
|
]),
|
|
1084
967
|
{
|
|
1085
|
-
name: "
|
|
968
|
+
name: "buildId",
|
|
1086
969
|
type: z.string(),
|
|
1087
|
-
description: "ID of the
|
|
970
|
+
description: "ID of the build to retrieve",
|
|
1088
971
|
required: true,
|
|
1089
972
|
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
1090
973
|
},
|
|
1091
974
|
],
|
|
1092
975
|
examples: [
|
|
1093
976
|
{
|
|
1094
|
-
description: "
|
|
977
|
+
description: "Get details for a specific build",
|
|
1095
978
|
parameters: {
|
|
1096
|
-
|
|
979
|
+
buildId: "5f8d0d55c9e77c0017a1b2c3",
|
|
1097
980
|
},
|
|
1098
|
-
expectedOutput: "JSON
|
|
981
|
+
expectedOutput: "JSON object with build details including version, source control info, error counts and stability data.",
|
|
1099
982
|
},
|
|
1100
983
|
],
|
|
1101
|
-
hints: ["
|
|
984
|
+
hints: ["Build IDs can be found using the List builds tool"],
|
|
1102
985
|
readOnly: true,
|
|
1103
986
|
idempotent: true,
|
|
1104
|
-
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",
|
|
1105
988
|
}, async (args, _extra) => {
|
|
1106
|
-
if (!args.
|
|
1107
|
-
throw new Error("
|
|
1108
|
-
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);
|
|
1109
992
|
return {
|
|
1110
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
993
|
+
content: [{ type: "text", text: JSON.stringify(response.body) }],
|
|
1111
994
|
};
|
|
1112
995
|
});
|
|
1113
996
|
}
|
package/dist/common/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { ZodAny, ZodArray, ZodBoolean, ZodEnum, ZodLiteral, ZodNumber, ZodObject, ZodString, ZodUnion, } from "zod";
|
|
2
|
+
import { ZodAny, ZodArray, ZodBoolean, ZodEnum, ZodLiteral, ZodNumber, ZodObject, ZodOptional, ZodString, ZodUnion, } from "zod";
|
|
3
3
|
import Bugsnag from "../common/bugsnag.js";
|
|
4
4
|
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "./info.js";
|
|
5
5
|
export class SmartBearMcpServer extends McpServer {
|
|
@@ -142,6 +142,9 @@ export class SmartBearMcpServer extends McpServer {
|
|
|
142
142
|
`${key === "constraints" && field instanceof ZodEnum ? `\n - ${Object.keys(field.enum).join("\n - ")}` : ""}`);
|
|
143
143
|
}
|
|
144
144
|
getReadableTypeName(zodType) {
|
|
145
|
+
if (zodType instanceof ZodOptional) {
|
|
146
|
+
zodType = zodType._def.innerType;
|
|
147
|
+
}
|
|
145
148
|
if (zodType instanceof ZodString)
|
|
146
149
|
return "string";
|
|
147
150
|
if (zodType instanceof ZodNumber)
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { SmartBearMcpServer } from "./common/server.js";
|
|
|
7
7
|
import { PactflowClient } from "./pactflow/client.js";
|
|
8
8
|
import { QmetryClient } from "./qmetry/client.js";
|
|
9
9
|
import { ReflectClient } from "./reflect/client.js";
|
|
10
|
+
import { ZephyrClient } from "./zephyr/client.js";
|
|
10
11
|
// This is used to report errors in the MCP server itself
|
|
11
12
|
// If you want to use your own BugSnag API key, set the MCP_SERVER_BUGSNAG_API_KEY environment variable
|
|
12
13
|
const McpServerBugsnagAPIKey = process.env.MCP_SERVER_BUGSNAG_API_KEY;
|
|
@@ -24,6 +25,8 @@ async function main() {
|
|
|
24
25
|
const pactBrokerPassword = process.env.PACT_BROKER_PASSWORD;
|
|
25
26
|
const qmetryToken = process.env.QMETRY_API_KEY;
|
|
26
27
|
const qmetryBaseUrl = process.env.QMETRY_BASE_URL;
|
|
28
|
+
const zephyrToken = process.env.ZEPHYR_API_TOKEN;
|
|
29
|
+
const zephyrBaseUrl = process.env.ZEPHYR_BASE_URL;
|
|
27
30
|
let client_defined = false;
|
|
28
31
|
if (reflectToken) {
|
|
29
32
|
server.addClient(new ReflectClient(reflectToken));
|
|
@@ -56,8 +59,12 @@ async function main() {
|
|
|
56
59
|
server.addClient(new QmetryClient(qmetryToken, qmetryBaseUrl));
|
|
57
60
|
client_defined = true;
|
|
58
61
|
}
|
|
62
|
+
if (zephyrToken) {
|
|
63
|
+
server.addClient(new ZephyrClient(zephyrToken, zephyrBaseUrl));
|
|
64
|
+
client_defined = true;
|
|
65
|
+
}
|
|
59
66
|
if (!client_defined) {
|
|
60
|
-
console.error("Please set one of REFLECT_API_TOKEN, BUGSNAG_AUTH_TOKEN, API_HUB_API_KEY, QMETRY_API_KEY or PACT_BROKER_BASE_URL / (and relevant Pact auth) environment variables");
|
|
67
|
+
console.error("Please set one of REFLECT_API_TOKEN, BUGSNAG_AUTH_TOKEN, API_HUB_API_KEY, QMETRY_API_KEY, ZEPHYR_API_TOKEN, or PACT_BROKER_BASE_URL / (and relevant Pact auth) environment variables");
|
|
61
68
|
process.exit(1);
|
|
62
69
|
}
|
|
63
70
|
const transport = new StdioServerTransport();
|