All files / src/tools getMEPDetails.ts

76.47% Statements 13/17
50% Branches 2/4
66.66% Functions 2/3
80% Lines 12/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 120 121                                                                                                                12x 12x   6x 9x 6x                     6x   6x     4x   4x   2x                   2x                         4x                                
/**
 * MCP Tool: get_mep_details
 * 
 * Retrieve detailed information about a specific MEP
 * 
 * **Intelligence Perspective:** Enables deep-dive MEP profiling including voting statistics,
 * committee memberships, political group alignment, and behavioral pattern analysis for
 * individual actor intelligence assessments.
 * 
 * **Business Perspective:** Powers premium MEP profile products for corporate affairs teams,
 * lobbyists, and political consultancies requiring comprehensive stakeholder intelligence.
 * 
 * **Marketing Perspective:** Demonstrates depth of EP data access—key differentiator
 * for attracting enterprise customers and academic researchers.
 * 
 * ISMS Policy: SC-002 (Input Validation), AU-002 (Audit Logging), GDPR Compliance
 */
 
import { GetMEPDetailsSchema, MEPDetailsSchema } 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_mep_details MCP tool request.
 *
 * Retrieves comprehensive information about a single MEP identified by their unique ID,
 * including biography, contact details, committee memberships, voting statistics, and
 * parliamentary activities. Access to personal data is audit-logged for GDPR compliance.
 *
 * @param args - Raw tool arguments, validated against {@link GetMEPDetailsSchema}
 * @returns MCP tool result containing detailed MEP profile data including biography,
 *   contact information, committee roles, voting record, and activity statistics
 * @throws - If `args` fails schema validation (e.g., missing or empty `id` field)
 * - If the European Parliament API is unreachable or returns an error response
 *
 * @example
 * ```typescript
 * const result = await handleGetMEPDetails({ id: 'MEP-124810' });
 * // Returns full profile for MEP 124810, including committees and voting stats
 * ```
 *
 * @security Input is validated with Zod before any API call.
 *   Personal data (biography, contact info) access is audit-logged per GDPR Art. 5(2)
 *   and ISMS Policy AU-002. Data minimisation applied per GDPR Article 5(1)(c).
 * @since 0.8.0
 * @see {@link getMEPDetailsToolMetadata} for MCP schema registration
 * @see {@link handleGetMEPs} for listing MEPs and obtaining valid IDs
 */
export async function handleGetMEPDetails(
  args: unknown
): Promise<ToolResult> {
  // Validate input — ZodErrors here are client mistakes (non-retryable)
  let params: ReturnType<typeof GetMEPDetailsSchema.parse>;
  try {
    params = GetMEPDetailsSchema.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_mep_details',
        operation: 'validateInput',
        message: `Invalid parameters: ${fieldErrors}`,
        isRetryable: false,
        cause: error,
      });
    }
    throw error;
  }
 
  try {
    // Fetch MEP details from EP API
    const result = await epClient.getMEPDetails(params.id);
    
    // Validate output
    const validated = MEPDetailsSchema.parse(result);
    
    return buildToolResponse(validated);
  } catch (error: unknown) {
    Iif (error instanceof z.ZodError) {
      const fieldErrors = error.issues.map(e => `${e.path.join('.')}: ${e.message}`).join('; ');
      throw new ToolError({
        toolName: 'get_mep_details',
        operation: 'validateOutput',
        message: `Unexpected EP API response format: ${fieldErrors}`,
        isRetryable: false,
        cause: error,
      });
    }
    throw new ToolError({
      toolName: 'get_mep_details',
      operation: 'fetchData',
      message: 'Failed to retrieve MEP details',
      isRetryable: true,
      cause: error,
    });
  }
}
 
/**
 * Tool metadata for MCP registration
 */
export const getMEPDetailsToolMetadata = {
  name: 'get_mep_details',
  description: 'Retrieve detailed information about a specific Member of European Parliament including biography, contact information, committee memberships, voting statistics, and parliamentary activities. Personal data access is logged for GDPR compliance.',
  inputSchema: {
    type: 'object' as const,
    properties: {
      id: {
        type: 'string',
        description: 'MEP identifier (e.g., "MEP-124810")',
        minLength: 1,
        maxLength: 100
      }
    },
    required: ['id']
  }
};