All files / src/tools getProcedures.ts

93.75% Statements 15/16
75% Branches 3/4
100% Functions 2/2
93.33% Lines 14/15

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                                                                                                                        16x 16x   6x 6x 6x                     10x 10x 1x 1x     9x           9x       8x   1x                   4x                            
/**
 * MCP Tool: get_procedures
 *
 * Retrieve European Parliament legislative procedures.
 * Supports single procedure lookup by processId or list with year filtering.
 *
 * **Intelligence Perspective:** Procedure data enables end-to-end legislative tracking,
 * outcome prediction, and timeline analysis—core for policy monitoring intelligence.
 *
 * **Business Perspective:** Procedure tracking powers legislative intelligence products,
 * regulatory risk assessments, and compliance early-warning systems.
 *
 * **EP API Endpoints:**
 * - `GET /procedures` (list)
 * - `GET /procedures/{process-id}` (single)
 *
 * ISMS Policy: SC-002 (Input Validation), AC-003 (Least Privilege)
 */
 
import { GetProceduresSchema } from '../schemas/europeanParliament.js';
import { epClient } from '../clients/europeanParliamentClient.js';
import { buildToolResponse } from './shared/responseBuilder.js';
import { buildApiParams } from './shared/paramBuilder.js';
import { ToolError } from './shared/errors.js';
import { z } from 'zod';
import type { ToolResult } from './shared/types.js';
 
/**
 * Handles the get_procedures MCP tool request.
 *
 * Retrieves European Parliament legislative procedures enabling end-to-end legislative
 * tracking, outcome prediction, and timeline analysis. Supports both a single-procedure
 * lookup by `processId` and a paginated list optionally filtered by year.
 *
 * @param args - Raw tool arguments, validated against {@link GetProceduresSchema}
 * @returns MCP tool result containing procedure data (single procedure or paginated list)
 * @throws - If `args` fails schema validation (e.g., invalid field types or formats)
 * - If the European Parliament API is unreachable or returns an error response
 *
 * @example
 * ```typescript
 * // Single procedure lookup
 * const single = await handleGetProcedures({ processId: '2023/0132(COD)' });
 * // Returns the legislative procedure for the Artificial Intelligence Act
 *
 * // List procedures from 2024
 * const list = await handleGetProcedures({ year: 2024, limit: 50, offset: 0 });
 * // Returns up to 50 legislative procedures initiated in 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 getProceduresToolMetadata} for MCP schema registration
 * @see {@link handleGetProcedureEvents} for retrieving events linked to a specific procedure
 */
export async function handleGetProcedures(args: unknown): Promise<ToolResult> {
  // Validate input — ZodErrors here are client mistakes (non-retryable)
  let params: ReturnType<typeof GetProceduresSchema.parse>;
  try {
    params = GetProceduresSchema.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_procedures',
        operation: 'validateInput',
        message: `Invalid parameters: ${fieldErrors}`,
        isRetryable: false,
        cause: error,
      });
    }
    throw error;
  }
 
  try {
    if (params.processId !== undefined) {
      const result = await epClient.getProcedureById(params.processId);
      return buildToolResponse(result);
    }
 
    const apiParams = {
      limit: params.limit,
      offset: params.offset,
      ...buildApiParams(params, [{ from: 'year', to: 'year' }]),
    };
 
    const result = await epClient.getProcedures(
      apiParams as Parameters<typeof epClient.getProcedures>[0]
    );
 
    return buildToolResponse(result);
  } catch (error: unknown) {
    throw new ToolError({
      toolName: 'get_procedures',
      operation: 'fetchData',
      message: 'Failed to retrieve procedures',
      isRetryable: true,
      cause: error,
    });
  }
}
/** Tool metadata for get_procedures */
export const getProceduresToolMetadata = {
  name: 'get_procedures',
  description:
    'Get European Parliament legislative procedures. Supports single procedure lookup by processId or list with year filter. Data source: European Parliament Open Data Portal.',
  inputSchema: {
    type: 'object' as const,
    properties: {
      processId: { type: 'string', description: 'Process ID for single procedure lookup' },
      year: { type: 'number', description: 'Filter by year (e.g., 2024)' },
      limit: { type: 'number', description: 'Maximum results to return (1-100)', default: 50 },
      offset: { type: 'number', description: 'Pagination offset', default: 0 },
    },
  },
};