@smartbear/mcp 0.10.0 → 0.11.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 +10 -8
- package/dist/bugsnag/client/api/index.js +2 -0
- package/dist/bugsnag/client/filters.js +0 -6
- package/dist/bugsnag/client.js +234 -376
- package/dist/bugsnag/input-schemas.js +51 -0
- package/dist/collaborator/client.js +18 -5
- package/dist/common/cache.js +63 -0
- package/dist/common/client-registry.js +128 -0
- package/dist/common/register-clients.js +31 -0
- package/dist/common/server.js +30 -9
- package/dist/common/transport-http.js +377 -0
- package/dist/common/transport-stdio.js +43 -0
- package/dist/index.js +20 -70
- package/dist/pactflow/client.js +39 -19
- package/dist/qmetry/client.js +24 -9
- package/dist/reflect/client.js +10 -4
- package/dist/{api-hub → swagger}/client/api.js +2 -2
- package/dist/{api-hub → swagger}/client/configuration.js +1 -1
- package/dist/{api-hub → swagger}/client/index.js +2 -2
- package/dist/{api-hub → swagger}/client/tools.js +4 -4
- package/dist/{api-hub → swagger}/client.js +47 -35
- package/dist/swagger/config-utils.js +18 -0
- package/dist/zephyr/client.js +40 -8
- package/dist/zephyr/common/rest-api-schemas.js +79 -78
- package/dist/zephyr/tool/priority/get-priorities.js +43 -0
- package/dist/zephyr/tool/status/get-statuses.js +49 -0
- package/dist/zephyr/tool/test-case/get-test-case.js +39 -0
- package/dist/zephyr/tool/test-case/get-test-cases.js +64 -0
- package/dist/zephyr/tool/test-cycle/get-test-cycle.js +39 -0
- package/dist/zephyr/tool/test-cycle/get-test-cycles.js +2 -2
- package/dist/zephyr/tool/test-execution/get-test-execution.js +39 -0
- package/package.json +2 -2
- /package/dist/{api-hub → swagger}/client/portal-types.js +0 -0
- /package/dist/{api-hub → swagger}/client/registry-types.js +0 -0
- /package/dist/{api-hub → swagger}/client/user-management-types.js +0 -0
package/dist/bugsnag/client.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import NodeCache from "node-cache";
|
|
2
1
|
import { z } from "zod";
|
|
3
2
|
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
|
|
4
3
|
import { ToolError, } from "../common/types.js";
|
|
5
|
-
import { Configuration, CurrentUserAPI, ErrorAPI, ProjectAPI, } from "./client/api/index.js";
|
|
6
|
-
import {
|
|
4
|
+
import { Configuration, CurrentUserAPI, ErrorAPI, ErrorUpdateRequest, ProjectAPI, } from "./client/api/index.js";
|
|
5
|
+
import { toUrlSearchParams } from "./client/filters.js";
|
|
6
|
+
import { toolInputParameters } from "./input-schemas.js";
|
|
7
7
|
const HUB_PREFIX = "00000";
|
|
8
8
|
const DEFAULT_DOMAIN = "bugsnag.com";
|
|
9
9
|
const HUB_DOMAIN = "bugsnag.smartbear.com";
|
|
10
10
|
const cacheKeys = {
|
|
11
11
|
ORG: "bugsnag_org",
|
|
12
12
|
PROJECTS: "bugsnag_projects",
|
|
13
|
+
PROJECT_EVENT_FILTERS: "bugsnag_project_event_filters",
|
|
13
14
|
CURRENT_PROJECT: "bugsnag_current_project",
|
|
14
|
-
CURRENT_PROJECT_EVENT_FILTERS: "bugsnag_current_project_event_filters",
|
|
15
15
|
};
|
|
16
16
|
// Exclude certain event fields from the project event filters to improve agent usage
|
|
17
17
|
const EXCLUDED_EVENT_FIELDS = new Set([
|
|
@@ -25,57 +25,92 @@ const PERMITTED_UPDATE_OPERATIONS = [
|
|
|
25
25
|
"discard",
|
|
26
26
|
"undiscard",
|
|
27
27
|
];
|
|
28
|
+
const ConfigurationSchema = z.object({
|
|
29
|
+
auth_token: z.string().describe("BugSnag personal authentication token"),
|
|
30
|
+
project_api_key: z.string().describe("BugSnag project API key").optional(),
|
|
31
|
+
endpoint: z.string().url().describe("BugSnag endpoint URL").optional(),
|
|
32
|
+
});
|
|
28
33
|
export class BugsnagClient {
|
|
29
|
-
currentUserApi;
|
|
30
|
-
errorsApi;
|
|
31
34
|
cache;
|
|
32
|
-
projectApi;
|
|
33
35
|
projectApiKey;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
configuredProjectApiKey;
|
|
37
|
+
_currentUserApi;
|
|
38
|
+
_errorsApi;
|
|
39
|
+
_projectApi;
|
|
40
|
+
_appEndpoint;
|
|
41
|
+
get currentUserApi() {
|
|
42
|
+
if (!this._currentUserApi)
|
|
43
|
+
throw new Error("Client not configured");
|
|
44
|
+
return this._currentUserApi;
|
|
45
|
+
}
|
|
46
|
+
get errorsApi() {
|
|
47
|
+
if (!this._errorsApi)
|
|
48
|
+
throw new Error("Client not configured");
|
|
49
|
+
return this._errorsApi;
|
|
50
|
+
}
|
|
51
|
+
get projectApi() {
|
|
52
|
+
if (!this._projectApi)
|
|
53
|
+
throw new Error("Client not configured");
|
|
54
|
+
return this._projectApi;
|
|
55
|
+
}
|
|
56
|
+
get appEndpoint() {
|
|
57
|
+
if (!this._appEndpoint)
|
|
58
|
+
throw new Error("Client not configured");
|
|
59
|
+
return this._appEndpoint;
|
|
60
|
+
}
|
|
36
61
|
name = "BugSnag";
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
toolPrefix = "bugsnag";
|
|
63
|
+
configPrefix = "Bugsnag";
|
|
64
|
+
config = ConfigurationSchema;
|
|
65
|
+
async configure(server, config) {
|
|
66
|
+
this.cache = server.getCache();
|
|
67
|
+
this._appEndpoint = this.getEndpoint("app", config.project_api_key, config.endpoint);
|
|
68
|
+
const apiConfig = new Configuration({
|
|
69
|
+
apiKey: `token ${config.auth_token}`,
|
|
43
70
|
headers: {
|
|
44
71
|
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
|
|
45
72
|
"Content-Type": "application/json",
|
|
46
73
|
"X-Bugsnag-API": "true",
|
|
47
74
|
"X-Version": "2",
|
|
48
75
|
},
|
|
49
|
-
basePath: this.
|
|
76
|
+
basePath: this.getEndpoint("api", config.project_api_key, config.endpoint),
|
|
50
77
|
});
|
|
51
|
-
this.
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
});
|
|
56
|
-
this.projectApi = new ProjectAPI(config);
|
|
57
|
-
this.projectApiKey = projectApiKey;
|
|
58
|
-
}
|
|
59
|
-
async initialize() {
|
|
78
|
+
this._currentUserApi = new CurrentUserAPI(apiConfig);
|
|
79
|
+
this._errorsApi = new ErrorAPI(apiConfig);
|
|
80
|
+
this._projectApi = new ProjectAPI(apiConfig);
|
|
81
|
+
this.projectApiKey = config.project_api_key;
|
|
60
82
|
// Trigger caching of org and projects
|
|
61
83
|
try {
|
|
62
|
-
await this.getProjects();
|
|
84
|
+
const projects = await this.getProjects();
|
|
85
|
+
// If there's just one project, make this the current project
|
|
86
|
+
if (projects.length === 1 && !this.projectApiKey) {
|
|
87
|
+
this.projectApiKey = projects[0].apiKey;
|
|
88
|
+
}
|
|
63
89
|
}
|
|
64
90
|
catch (error) {
|
|
65
91
|
// Swallow auth errors here to allow the tools to be registered for visibility, even if the token is invalid
|
|
66
92
|
console.error("Unable to connect to BugSnag APIs, the BugSnag tools will not work. Check your configured BugSnag auth token.", error);
|
|
67
93
|
}
|
|
68
94
|
if (this.projectApiKey) {
|
|
95
|
+
this.configuredProjectApiKey = this.projectApiKey; // Store the originally configured API key
|
|
96
|
+
let currentProject = null;
|
|
69
97
|
try {
|
|
70
|
-
await this.getCurrentProject();
|
|
98
|
+
currentProject = await this.getCurrentProject();
|
|
71
99
|
}
|
|
72
100
|
catch (error) {
|
|
101
|
+
console.error("An error occurred while fetching project information", error);
|
|
102
|
+
}
|
|
103
|
+
if (currentProject) {
|
|
104
|
+
await this.getProjectEventFilters(currentProject);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
73
107
|
// Clear the project API key to allow tools to work across all projects
|
|
74
108
|
this.projectApiKey = undefined;
|
|
75
109
|
console.error("Unable to find your configured BugSnag project, the BugSnag tools will continue to work across all projects in your organization. " +
|
|
76
|
-
"Check your configured BugSnag project API key."
|
|
110
|
+
"Check your configured BugSnag project API key.");
|
|
77
111
|
}
|
|
78
112
|
}
|
|
113
|
+
return true;
|
|
79
114
|
}
|
|
80
115
|
getHost(apiKey, subdomain) {
|
|
81
116
|
if (apiKey?.startsWith(HUB_PREFIX)) {
|
|
@@ -126,7 +161,7 @@ export class BugsnagClient {
|
|
|
126
161
|
return `${dashboardUrl}/errors/${errorId}${queryString ? `?${queryString}` : ""}`;
|
|
127
162
|
}
|
|
128
163
|
async getOrganization() {
|
|
129
|
-
let org = this.cache
|
|
164
|
+
let org = this.cache?.get(cacheKeys.ORG);
|
|
130
165
|
if (!org) {
|
|
131
166
|
const response = await this.currentUserApi.listUserOrganizations();
|
|
132
167
|
const orgs = response.body;
|
|
@@ -134,7 +169,7 @@ export class BugsnagClient {
|
|
|
134
169
|
throw new Error("No organizations found for the current user.");
|
|
135
170
|
}
|
|
136
171
|
org = orgs[0];
|
|
137
|
-
this.cache
|
|
172
|
+
this.cache?.set(cacheKeys.ORG, org);
|
|
138
173
|
}
|
|
139
174
|
return org;
|
|
140
175
|
}
|
|
@@ -143,12 +178,12 @@ export class BugsnagClient {
|
|
|
143
178
|
// stores them in the cache for future use.
|
|
144
179
|
// It throws an error if no organizations are found in the cache.
|
|
145
180
|
async getProjects() {
|
|
146
|
-
let projects = this.cache
|
|
181
|
+
let projects = this.cache?.get(cacheKeys.PROJECTS);
|
|
147
182
|
if (!projects) {
|
|
148
183
|
const org = await this.getOrganization();
|
|
149
184
|
const response = await this.currentUserApi.getOrganizationProjects(org.id);
|
|
150
185
|
projects = response.body;
|
|
151
|
-
this.cache
|
|
186
|
+
this.cache?.set(cacheKeys.PROJECTS, projects);
|
|
152
187
|
}
|
|
153
188
|
return projects;
|
|
154
189
|
}
|
|
@@ -157,28 +192,27 @@ export class BugsnagClient {
|
|
|
157
192
|
return projects.find((p) => p.id === projectId) || null;
|
|
158
193
|
}
|
|
159
194
|
async getCurrentProject() {
|
|
160
|
-
let project = this.cache
|
|
195
|
+
let project = this.cache?.get(cacheKeys.CURRENT_PROJECT) ?? null;
|
|
161
196
|
if (!project && this.projectApiKey) {
|
|
162
197
|
const projects = await this.getProjects();
|
|
163
198
|
project =
|
|
164
199
|
projects.find((p) => p.apiKey === this.projectApiKey) ?? null;
|
|
165
|
-
|
|
166
|
-
throw new ToolError("Unable to find project with the configured API key.");
|
|
167
|
-
}
|
|
168
|
-
this.cache.set(cacheKeys.CURRENT_PROJECT, project);
|
|
169
|
-
if (project) {
|
|
170
|
-
this.cache.set(cacheKeys.CURRENT_PROJECT_EVENT_FILTERS, await this.getProjectEventFilters(project));
|
|
171
|
-
}
|
|
200
|
+
this.cache?.set(cacheKeys.CURRENT_PROJECT, project);
|
|
172
201
|
}
|
|
173
202
|
return project;
|
|
174
203
|
}
|
|
175
204
|
async getProjectEventFilters(project) {
|
|
176
|
-
|
|
177
|
-
if (!
|
|
178
|
-
|
|
205
|
+
const projectFiltersCache = this.cache?.get(cacheKeys.PROJECT_EVENT_FILTERS) || {};
|
|
206
|
+
if (!projectFiltersCache[project.id]) {
|
|
207
|
+
let filtersResponse = (await this.projectApi.listProjectEventFields(project.id)).body;
|
|
208
|
+
if (!filtersResponse || filtersResponse.length === 0) {
|
|
209
|
+
throw new ToolError(`No event fields found for project ${project.name}.`);
|
|
210
|
+
}
|
|
211
|
+
filtersResponse = filtersResponse.filter((field) => field.displayId && !EXCLUDED_EVENT_FIELDS.has(field.displayId));
|
|
212
|
+
projectFiltersCache[project.id] = filtersResponse;
|
|
213
|
+
this.cache?.set(cacheKeys.PROJECT_EVENT_FILTERS, projectFiltersCache);
|
|
179
214
|
}
|
|
180
|
-
|
|
181
|
-
return filtersResponse;
|
|
215
|
+
return projectFiltersCache[project.id];
|
|
182
216
|
}
|
|
183
217
|
async getEvent(eventId, projectId) {
|
|
184
218
|
const projectIds = projectId
|
|
@@ -193,6 +227,10 @@ export class BugsnagClient {
|
|
|
193
227
|
if (!maybeProject) {
|
|
194
228
|
throw new ToolError(`Project with ID ${projectId} not found.`);
|
|
195
229
|
}
|
|
230
|
+
// If this hasn't been configured at startup, set this to the current project for future tool calls
|
|
231
|
+
if (!this.configuredProjectApiKey) {
|
|
232
|
+
this.cache?.set(cacheKeys.CURRENT_PROJECT, maybeProject);
|
|
233
|
+
}
|
|
196
234
|
return maybeProject;
|
|
197
235
|
}
|
|
198
236
|
else {
|
|
@@ -232,72 +270,69 @@ export class BugsnagClient {
|
|
|
232
270
|
};
|
|
233
271
|
}
|
|
234
272
|
registerTools(register, getInput) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
299
|
-
});
|
|
300
|
-
}
|
|
273
|
+
register({
|
|
274
|
+
title: "Get Current Project",
|
|
275
|
+
summary: "Retrieve the 'current' project on which tools should operate by default. This allows BugSnag tools to be called with no projectId parameter.",
|
|
276
|
+
purpose: "Gets information about the 'current' BugSnag project, including ID and API key",
|
|
277
|
+
useCases: ["Understand if a current project has been set"],
|
|
278
|
+
inputSchema: toolInputParameters.empty,
|
|
279
|
+
hints: [
|
|
280
|
+
"If a project is returned, it can be assumed that the user expects interactions with BugSnag tools to refer to this project",
|
|
281
|
+
"If this tool returns no current project then other BugSnag tools will require an explicit project ID parameter",
|
|
282
|
+
"Call the List Projects tool to see all projects that the user has access to. Get the project ID from this list either by asking the user for the project name or slug",
|
|
283
|
+
"You might find a BugSnag API key in the user's code where they configure the BugSnag SDK that can be matched to a project 'apiKey' field from the project list",
|
|
284
|
+
],
|
|
285
|
+
}, async (_args, _extra) => {
|
|
286
|
+
const project = await this.getCurrentProject();
|
|
287
|
+
if (!project) {
|
|
288
|
+
throw new ToolError("No current project is configured in the MCP server - use List Projects to see the available projects and use the project ID as a parameter to other BugSnag tools. You can ask the user to select the project based on the name or slug, or use the apiKey field and see if there's a BugSnag API key set in the user's code when they configure the BugSnag SDK");
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
content: [{ type: "text", text: JSON.stringify(project) }],
|
|
292
|
+
};
|
|
293
|
+
});
|
|
294
|
+
const listProjectsInputSchema = z.object({
|
|
295
|
+
apiKey: z
|
|
296
|
+
.string()
|
|
297
|
+
.optional()
|
|
298
|
+
.describe("The API key of the BugSnag project, if known."),
|
|
299
|
+
});
|
|
300
|
+
register({
|
|
301
|
+
title: "List Projects",
|
|
302
|
+
summary: "List all projects in the organization that the current user has access to, or find a project matching an API key.",
|
|
303
|
+
purpose: "Retrieve available projects for browsing and selecting which project to analyze.",
|
|
304
|
+
useCases: [
|
|
305
|
+
"Get an overview of all projects in the organization",
|
|
306
|
+
"Locate a project by its API key if known from the user's code",
|
|
307
|
+
],
|
|
308
|
+
inputSchema: listProjectsInputSchema,
|
|
309
|
+
hints: [
|
|
310
|
+
"Project IDs from this list can be used with other tools when no project API key is configured",
|
|
311
|
+
],
|
|
312
|
+
}, async (args, _extra) => {
|
|
313
|
+
const params = listProjectsInputSchema.parse(args);
|
|
314
|
+
let projects = await this.getProjects();
|
|
315
|
+
if (!projects || projects.length === 0) {
|
|
316
|
+
throw new ToolError("No BugSnag projects found for the current user.");
|
|
317
|
+
}
|
|
318
|
+
if (params.apiKey) {
|
|
319
|
+
const matchedProject = projects.find((p) => p.apiKey === params.apiKey);
|
|
320
|
+
projects = matchedProject ? [matchedProject] : [];
|
|
321
|
+
}
|
|
322
|
+
const content = {
|
|
323
|
+
data: projects,
|
|
324
|
+
count: projects.length,
|
|
325
|
+
};
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: JSON.stringify(content) }],
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
const getErrorInputSchema = z.object({
|
|
331
|
+
projectId: toolInputParameters.projectId,
|
|
332
|
+
errorId: toolInputParameters.errorId.describe("Unique identifier of the error to retrieve"),
|
|
333
|
+
filters: toolInputParameters.filters.describe("Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields. " +
|
|
334
|
+
"Time filters support extended ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)."),
|
|
335
|
+
});
|
|
301
336
|
register({
|
|
302
337
|
title: "Get Error",
|
|
303
338
|
summary: "Get full details on an error, including aggregated and summarized data across all events (occurrences) and details of the latest event (occurrence), such as breadcrumbs, metadata and the stacktrace. Use the filters parameter to narrow down the summaries further.",
|
|
@@ -308,42 +343,7 @@ export class BugsnagClient {
|
|
|
308
343
|
"Get error details for debugging and root cause analysis",
|
|
309
344
|
"Retrieve error metadata for incident reports and documentation",
|
|
310
345
|
],
|
|
311
|
-
|
|
312
|
-
{
|
|
313
|
-
name: "errorId",
|
|
314
|
-
type: z.string(),
|
|
315
|
-
required: true,
|
|
316
|
-
description: "Unique identifier of the error to retrieve",
|
|
317
|
-
examples: ["6863e2af8c857c0a5023b411"],
|
|
318
|
-
},
|
|
319
|
-
...(this.projectApiKey
|
|
320
|
-
? []
|
|
321
|
-
: [
|
|
322
|
-
{
|
|
323
|
-
name: "projectId",
|
|
324
|
-
type: z.string(),
|
|
325
|
-
required: true,
|
|
326
|
-
description: "ID of the project containing the error",
|
|
327
|
-
},
|
|
328
|
-
]),
|
|
329
|
-
{
|
|
330
|
-
name: "filters",
|
|
331
|
-
type: FilterObjectSchema,
|
|
332
|
-
required: false,
|
|
333
|
-
description: "Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields",
|
|
334
|
-
examples: [
|
|
335
|
-
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
336
|
-
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
337
|
-
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
338
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
339
|
-
],
|
|
340
|
-
constraints: [
|
|
341
|
-
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
342
|
-
"ISO 8601 times must be in UTC and use extended format",
|
|
343
|
-
"Relative time periods: h (hours), d (days)",
|
|
344
|
-
],
|
|
345
|
-
},
|
|
346
|
-
],
|
|
346
|
+
inputSchema: getErrorInputSchema,
|
|
347
347
|
outputDescription: "JSON object containing: " +
|
|
348
348
|
" - error_details: Aggregated data about the error, including first and last seen occurrence" +
|
|
349
349
|
" - latest_event: Detailed information about the most recent occurrence of the error, including stacktrace, breadcrumbs, user and context" +
|
|
@@ -365,15 +365,14 @@ export class BugsnagClient {
|
|
|
365
365
|
"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",
|
|
366
366
|
],
|
|
367
367
|
}, async (args, _extra) => {
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const errorDetails = (await this.errorsApi.viewErrorOnProject(project.id, args.errorId)).body;
|
|
368
|
+
const params = getErrorInputSchema.parse(args);
|
|
369
|
+
const project = await this.getInputProject(params.projectId);
|
|
370
|
+
const errorDetails = (await this.errorsApi.viewErrorOnProject(project.id, params.errorId)).body;
|
|
372
371
|
if (!errorDetails) {
|
|
373
|
-
throw new ToolError(`Error with ID ${
|
|
372
|
+
throw new ToolError(`Error with ID ${params.errorId} not found in project ${project.id}.`);
|
|
374
373
|
}
|
|
375
374
|
const filters = {
|
|
376
|
-
error: [{ type: "eq", value:
|
|
375
|
+
error: [{ type: "eq", value: params.errorId }],
|
|
377
376
|
...args.filters,
|
|
378
377
|
};
|
|
379
378
|
// Get the latest event for this error using the events endpoint with filters
|
|
@@ -398,6 +397,11 @@ export class BugsnagClient {
|
|
|
398
397
|
content: [{ type: "text", text: JSON.stringify(content) }],
|
|
399
398
|
};
|
|
400
399
|
});
|
|
400
|
+
const getEventDetailsInputSchema = z.object({
|
|
401
|
+
link: z
|
|
402
|
+
.string()
|
|
403
|
+
.describe("Full URL to the event details page in the BugSnag dashboard (web interface), containing project slug and event_id parameter."),
|
|
404
|
+
});
|
|
401
405
|
register({
|
|
402
406
|
title: "Get Event Details",
|
|
403
407
|
summary: "Get detailed information about a specific event using its dashboard URL",
|
|
@@ -407,20 +411,7 @@ export class BugsnagClient {
|
|
|
407
411
|
"Extract event information from shared links or browser URLs",
|
|
408
412
|
"Quick lookup of event details without needing separate project and event IDs",
|
|
409
413
|
],
|
|
410
|
-
|
|
411
|
-
{
|
|
412
|
-
name: "link",
|
|
413
|
-
type: z.string(),
|
|
414
|
-
description: "Full URL to the event details page in the BugSnag dashboard (web interface)",
|
|
415
|
-
required: true,
|
|
416
|
-
examples: [
|
|
417
|
-
"https://app.bugsnag.com/my-org/my-project/errors/6863e2af8c857c0a5023b411?event_id=6863e2af012caf1d5c320000",
|
|
418
|
-
],
|
|
419
|
-
constraints: [
|
|
420
|
-
"Must be a valid dashboard URL containing project slug and event_id parameter",
|
|
421
|
-
],
|
|
422
|
-
},
|
|
423
|
-
],
|
|
414
|
+
inputSchema: getEventDetailsInputSchema,
|
|
424
415
|
examples: [
|
|
425
416
|
{
|
|
426
417
|
description: "Get event details from a dashboard URL",
|
|
@@ -435,9 +426,8 @@ export class BugsnagClient {
|
|
|
435
426
|
"This is useful when users share BugSnag dashboard URLs and you need to extract the event data",
|
|
436
427
|
],
|
|
437
428
|
}, async (args, _extra) => {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const url = new URL(args.link);
|
|
429
|
+
const params = getEventDetailsInputSchema.parse(args);
|
|
430
|
+
const url = new URL(params.link);
|
|
441
431
|
const eventId = url.searchParams.get("event_id");
|
|
442
432
|
const projectSlug = url.pathname.split("/")[2];
|
|
443
433
|
if (!projectSlug || !eventId)
|
|
@@ -453,6 +443,15 @@ export class BugsnagClient {
|
|
|
453
443
|
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
454
444
|
};
|
|
455
445
|
});
|
|
446
|
+
const listProjectErrorsInputSchema = z.object({
|
|
447
|
+
projectId: toolInputParameters.projectId,
|
|
448
|
+
filters: toolInputParameters.filters.describe("Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields. " +
|
|
449
|
+
"Time filters support extended ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)."),
|
|
450
|
+
sort: toolInputParameters.sort,
|
|
451
|
+
direction: toolInputParameters.direction,
|
|
452
|
+
perPage: toolInputParameters.perPage,
|
|
453
|
+
nextUrl: toolInputParameters.nextUrl,
|
|
454
|
+
});
|
|
456
455
|
register({
|
|
457
456
|
title: "List Project Errors",
|
|
458
457
|
summary: "List and search errors in a project using customizable filters and pagination",
|
|
@@ -463,73 +462,7 @@ export class BugsnagClient {
|
|
|
463
462
|
"Monitor error trends over time using date range filters",
|
|
464
463
|
"Find errors affecting specific users or environments using metadata filters",
|
|
465
464
|
],
|
|
466
|
-
|
|
467
|
-
{
|
|
468
|
-
name: "filters",
|
|
469
|
-
type: FilterObjectSchema.default({
|
|
470
|
-
"event.since": [{ type: "eq", value: "30d" }],
|
|
471
|
-
"error.status": [{ type: "eq", value: "open" }],
|
|
472
|
-
}),
|
|
473
|
-
description: "Apply filters to narrow down the error list. Use the List Project Event Filters tool to discover available filter fields",
|
|
474
|
-
required: false,
|
|
475
|
-
examples: [
|
|
476
|
-
'{"error.status": [{"type": "eq", "value": "open"}]}',
|
|
477
|
-
'{"event.since": [{"type": "eq", "value": "7d"}]} // Relative time: last 7 days',
|
|
478
|
-
'{"event.since": [{"type": "eq", "value": "2018-05-20T00:00:00Z"}]} // ISO 8601 UTC format',
|
|
479
|
-
'{"user.email": [{"type": "eq", "value": "user@example.com"}]}',
|
|
480
|
-
],
|
|
481
|
-
constraints: [
|
|
482
|
-
"Time filters support ISO 8601 format (e.g. 2018-05-20T00:00:00Z) or relative format (e.g. 7d, 24h)",
|
|
483
|
-
"ISO 8601 times must be in UTC and use extended format",
|
|
484
|
-
"Relative time periods: h (hours), d (days)",
|
|
485
|
-
],
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
name: "sort",
|
|
489
|
-
type: z
|
|
490
|
-
.enum(["first_seen", "last_seen", "events", "users", "unsorted"])
|
|
491
|
-
.default("last_seen"),
|
|
492
|
-
description: "Field to sort the errors by",
|
|
493
|
-
required: false,
|
|
494
|
-
examples: ["last_seen"],
|
|
495
|
-
},
|
|
496
|
-
{
|
|
497
|
-
name: "direction",
|
|
498
|
-
type: z.enum(["asc", "desc"]).default("desc"),
|
|
499
|
-
description: "Sort direction for ordering results",
|
|
500
|
-
required: false,
|
|
501
|
-
examples: ["desc"],
|
|
502
|
-
},
|
|
503
|
-
{
|
|
504
|
-
name: "perPage",
|
|
505
|
-
type: z.number().min(1).max(100).default(30),
|
|
506
|
-
description: "How many results to return per page.",
|
|
507
|
-
required: false,
|
|
508
|
-
examples: ["30", "50", "100"],
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
name: "nextUrl",
|
|
512
|
-
type: z.string(),
|
|
513
|
-
description: "URL for retrieving the next page of results. Use the value in the previous response to get the next page when more results are available.",
|
|
514
|
-
required: false,
|
|
515
|
-
examples: [
|
|
516
|
-
"https://api.bugsnag.com/projects/515fb9337c1074f6fd000003/errors?offset=30&per_page=30&sort=last_seen",
|
|
517
|
-
],
|
|
518
|
-
constraints: [
|
|
519
|
-
"Only values provided in the output from this tool can be used. Do not attempt to construct it manually.",
|
|
520
|
-
],
|
|
521
|
-
},
|
|
522
|
-
...(this.projectApiKey
|
|
523
|
-
? []
|
|
524
|
-
: [
|
|
525
|
-
{
|
|
526
|
-
name: "projectId",
|
|
527
|
-
type: z.string(),
|
|
528
|
-
description: "ID of the project to query for errors",
|
|
529
|
-
required: true,
|
|
530
|
-
},
|
|
531
|
-
]),
|
|
532
|
-
],
|
|
465
|
+
inputSchema: listProjectErrorsInputSchema,
|
|
533
466
|
examples: [
|
|
534
467
|
{
|
|
535
468
|
description: "Find errors affecting a specific user in the last 24 hours",
|
|
@@ -564,7 +497,7 @@ export class BugsnagClient {
|
|
|
564
497
|
},
|
|
565
498
|
],
|
|
566
499
|
hints: [
|
|
567
|
-
"Use
|
|
500
|
+
"Use List Project Event Filters tool first to discover valid filter field names for your project",
|
|
568
501
|
"Combine multiple filters to narrow results - filters are applied with AND logic",
|
|
569
502
|
"For time filters: use relative format (7d, 24h) for recent periods or ISO 8601 UTC format (2018-05-20T00:00:00Z) for specific dates",
|
|
570
503
|
"Common time filters: event.since (from this time), event.before (until this time)",
|
|
@@ -575,12 +508,13 @@ export class BugsnagClient {
|
|
|
575
508
|
"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.",
|
|
576
509
|
],
|
|
577
510
|
}, async (args, _extra) => {
|
|
578
|
-
const
|
|
511
|
+
const params = listProjectErrorsInputSchema.parse(args);
|
|
512
|
+
const project = await this.getInputProject(params.projectId);
|
|
579
513
|
// Validate filter keys against cached event fields
|
|
580
|
-
if (
|
|
581
|
-
const eventFields = this.
|
|
514
|
+
if (params.filters) {
|
|
515
|
+
const eventFields = await this.getProjectEventFilters(project);
|
|
582
516
|
const validKeys = new Set(eventFields.map((f) => f.displayId));
|
|
583
|
-
for (const key of Object.keys(
|
|
517
|
+
for (const key of Object.keys(params.filters)) {
|
|
584
518
|
if (!validKeys.has(key)) {
|
|
585
519
|
throw new ToolError(`Invalid filter key: ${key}`);
|
|
586
520
|
}
|
|
@@ -589,9 +523,9 @@ export class BugsnagClient {
|
|
|
589
523
|
const filters = {
|
|
590
524
|
"event.since": [{ type: "eq", value: "30d" }],
|
|
591
525
|
"error.status": [{ type: "eq", value: "open" }],
|
|
592
|
-
...
|
|
526
|
+
...params.filters,
|
|
593
527
|
};
|
|
594
|
-
const response = await this.errorsApi.listProjectErrors(project.id, null,
|
|
528
|
+
const response = await this.errorsApi.listProjectErrors(project.id, null, params.sort, params.direction, params.perPage, filters, params.nextUrl);
|
|
595
529
|
const result = {
|
|
596
530
|
data: response.body,
|
|
597
531
|
next_url: response.nextUrl ?? undefined,
|
|
@@ -602,16 +536,19 @@ export class BugsnagClient {
|
|
|
602
536
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
603
537
|
};
|
|
604
538
|
});
|
|
539
|
+
const listProjectEventFiltersInputSchema = z.object({
|
|
540
|
+
projectId: toolInputParameters.projectId,
|
|
541
|
+
});
|
|
605
542
|
register({
|
|
606
543
|
title: "List Project Event Filters",
|
|
607
|
-
summary: "Get available event filter fields for
|
|
544
|
+
summary: "Get available event filter fields for a project",
|
|
608
545
|
purpose: "Discover valid filter field names and options that can be used with the List Errors or Get Error tools",
|
|
609
546
|
useCases: [
|
|
610
547
|
"Discover what filter fields are available before searching for errors",
|
|
611
548
|
"Find the correct field names for filtering by user, environment, or custom metadata",
|
|
612
549
|
"Understand filter options and data types for building complex queries",
|
|
613
550
|
],
|
|
614
|
-
|
|
551
|
+
inputSchema: listProjectEventFiltersInputSchema,
|
|
615
552
|
examples: [
|
|
616
553
|
{
|
|
617
554
|
description: "Get all available filter fields",
|
|
@@ -623,14 +560,20 @@ export class BugsnagClient {
|
|
|
623
560
|
"Use this tool before the List Errors or Get Error tools to understand available filters",
|
|
624
561
|
"Look for display_id field in the response - these are the field names to use in filters",
|
|
625
562
|
],
|
|
626
|
-
}, async (
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
throw new ToolError("No event filters found in cache.");
|
|
563
|
+
}, async (args, _extra) => {
|
|
564
|
+
const params = listProjectEventFiltersInputSchema.parse(args);
|
|
565
|
+
const eventFilters = await this.getProjectEventFilters(await this.getInputProject(params.projectId));
|
|
630
566
|
return {
|
|
631
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
567
|
+
content: [{ type: "text", text: JSON.stringify(eventFilters) }],
|
|
632
568
|
};
|
|
633
569
|
});
|
|
570
|
+
const updateErrorInputSchema = z.object({
|
|
571
|
+
projectId: toolInputParameters.projectId,
|
|
572
|
+
errorId: toolInputParameters.errorId,
|
|
573
|
+
operation: z
|
|
574
|
+
.enum(PERMITTED_UPDATE_OPERATIONS)
|
|
575
|
+
.describe("The operation to apply to the error"),
|
|
576
|
+
});
|
|
634
577
|
register({
|
|
635
578
|
title: "Update Error",
|
|
636
579
|
summary: "Update the status of an error",
|
|
@@ -640,32 +583,7 @@ export class BugsnagClient {
|
|
|
640
583
|
"Discard or un-discard an error",
|
|
641
584
|
"Update the severity of an error",
|
|
642
585
|
],
|
|
643
|
-
|
|
644
|
-
...(this.projectApiKey
|
|
645
|
-
? []
|
|
646
|
-
: [
|
|
647
|
-
{
|
|
648
|
-
name: "projectId",
|
|
649
|
-
type: z.string(),
|
|
650
|
-
description: "ID of the project that contains the error to be updated",
|
|
651
|
-
required: true,
|
|
652
|
-
},
|
|
653
|
-
]),
|
|
654
|
-
{
|
|
655
|
-
name: "errorId",
|
|
656
|
-
type: z.string(),
|
|
657
|
-
description: "ID of the error to update",
|
|
658
|
-
required: true,
|
|
659
|
-
examples: ["6863e2af8c857c0a5023b411"],
|
|
660
|
-
},
|
|
661
|
-
{
|
|
662
|
-
name: "operation",
|
|
663
|
-
type: z.enum(PERMITTED_UPDATE_OPERATIONS),
|
|
664
|
-
description: "The operation to apply to the error",
|
|
665
|
-
required: true,
|
|
666
|
-
examples: ["fix", "open", "ignore", "discard", "undiscard"],
|
|
667
|
-
},
|
|
668
|
-
],
|
|
586
|
+
inputSchema: updateErrorInputSchema,
|
|
669
587
|
examples: [
|
|
670
588
|
{
|
|
671
589
|
description: "Mark an error as fixed",
|
|
@@ -682,10 +600,10 @@ export class BugsnagClient {
|
|
|
682
600
|
readOnly: false,
|
|
683
601
|
idempotent: false,
|
|
684
602
|
}, async (args, _extra) => {
|
|
685
|
-
const
|
|
686
|
-
const project = await this.getInputProject(
|
|
603
|
+
const params = updateErrorInputSchema.parse(args);
|
|
604
|
+
const project = await this.getInputProject(params.projectId);
|
|
687
605
|
let severity;
|
|
688
|
-
if (operation === "override_severity") {
|
|
606
|
+
if (params.operation === "override_severity") {
|
|
689
607
|
// illicit the severity from the user
|
|
690
608
|
const result = await getInput({
|
|
691
609
|
message: "Please provide the new severity for the error (e.g. 'info', 'warning', 'error', 'critical')",
|
|
@@ -705,8 +623,8 @@ export class BugsnagClient {
|
|
|
705
623
|
severity = result.content.severity;
|
|
706
624
|
}
|
|
707
625
|
}
|
|
708
|
-
const result = await this.errorsApi.updateErrorOnProject(project.id, errorId, {
|
|
709
|
-
operation: operation,
|
|
626
|
+
const result = await this.errorsApi.updateErrorOnProject(project.id, params.errorId, {
|
|
627
|
+
operation: Object.values(ErrorUpdateRequest.OperationEnum).find((value) => value === params.operation),
|
|
710
628
|
severity: severity,
|
|
711
629
|
});
|
|
712
630
|
return {
|
|
@@ -720,6 +638,16 @@ export class BugsnagClient {
|
|
|
720
638
|
],
|
|
721
639
|
};
|
|
722
640
|
});
|
|
641
|
+
const listReleasesInputSchema = z.object({
|
|
642
|
+
projectId: toolInputParameters.projectId,
|
|
643
|
+
releaseStage: toolInputParameters.releaseStage,
|
|
644
|
+
visibleOnly: z
|
|
645
|
+
.boolean()
|
|
646
|
+
.describe("Whether to only include releases that are marked as visible in the dashboard")
|
|
647
|
+
.default(false),
|
|
648
|
+
perPage: toolInputParameters.perPage,
|
|
649
|
+
nextUrl: toolInputParameters.nextUrl,
|
|
650
|
+
});
|
|
723
651
|
register({
|
|
724
652
|
title: "List Releases",
|
|
725
653
|
summary: "List releases for a project",
|
|
@@ -728,48 +656,7 @@ export class BugsnagClient {
|
|
|
728
656
|
"View recent releases to correlate with error spikes",
|
|
729
657
|
"Filter releases by stage (e.g. production, staging) for targeted analysis",
|
|
730
658
|
],
|
|
731
|
-
|
|
732
|
-
...(this.projectApiKey
|
|
733
|
-
? []
|
|
734
|
-
: [
|
|
735
|
-
{
|
|
736
|
-
name: "projectId",
|
|
737
|
-
type: z.string(),
|
|
738
|
-
description: "ID of the project to list releases for",
|
|
739
|
-
required: true,
|
|
740
|
-
},
|
|
741
|
-
]),
|
|
742
|
-
{
|
|
743
|
-
name: "releaseStage",
|
|
744
|
-
type: z.string().default("production"),
|
|
745
|
-
description: "Filter releases by this stage (e.g. production, staging), defaults to 'production'",
|
|
746
|
-
required: false,
|
|
747
|
-
examples: ["production", "staging"],
|
|
748
|
-
},
|
|
749
|
-
{
|
|
750
|
-
name: "visibleOnly",
|
|
751
|
-
type: z.boolean().default(false),
|
|
752
|
-
description: "Whether to only include releases that are marked as visible in the dashboard, defaults to false",
|
|
753
|
-
required: false,
|
|
754
|
-
examples: ["true", "false"],
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
name: "perPage",
|
|
758
|
-
type: z.number().min(1).max(100).default(30),
|
|
759
|
-
description: "How many results to return per page.",
|
|
760
|
-
required: false,
|
|
761
|
-
examples: ["30", "50", "100"],
|
|
762
|
-
},
|
|
763
|
-
{
|
|
764
|
-
name: "nextUrl",
|
|
765
|
-
type: z.string(),
|
|
766
|
-
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.",
|
|
767
|
-
required: false,
|
|
768
|
-
examples: [
|
|
769
|
-
"/projects/515fb9337c1074f6fd000003/releases?offset=30&per_page=30",
|
|
770
|
-
],
|
|
771
|
-
},
|
|
772
|
-
],
|
|
659
|
+
inputSchema: listReleasesInputSchema,
|
|
773
660
|
examples: [
|
|
774
661
|
{
|
|
775
662
|
description: "List production releases for a project",
|
|
@@ -800,9 +687,10 @@ export class BugsnagClient {
|
|
|
800
687
|
idempotent: true,
|
|
801
688
|
outputDescription: "JSON array of release summary objects with metadata, with a URL to the next page if more results are available",
|
|
802
689
|
}, async (args, _extra) => {
|
|
803
|
-
const
|
|
804
|
-
const
|
|
805
|
-
|
|
690
|
+
const params = listReleasesInputSchema.parse(args);
|
|
691
|
+
const project = await this.getInputProject(params.projectId);
|
|
692
|
+
const response = await this.projectApi.listProjectReleaseGroups(project.id, params.releaseStage, false, // Not top-only
|
|
693
|
+
params.visibleOnly, params.perPage, params.nextUrl);
|
|
806
694
|
let releases = [];
|
|
807
695
|
if (response.body) {
|
|
808
696
|
releases = response.body.map((r) => this.addStabilityData(r, project));
|
|
@@ -821,6 +709,10 @@ export class BugsnagClient {
|
|
|
821
709
|
],
|
|
822
710
|
};
|
|
823
711
|
});
|
|
712
|
+
const getReleaseInputSchema = z.object({
|
|
713
|
+
projectId: toolInputParameters.projectId,
|
|
714
|
+
releaseId: toolInputParameters.releaseId,
|
|
715
|
+
});
|
|
824
716
|
register({
|
|
825
717
|
title: "Get Release",
|
|
826
718
|
summary: "Get more details for a specific release by its ID, including source control information and associated builds",
|
|
@@ -830,25 +722,7 @@ export class BugsnagClient {
|
|
|
830
722
|
"Analyze the stability data and targets for a release",
|
|
831
723
|
"See the builds that make up the release",
|
|
832
724
|
],
|
|
833
|
-
|
|
834
|
-
...(this.projectApiKey
|
|
835
|
-
? []
|
|
836
|
-
: [
|
|
837
|
-
{
|
|
838
|
-
name: "projectId",
|
|
839
|
-
type: z.string(),
|
|
840
|
-
description: "ID of the project containing the release",
|
|
841
|
-
required: true,
|
|
842
|
-
},
|
|
843
|
-
]),
|
|
844
|
-
{
|
|
845
|
-
name: "releaseId",
|
|
846
|
-
type: z.string(),
|
|
847
|
-
description: "ID of the release to retrieve",
|
|
848
|
-
required: true,
|
|
849
|
-
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
850
|
-
},
|
|
851
|
-
],
|
|
725
|
+
inputSchema: getReleaseInputSchema,
|
|
852
726
|
examples: [
|
|
853
727
|
{
|
|
854
728
|
description: "Get details for a specific release",
|
|
@@ -863,16 +737,15 @@ export class BugsnagClient {
|
|
|
863
737
|
idempotent: true,
|
|
864
738
|
outputDescription: "JSON object containing release details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
865
739
|
}, async (args, _extra) => {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
const
|
|
869
|
-
const releaseResponse = await this.projectApi.getReleaseGroup(args.releaseId);
|
|
740
|
+
const params = getReleaseInputSchema.parse(args);
|
|
741
|
+
const project = await this.getInputProject(params.projectId);
|
|
742
|
+
const releaseResponse = await this.projectApi.getReleaseGroup(params.releaseId);
|
|
870
743
|
if (!releaseResponse.body)
|
|
871
|
-
throw new ToolError(`No release for ${
|
|
744
|
+
throw new ToolError(`No release for ${params.releaseId} found.`);
|
|
872
745
|
const release = this.addStabilityData(releaseResponse.body, project);
|
|
873
746
|
let builds = [];
|
|
874
747
|
if (releaseResponse.body) {
|
|
875
|
-
const buildsResponse = await this.projectApi.listBuildsInRelease(
|
|
748
|
+
const buildsResponse = await this.projectApi.listBuildsInRelease(params.releaseId);
|
|
876
749
|
if (buildsResponse.body) {
|
|
877
750
|
builds = buildsResponse.body.map((b) => this.addStabilityData(b, project));
|
|
878
751
|
}
|
|
@@ -889,6 +762,10 @@ export class BugsnagClient {
|
|
|
889
762
|
],
|
|
890
763
|
};
|
|
891
764
|
});
|
|
765
|
+
const getBuildInputSchema = z.object({
|
|
766
|
+
projectId: toolInputParameters.projectId,
|
|
767
|
+
buildId: toolInputParameters.buildId,
|
|
768
|
+
});
|
|
892
769
|
register({
|
|
893
770
|
title: "Get Build",
|
|
894
771
|
summary: "Get more details for a specific build by its ID",
|
|
@@ -898,25 +775,7 @@ export class BugsnagClient {
|
|
|
898
775
|
"Analyze a specific build to correlate with error spikes or deployments",
|
|
899
776
|
"See the stability targets for a project and if the build meets them",
|
|
900
777
|
],
|
|
901
|
-
|
|
902
|
-
...(this.projectApiKey
|
|
903
|
-
? []
|
|
904
|
-
: [
|
|
905
|
-
{
|
|
906
|
-
name: "projectId",
|
|
907
|
-
type: z.string(),
|
|
908
|
-
description: "ID of the project containing the build",
|
|
909
|
-
required: true,
|
|
910
|
-
},
|
|
911
|
-
]),
|
|
912
|
-
{
|
|
913
|
-
name: "buildId",
|
|
914
|
-
type: z.string(),
|
|
915
|
-
description: "ID of the build to retrieve",
|
|
916
|
-
required: true,
|
|
917
|
-
examples: ["5f8d0d55c9e77c0017a1b2c3"],
|
|
918
|
-
},
|
|
919
|
-
],
|
|
778
|
+
inputSchema: getBuildInputSchema,
|
|
920
779
|
examples: [
|
|
921
780
|
{
|
|
922
781
|
description: "Get details for a specific build",
|
|
@@ -931,12 +790,11 @@ export class BugsnagClient {
|
|
|
931
790
|
idempotent: true,
|
|
932
791
|
outputDescription: "JSON object containing build details along with stability metrics such as user and session stability, and whether it meets project targets",
|
|
933
792
|
}, async (args, _extra) => {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
const
|
|
937
|
-
const response = await this.projectApi.getProjectReleaseById(project.id, args.buildId);
|
|
793
|
+
const params = getBuildInputSchema.parse(args);
|
|
794
|
+
const project = await this.getInputProject(params.projectId);
|
|
795
|
+
const response = await this.projectApi.getProjectReleaseById(project.id, params.buildId);
|
|
938
796
|
if (!response.body)
|
|
939
|
-
throw new ToolError(`No build for ${
|
|
797
|
+
throw new ToolError(`No build for ${params.buildId} found.`);
|
|
940
798
|
const build = this.addStabilityData(response.body, project);
|
|
941
799
|
return {
|
|
942
800
|
content: [{ type: "text", text: JSON.stringify(build) }],
|