All files / src/tools getEvents.ts

95.45% Statements 21/22
90% Branches 9/10
100% Functions 2/2
94.44% Lines 17/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                                                                                                                    16x 16x   5x 5x 5x                     11x 11x 1x 1x     10x       10x 10x 10x   10x   9x   1x                   4x                                          
/**
 * MCP Tool: get_events
 *
 * Retrieve European Parliament events (hearings, conferences, seminars).
 * Supports single event lookup by eventId or list with date range filtering.
 *
 * **Intelligence Perspective:** Event monitoring enables early detection of emerging
 * policy priorities and stakeholder engagement patterns.
 *
 * **Business Perspective:** Event data powers calendar integration and stakeholder
 * engagement tracking products.
 *
 * **EP API Endpoints:**
 * - `GET /events` (list)
 * - `GET /events/{event-id}` (single)
 *
 * ISMS Policy: SC-002 (Input Validation), AC-003 (Least Privilege)
 */
 
import { GetEventsSchema } from '../schemas/europeanParliament.js';
import { epClient } from '../clients/europeanParliamentClient.js';
import { buildToolResponse } from './shared/responseBuilder.js';
import { ToolError } from './shared/errors.js';
import { z } from 'zod';
import type { ToolResult } from './shared/types.js';
 
/**
 * Handles the get_events MCP tool request.
 *
 * Retrieves European Parliament events including hearings, conferences, and seminars.
 * Supports single event lookup by eventId or a paginated list filtered by date range.
 *
 * @param args - Raw tool arguments, validated against {@link GetEventsSchema}
 * @returns MCP tool result containing either a single event record or a paginated list of EP events
 * @throws - If `args` fails schema validation (e.g., missing required fields or invalid format)
 * - If the European Parliament API is unreachable or returns an error response
 *
 * @example
 * ```typescript
 * // Single event lookup
 * const result = await handleGetEvents({ eventId: 'EVT-2024-001' });
 * // Returns the full record for the specified event
 *
 * // List events within a date range
 * const list = await handleGetEvents({ dateFrom: '2024-06-01', dateTo: '2024-06-30', limit: 30 });
 * // Returns up to 30 EP events in June 2024
 * ```
 *
 * @security - Input is validated with Zod before any API call.
 * - Personal data in responses is minimised per GDPR Article 5(1)(c).
 * - All requests are rate-limited and audit-logged per ISMS Policy AU-002.
 * @since 0.8.0
 * @see {@link getEventsToolMetadata} for MCP schema registration
 * @see {@link handleGetMeetingActivities} for retrieving activities within a specific plenary sitting
 */
export async function handleGetEvents(args: unknown): Promise<ToolResult> {
  // Validate input — ZodErrors here are client mistakes (non-retryable)
  let params: ReturnType<typeof GetEventsSchema.parse>;
  try {
    params = GetEventsSchema.parse(args);
  } catch (error: unknown) {
    Eif (error instanceof z.ZodError) {
      const fieldErrors = error.issues.map((e) => `${e.path.join('.')}: ${e.message}`).join('; ');
      throw new ToolError({
        toolName: 'get_events',
        operation: 'validateInput',
        message: `Invalid parameters: ${fieldErrors}`,
        isRetryable: false,
        cause: error,
      });
    }
    throw error;
  }
 
  try {
    if (params.eventId !== undefined) {
      const result = await epClient.getEventById(params.eventId);
      return buildToolResponse(result);
    }
 
    const apiParams: Record<string, unknown> = {
      limit: params.limit,
      offset: params.offset,
    };
    if (params.year !== undefined) apiParams['year'] = params.year;
    if (params.dateFrom !== undefined) apiParams['dateFrom'] = params.dateFrom;
    if (params.dateTo !== undefined) apiParams['dateTo'] = params.dateTo;
 
    const result = await epClient.getEvents(apiParams as Parameters<typeof epClient.getEvents>[0]);
 
    return buildToolResponse(result);
  } catch (error: unknown) {
    throw new ToolError({
      toolName: 'get_events',
      operation: 'fetchData',
      message: 'Failed to retrieve events',
      isRetryable: true,
      cause: error,
    });
  }
}
/** Tool metadata for get_events */
export const getEventsToolMetadata = {
  name: 'get_events',
  description:
    'Get European Parliament events including hearings, conferences, seminars, and institutional events. Supports single event lookup by eventId or list with year or date range filtering. Data source: European Parliament Open Data Portal.',
  inputSchema: {
    type: 'object' as const,
    properties: {
      eventId: { type: 'string', description: 'Event ID for single event lookup' },
      year: {
        type: 'number',
        description: 'Filter by calendar year (recommended for annual counts)',
        minimum: 1900,
        maximum: 2100,
      },
      dateFrom: { type: 'string', description: 'Start date (YYYY-MM-DD)' },
      dateTo: { type: 'string', description: 'End date (YYYY-MM-DD)' },
      limit: { type: 'number', description: 'Maximum results to return (1-100)', default: 50 },
      offset: { type: 'number', description: 'Pagination offset', default: 0 },
    },
  },
};