@quorum-us/opsgenie-mcp
Version:
MCP server for Opsgenie alert management with comprehensive filtering, custom queries, and AI-friendly interface
115 lines (114 loc) • 3.95 kB
JavaScript
import axios from "axios";
import { DEFAULTS, ENDPOINTS, ERROR_MESSAGES, validateLimit, validateOffset, validateIdentifier, buildQueryParams, buildSearchQuery, } from './constants.js';
/**
* Opsgenie API Client class for handling all Opsgenie operations
*/
export class OpsgenieClient {
client;
apiKey;
baseUrl;
/**
* Constructor for OpsgenieClient
* @param config - Configuration object containing API key and optional settings
*/
constructor(config) {
this.apiKey = config.apiKey;
this.baseUrl = config.baseUrl ?? DEFAULTS.BASE_URL;
this.client = this.createHttpClient(config);
}
/**
* Create HTTP client with proper configuration
* @param config - Configuration object
* @returns Configured axios instance
*/
createHttpClient(config) {
return axios.create({
baseURL: this.baseUrl,
timeout: config.timeout ?? DEFAULTS.TIMEOUT,
headers: {
'Authorization': `GenieKey ${this.apiKey}`,
'Content-Type': 'application/json',
},
});
}
/**
* Generic method to handle API responses and errors for MCP
* @param apiCall - Promise that makes the API call
* @returns Promise that resolves to MCP response
*/
async handleApiCall(apiCall) {
try {
const response = await apiCall;
return {
content: [{
type: "text",
text: JSON.stringify(response.data)
}],
};
}
catch (error) {
const errorMessage = error.response?.data?.message || error.message || ERROR_MESSAGES.UNKNOWN_ERROR;
return {
isError: true,
content: [{
type: "text",
text: `Error: ${errorMessage}`,
}],
structuredContent: {},
};
}
}
/**
* List alerts with comprehensive filtering options
* @param filter - Filter options for alerts
* @returns Promise that resolves to MCP response
*/
async listAlerts(filter = {}) {
// Build the search query from filter options
const searchQuery = buildSearchQuery({
query: filter.query,
status: filter.status,
priority: filter.priority,
message: filter.message,
source: filter.source,
owner: filter.owner,
tags: filter.tags,
teams: filter.teams,
});
const params = buildQueryParams({
query: searchQuery || undefined,
searchIdentifier: filter.searchIdentifier,
searchIdentifierType: filter.searchIdentifierType,
offset: validateOffset(filter.offset),
limit: validateLimit(filter.limit),
sort: filter.sort ?? DEFAULTS.ALERT_SORT,
order: filter.order ?? DEFAULTS.ALERT_ORDER,
});
return this.handleApiCall(this.client.get(ENDPOINTS.ALERTS, { params }));
}
/**
* Get details of a specific alert
* @param identifier - Alert identifier (ID or alias)
* @returns Promise that resolves to MCP response
*/
async getAlert(identifier) {
validateIdentifier(identifier);
return this.handleApiCall(this.client.get(ENDPOINTS.ALERT_BY_ID(identifier)));
}
}
/**
* Factory function to create an OpsgenieClient instance
* @param apiKey - Opsgenie API key
* @param config - Optional additional configuration
* @returns OpsgenieClient instance
*/
export function createOpsgenieClient(apiKey, config = {}) {
const finalApiKey = apiKey ?? process.env.OPSGENIE_API_KEY;
if (!finalApiKey) {
throw new Error(ERROR_MESSAGES.API_KEY_MISSING);
}
return new OpsgenieClient({
apiKey: finalApiKey,
...config,
});
}