@raygun.io/mcp-server-raygun
Version:
MCP Server for Raygun's API V3 endpoints for interacting with your Crash Reporting and Real User Monitoring applications
200 lines (199 loc) • 9.24 kB
JavaScript
import { ConfigSchema, } from "./types.js";
import * as fs from "node:fs/promises";
export class RaygunError extends Error {
status;
details;
constructor(message, status, details) {
super(message);
this.status = status;
this.details = details;
this.name = "RaygunError";
}
}
export class RaygunAPIV3Client {
config;
constructor(config) {
this.config = ConfigSchema.parse({
baseUrl: "https://api.raygun.com/v3",
...config,
});
}
async request(method, path, body, queryParams) {
const url = new URL(this.config.baseUrl + path);
if (queryParams) {
Object.entries(queryParams).forEach(([key, value]) => {
if (value != null && value !== '') {
url.searchParams.append(key, String(value));
}
});
}
const response = await fetch(url.toString(), {
method,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.config.apiKey}`,
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
throw new RaygunError(`Raygun API error: ${url.toString()}: ${response.status}`, response.status, await response.json().catch(() => undefined));
}
if (response.status === 204) {
return undefined;
}
return response.json();
}
// Applications
async listApplications(options) {
return this.request("GET", "/applications", undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(",") || "",
});
}
async getApplication(applicationIdentifier) {
return this.request('GET', `/applications/${applicationIdentifier}`);
}
async getApplicationByApiKey(apiKey) {
return this.request('GET', `/applications/api-key/${apiKey}`);
}
async regenerateApplicationApiKey(applicationIdentifier) {
return this.request('POST', `/applications/${applicationIdentifier}/regenerate-api-key`);
}
async listCustomers(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/customers`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || '',
});
}
async listDeployments(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/deployments`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || '',
});
}
async getDeployment(applicationIdentifier, deploymentIdentifier) {
return this.request('GET', `/applications/${applicationIdentifier}/deployments/${deploymentIdentifier}`);
}
async deleteDeployment(applicationIdentifier, deploymentIdentifier) {
return this.request('DELETE', `/applications/${applicationIdentifier}/deployments/${deploymentIdentifier}`);
}
async updateDeployment(applicationIdentifier, deploymentIdentifier, updateData) {
return this.request('PATCH', `/applications/${applicationIdentifier}/deployments/${deploymentIdentifier}`, updateData);
}
async reprocessDeploymentCommits(applicationIdentifier, deploymentIdentifier) {
return this.request('POST', `/applications/${applicationIdentifier}/deployments/${deploymentIdentifier}/reprocess-commits`);
}
async listErrorGroups(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/error-groups`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || '',
});
}
async getErrorGroup(applicationIdentifier, errorGroupIdentifier) {
return this.request('GET', `/applications/${applicationIdentifier}/error-groups/${errorGroupIdentifier}`);
}
async resolveErrorGroup(applicationIdentifier, errorGroupIdentifier, data) {
return this.request('POST', `/applications/${applicationIdentifier}/error-groups/${errorGroupIdentifier}/resolve`, data);
}
async activateErrorGroup(applicationIdentifier, errorGroupIdentifier) {
return this.request('POST', `/applications/${applicationIdentifier}/error-groups/${errorGroupIdentifier}/activate`);
}
async ignoreErrorGroup(applicationIdentifier, errorGroupIdentifier) {
return this.request('POST', `/applications/${applicationIdentifier}/error-groups/${errorGroupIdentifier}/ignore`);
}
async permanentlyIgnoreErrorGroup(applicationIdentifier, errorGroupIdentifier, data) {
return this.request('POST', `/applications/${applicationIdentifier}/error-groups/${errorGroupIdentifier}/permanently-ignore`, data);
}
async listInvitations(options) {
return this.request('GET', '/invitations', undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || ''
});
}
async sendInvitation(data) {
return this.request('POST', '/invitations', data);
}
async getInvitation(invitationIdentifier) {
return this.request('GET', `/invitations/${invitationIdentifier}`);
}
async revokeInvitation(invitationIdentifier) {
return this.request('POST', `/invitations/${invitationIdentifier}/revoke`);
}
async listPages(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/pages`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || '',
});
}
async getPageMetricsTimeSeries(applicationIdentifier, params) {
return this.request('POST', `/metrics/${applicationIdentifier}/pages/time-series`, params);
}
async getPageMetricsHistogram(applicationIdentifier, params) {
return this.request('POST', `/metrics/${applicationIdentifier}/pages/histogram`, params);
}
async getErrorMetricsTimeSeries(applicationIdentifier, params) {
return this.request('POST', `/metrics/${applicationIdentifier}/errors/time-series`, params);
}
async listSessions(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/sessions`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
filter: options?.filter || '',
orderby: options?.orderBy?.join(',') || '',
});
}
async getSession(applicationIdentifier, sessionIdentifier, options) {
const params = {};
if (options?.include) {
params.include = options.include.join(',');
}
return this.request('GET', `/applications/${applicationIdentifier}/sessions/${sessionIdentifier}`, undefined, params);
}
async listSourceMaps(applicationIdentifier, options) {
return this.request('GET', `/applications/${applicationIdentifier}/source-maps`, undefined, {
count: options?.count || 100,
offset: options?.offset || 0,
orderby: options?.orderBy?.join(',') || ''
});
}
async getSourceMap(applicationIdentifier, sourceMapIdentifier) {
return this.request('GET', `/applications/${applicationIdentifier}/source-maps/${sourceMapIdentifier}`);
}
async updateSourceMap(applicationIdentifier, sourceMapIdentifier, data) {
return this.request('PATCH', `/applications/${applicationIdentifier}/source-maps/${sourceMapIdentifier}`, data);
}
async deleteSourceMap(applicationIdentifier, sourceMapIdentifier) {
return this.request('DELETE', `/applications/${applicationIdentifier}/source-maps/${sourceMapIdentifier}`);
}
async uploadSourceMap(applicationIdentifier, filePath, uri) {
const formData = new FormData();
const fileStream = await fs.readFile(filePath);
const file = new Blob([fileStream], {
type: 'application/json'
});
const fileName = filePath.split('/').pop() || 'sourcemap.js.map';
formData.append('file', file, fileName);
formData.append('uri', uri);
const url = new URL(this.config.baseUrl + `/applications/${applicationIdentifier}/source-maps`);
const response = await fetch(url.toString(), {
method: 'PUT',
headers: {
Authorization: `Bearer ${this.config.apiKey}`,
},
body: formData,
});
if (!response.ok) {
throw new RaygunError(`Raygun API error: ${url.toString()}: ${response.status}`, response.status, await response.json().catch(() => undefined));
}
return response.json();
}
async deleteAllSourceMaps(applicationIdentifier) {
return this.request('DELETE', `/applications/${applicationIdentifier}/source-maps`);
}
}