import { ToolExecutionError } from '../../utils/error-handling.js'; import { getLogger } from '../../utils/logging.js'; import { parseTimeString, getDateFromTimestamp } from '../../utils/time-utils.js'; import { trackToolRequest } from '../../utils/metrics.js'; import { validateWithZod } from '../../utils/validation.js'; import { CloudTrailService, createCloudTrailService } from '../../services/aws/cloudtrail.js'; import { McpToolResponse, CloudTrailEventsParams } from '../../types/tools.js'; import { Event } from '@aws-sdk/client-cloudtrail'; // CloudTrailEventInfo is imported but not used in this file // import { CloudTrailEventInfo } from '../../types/aws.js'; import { CloudTrailEventsSchema } from '../../types/validation-schemas.js'; const logger = getLogger(); const service: CloudTrailService = createCloudTrailService(); /** * Format CloudTrail events for display * @param events Array of CloudTrail events * @returns Formatted events as JSON string */ function formatCloudTrailEvents(events: Event[]): string { if (events.length === 0) { return 'No CloudTrail events found matching the criteria.'; } return JSON.stringify(events, null, 2); } /** * Tool to retrieve CloudTrail events * @param params Tool parameters * @returns MCP tool response */ export async function cloudTrailEventsTool(params: CloudTrailEventsParams): Promise { // Validate input parameters const validatedParams = validateWithZod( CloudTrailEventsSchema, params, 'CloudTrail events parameters' ); const { eventName, username, resourceName, resourceType, startTime, endTime, limit } = validatedParams; const startAppTime = Date.now(); let success = false; try { // Process time inputs let startTimeMs: number | undefined; const endTimeMs = endTime ? parseTimeString(endTime) : undefined; startTimeMs = startTime ? parseTimeString(startTime) : undefined; // Default to 1 hour ago if no start time if (!startTimeMs) { startTimeMs = Date.now() - 60 * 60 * 1000; } // Convert milliseconds to Date objects const startTimeDate = startTimeMs ? getDateFromTimestamp(startTimeMs) : undefined; const endTimeDate = endTimeMs ? getDateFromTimestamp(endTimeMs) : undefined; logger.info('Looking up CloudTrail events', { eventName: eventName || 'any', username: username || 'any', resourceName: resourceName || 'any', resourceType: resourceType || 'any', startTime: startTimeDate?.toISOString() || 'undefined', endTime: endTimeDate?.toISOString() || 'undefined', limit: limit || 50 }); // Call the service const events: Event[] = await service.lookupEvents({ eventName, username, resourceName, resourceType, startTime: startTimeDate, endTime: endTimeDate, limit: limit || 50 }); // Format the events const formattedEvents = formatCloudTrailEvents(events); success = true; return { content: [{ type: 'text' as const, text: formattedEvents }] }; } catch (error) { logger.error('Error retrieving CloudTrail events:', error); // Create a sanitized version of the parameters for error context const errorParams = { eventName: eventName || undefined, username: username || undefined, resourceName: resourceName || undefined, resourceType: resourceType || undefined, startTime: startTime ? 'provided' : undefined, endTime: endTime ? 'provided' : undefined, limit: limit || 50 }; // Wrap the error with tool execution context throw new ToolExecutionError( `Failed to retrieve CloudTrail events: ${error instanceof Error ? error.message : String(error)}`, 'cloudTrailEvents', errorParams, error ); } finally { // Track metrics for this tool invocation const responseTime = Date.now() - startAppTime; trackToolRequest('cloudTrailEvents', responseTime, success); } }