European Parliament MCP Server API - v1.3.9
    Preparing search index...

    Integration Testing Guide

    This guide explains how to run integration tests for the European Parliament MCP Server. The allTools.integration.test.ts suite validates 46 of the 62 MCP tools against the real European Parliament Open Data API. The remaining 16 tools โ€” 13 feed endpoints, get_all_generated_stats (precomputed, no live API calls), get_server_health (local diagnostics, no API calls), and get_procedure_event_by_id โ€” are validated through unit tests. All integration-tested tools return real data โ€” no mock or placeholder data is used.

    ISMS Policy: Hack23 Secure Development Policy - Testing

    Compliance: ISO 27001 (AU-2), NIST CSF 2.0 (DE.CM-6), CIS Controls v8.1 (8.11)


    Core Data Access Tools (7 โ€” real EP API):

    1. get_meps - MEP retrieval with filtering
    2. get_mep_details - Individual MEP information
    3. get_plenary_sessions - Plenary session data
    4. get_voting_records - Voting record access
    5. search_documents - Document search
    6. get_committee_info - Committee information
    7. get_parliamentary_questions - Parliamentary questions

    Advanced Analysis Tools (3 โ€” real EP API data): 8. analyze_voting_patterns - Voting pattern analysis 9. track_legislation - Legislative procedure tracking (real EP API /procedures) 10. generate_report - Report generation

    OSINT Intelligence Tools โ€” Phase 1 (6 โ€” real EP API data): 11. assess_mep_influence - MEP influence scoring (5-dimension model) 12. analyze_coalition_dynamics - Coalition cohesion & stress analysis 13. detect_voting_anomalies - Party defection & anomaly detection 14. compare_political_groups - Cross-group comparative analysis 15. analyze_legislative_effectiveness - MEP/committee legislative scoring 16. monitor_legislative_pipeline - Pipeline status (real EP API /procedures)

    OSINT Intelligence Tools โ€” Phase 2 (2 โ€” real EP API data): 17. analyze_committee_activity - Committee workload & engagement analysis 18. track_mep_attendance - MEP attendance patterns & trends

    OSINT Intelligence Tools โ€” Phase 3 (2 โ€” real EP API data): 19. analyze_country_delegation - Country delegation voting & composition analysis 20. generate_political_landscape - Parliament-wide political landscape overview

    OSINT Intelligence Tools โ€” Phase 6 (5 โ€” real EP API data): 21. network_analysis - MEP network and relationship analysis 22. sentiment_tracker - Political group sentiment tracking 23. early_warning_system - Political risk early warning detection 24. comparative_intelligence - Multi-MEP comparative intelligence analysis 25. correlate_intelligence - Multi-dimensional OSINT intelligence correlation analysis

    EP Data Access Tools โ€” Phase 4 (8 โ€” real EP API v2): 26. get_current_meps - Currently serving MEPs 27. get_speeches - Plenary speeches 28. get_procedures - Legislative procedures 29. get_adopted_texts - Adopted legislative texts 30. get_events - Parliamentary events 31. get_meeting_activities - Meeting activity records 32. get_meeting_decisions - Meeting decision outcomes 33. get_mep_declarations - MEP financial declarations

    EP Complete Coverage Tools โ€” Phase 5 (14 โ€” real EP API v2): 34. get_incoming_meps - Incoming MEPs (new members) 35. get_outgoing_meps - Outgoing MEPs (departing members) 36. get_homonym_meps - MEPs with duplicate names 37. get_plenary_documents - Plenary-specific documents 38. get_committee_documents - Committee-specific documents 39. get_plenary_session_documents - Session-specific documents 40. get_plenary_session_document_items - Document items within sessions 41. get_controlled_vocabularies - EP controlled vocabulary terms 42. get_external_documents - External reference documents 43. get_meeting_foreseen_activities - Planned meeting activities 44. get_procedure_events - Events linked to a procedure 45. get_meeting_plenary_session_documents - Plenary session meeting documents 46. get_meeting_plenary_session_document_items - Plenary session meeting document items 47. get_procedure_event_by_id - Single event for a specific procedure

    Precomputed Analytics (1 โ€” static data, no live EP API calls): 48. get_all_generated_stats - Precomputed EP activity statistics (2004โ€“2026); returns static data refreshed weekly by agentic workflow

    EP Data Feed Tools (13 โ€” real EP API v2 feeds): 49. get_meps_feed - Recently updated MEPs 50. get_events_feed - Recently updated events 51. get_procedures_feed - Recently updated procedures 52. get_adopted_texts_feed - Recently updated adopted texts 53. get_mep_declarations_feed - Recently updated MEP declarations 54. get_documents_feed - Recently updated documents 55. get_plenary_documents_feed - Recently updated plenary documents 56. get_committee_documents_feed - Recently updated committee documents 57. get_plenary_session_documents_feed - Recently updated plenary session documents 58. get_external_documents_feed - Recently updated external documents 59. get_parliamentary_questions_feed - Recently updated parliamentary questions 60. get_corporate_bodies_feed - Recently updated corporate bodies 61. get_controlled_vocabularies_feed - Recently updated controlled vocabularies

    Server Diagnostics (1 โ€” local only, no EP API calls): 62. get_server_health - Server health and feed availability status

    No Mock Data: All tools return real data from the EP API. The integration test suite (allTools.integration.test.ts) currently covers 46 of 62 tools (core, advanced, OSINT, phase 4, and phase 5 data tools). Feed tools and precomputed analytics tools are validated through unit tests. The suite explicitly checks that no tool returns confidenceLevel: 'NONE' or PLACEHOLDER DATA markers.

    Each tool includes comprehensive tests for:

    • โœ… Basic Retrieval - Core functionality validation
    • โœ… Filtering - Query parameter validation
    • โœ… Pagination - Offset and limit handling
    • โœ… Error Handling - Invalid input rejection
    • โœ… Response Validation - Schema compliance
    • โœ… Performance - Response time validation (<5s uncached, <1s cached)
    • โœ… Data Consistency - Repeated request validation
    • โœ… GDPR Compliance - PII handling (where applicable)

    The 15 OSINT tools share a common metadata envelope (OsintStandardOutput โ€” confidenceLevel, methodology, dataFreshness, sourceAttribution, dataQualityWarnings). A single, registry-driven contract test enforces that envelope uniformly across every OSINT tool so regressions cannot land undetected.

    Location: tests/integration/osint/contract.test.ts

    Driver: Iterates getToolMetadataArray().filter(t => t.category === 'osint'), so adding a new OSINT tool automatically enrols it in the contract suite (the only change required is a minimal-input entry in the test's TOOL_INPUTS map).

    For every OSINT tool, with EP and DOCEO clients mocked deterministically:

    1. Envelope schema โ€” response payload parses against OsintStandardOutputSchema.
    2. Confidence level โ€” confidenceLevel โˆˆ {HIGH, MEDIUM, LOW} (per the schema).
    3. Non-empty fields โ€” methodology, dataFreshness, sourceAttribution are non-empty strings; sourceAttribution references the EP Open Data Portal.
    4. No-silent-zero policy โ€” when underlying data is unavailable (mocked-empty EP API) and the tool degrades confidenceLevel to LOW or MEDIUM, dataQualityWarnings MUST be non-empty so callers can see why numeric metrics are zero. Tools that silently emit zeros without warnings violate the data-quality intent of the envelope and fail this test.
    5. Determinism โ€” invoking each tool twice with the same input yields byte-identical JSON payloads after stripping volatile fields (analysisTime, assessmentTime, generatedAt, timestamp, correlationId, runId, requestId, computedAt, asOf). Wall-clock is pinned via vi.setSystemTime to keep timestamp-derived envelope wording stable within a test.

    If any numeric field outside dataQualityWarnings would be zero because a data source is unavailable (rather than because the underlying real-world count is actually zero), the tool MUST add a dataQualityWarnings entry explaining the unavailability. The contract test enforces the observable side of this policy: whenever confidenceLevel is LOW or MEDIUM, dataQualityWarnings MUST be non-empty. A degraded confidence level with no accompanying warning is treated as a silent-zero regression and fails the test. Tools whose remaining (per-MEP) data is sufficient to legitimately keep confidenceLevel = HIGH are allowed to do so without a warning.

    # All 45 contract checks (15 tools ร— 3 scenarios), no network calls
    npx vitest run tests/integration/osint/contract.test.ts

    The suite completes in ~1 s because it uses vi.mock to stub the EP and DOCEO clients with synthetic, redacted fixtures from tests/fixtures/osintPhase6Fixtures.ts. It runs automatically as part of npm run test:integration in the Integration and E2E Tests CI workflow.

    1. Register the tool in src/server/toolRegistry.ts with category: 'osint'.
    2. Add the minimal-valid input for the tool in TOOL_INPUTS inside tests/integration/osint/contract.test.ts.
    3. Run npx vitest run tests/integration/osint/contract.test.ts โ€” a failing beforeAll will list any registered OSINT tool that lacks a TOOL_INPUTS entry.
    4. If the new tool calls an EP API method not yet mocked in installDefaultMocks(), add a default mock there (use emptyPaginated() for list endpoints).

    • Node.js 25.x or higher
    • npm 10.0.0 or higher
    • Network access to https://data.europarl.europa.eu

    Integration tests are disabled by default to avoid accidental real API calls and rate limit issues.

    # Enable and run all integration tests
    EP_INTEGRATION_TESTS=true npm run test:integration

    # Run specific tool tests
    EP_INTEGRATION_TESTS=true npm run test:integration -- getMEPs

    # Run with fixture capture enabled
    EP_INTEGRATION_TESTS=true EP_SAVE_FIXTURES=true npm run test:integration

    # Run with verbose output
    EP_INTEGRATION_TESTS=true npm run test:integration -- --reporter=verbose
    Variable Default Description
    EP_INTEGRATION_TESTS false Enable integration tests (set to true to run)
    EP_SAVE_FIXTURES false Save real API responses as test fixtures
    EP_API_URL https://data.europarl.europa.eu/api/v2/ European Parliament API base URL (must include trailing /)

    Important: Always include a trailing / in EP_API_URL. The client builds URLs with new URL(endpoint, baseURL), and omitting the trailing slash (for example using /api/v2 instead of /api/v2/) can cause the v2 path segment to be dropped when resolving endpoints.


    tests/
    โ”œโ”€โ”€ integration/
    โ”‚ โ”œโ”€โ”€ setup.ts # Test environment configuration
    โ”‚ โ”œโ”€โ”€ epApi.integration.test.ts # API client integration tests
    โ”‚ โ”œโ”€โ”€ helpers/
    โ”‚ โ”‚ โ”œโ”€โ”€ responseValidator.ts # Response validation utilities
    โ”‚ โ”‚ โ””โ”€โ”€ fixtureManager.ts # Fixture capture utilities
    โ”‚ โ””โ”€โ”€ tools/
    โ”‚ โ”œโ”€โ”€ allTools.integration.test.ts # 46 tools integration coverage
    โ”‚ โ”œโ”€โ”€ getMEPs.integration.test.ts
    โ”‚ โ”œโ”€โ”€ getMEPDetails.integration.test.ts
    โ”‚ โ”œโ”€โ”€ getPlenarySessions.integration.test.ts
    โ”‚ โ”œโ”€โ”€ getVotingRecords.integration.test.ts
    โ”‚ โ”œโ”€โ”€ searchDocuments.integration.test.ts
    โ”‚ โ”œโ”€โ”€ getCommitteeInfo.integration.test.ts
    โ”‚ โ”œโ”€โ”€ getParliamentaryQuestions.integration.test.ts
    โ”‚ โ”œโ”€โ”€ analyzeVotingPatterns.integration.test.ts
    โ”‚ โ”œโ”€โ”€ trackLegislation.integration.test.ts
    โ”‚ โ””โ”€โ”€ generateReport.integration.test.ts
    โ””โ”€โ”€ fixtures/
    โ””โ”€โ”€ real-api/ # Captured real API responses
    โ”œโ”€โ”€ get_meps/
    โ”œโ”€โ”€ get_mep_details/
    โ”œโ”€โ”€ get_plenary_sessions/
    โ””โ”€โ”€ ...

    Validates MCP tool responses against expected schemas:

    import { validatePaginatedResponse, validateMEPStructure } from '../helpers/responseValidator.js';

    const response = validatePaginatedResponse(result);
    response.data.forEach(mep => validateMEPStructure(mep));

    Captures real API responses for offline testing:

    import { saveMCPResponseFixture } from '../helpers/fixtureManager.js';

    saveMCPResponseFixture('get_meps', 'swedish-meps', result);

    • Rate Limit: Approximately 100 requests per 15 minutes per endpoint
    • No Authentication Required: Public data access
    • Response Format: JSON-LD (primary), RDF/XML, Turtle

    Integration tests implement several strategies to respect rate limits:

    1. Sequential Execution: Tests run one at a time within each suite
    2. Inter-Test Delays: 100ms wait between tests (provides breathing room, not strict rate limiting)
    3. Retry Logic: Exponential backoff for transient failures (adds additional delays on errors)
    4. Caching: Leverages LRU cache to minimize API calls
    5. Test Execution Strategy: Run tests manually or on schedule (not on every commit) to avoid overwhelming the API

    Note: The 100ms inter-test delay is a courtesy pause between tests, not a strict rate limiter. With 107 tests and retry logic, the effective request rate is much lower than the theoretical maximum. The EP API client includes its own rate limiting (100 tokens per minute) that provides the primary throttling mechanism. For production use, tests should be run individually or in small batches rather than the full suite at once.

    beforeEach(async () => {
    // Wait between tests to respect rate limits
    await new Promise(resolve => setTimeout(resolve, 100));
    });

    โœ… DO:

    • Run integration tests during off-peak hours
    • Use EP_SAVE_FIXTURES=true to capture responses for offline testing
    • Test with small limit values (5-10) to minimize API load
    • Review test output for rate limit warnings

    โŒ DON'T:

    • Run integration tests in CI/CD on every commit
    • Execute concurrent integration test suites
    • Use large pagination limits in tests
    • Ignore rate limit errors

    Fixtures allow offline testing without hitting the real API:

    # Enable fixture capture
    EP_INTEGRATION_TESTS=true EP_SAVE_FIXTURES=true npm run test:integration

    This saves real API responses to tests/fixtures/real-api/ for:

    • Offline development
    • Consistent test data
    • API response documentation
    • Regression testing
    {
    "data": [
    {
    "id": "MEP-123",
    "name": "Example MEP",
    "country": "SE",
    "politicalGroup": "EPP",
    "active": true
    }
    ],
    "total": 100,
    "limit": 10,
    "offset": 0
    }

    import { describe, it, expect } from 'vitest';
    import { handleGetMEPs } from '../../../src/tools/getMEPs.js';
    import { shouldRunIntegrationTests } from '../setup.js';
    import { validatePaginatedResponse } from '../helpers/responseValidator.js';

    const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip;

    describeIntegration('get_meps Integration Tests', () => {
    it('should fetch Swedish MEPs from real API', async () => {
    const result = await handleGetMEPs({ country: 'SE', limit: 10 });

    const response = validatePaginatedResponse(result);
    expect(response.data).toBeDefined();
    expect(response.total).toBeGreaterThan(0);
    }, 30000);
    });
    import { retry } from '../../helpers/testUtils.js';

    it('should handle transient failures', async () => {
    const result = await retry(async () => {
    return handleGetMEPs({ country: 'DE', limit: 5 });
    }, 3, 1000); // 3 retries, 1 second base delay

    expect(result).toBeDefined();
    }, 30000);
    import { measureTime } from '../../helpers/testUtils.js';

    it('should complete within acceptable time', async () => {
    const [result, duration] = await measureTime(async () => {
    return handleGetMEPs({ limit: 10 });
    });

    expect(duration).toBeLessThan(5000); // 5 seconds
    console.log(`Request duration: ${duration.toFixed(2)}ms`);
    }, 30000);

    Integration tests handle personally identifiable information (PII) appropriately:

    • โœ… Data Minimization: Tests use minimal limit values
    • โœ… Purpose Limitation: Data used only for testing
    • โœ… Storage Limitation: Fixtures contain no sensitive PII
    • โœ… Audit Logging: All API access is logged per AU-2

    Tests comply with Hack23 Secure Development Policy:

    • SC-002: Input validation for all tool parameters
    • PE-001: Performance benchmarks (<200ms cached, <2s uncached)
    • AU-2: Audit logging for all data access
    • SI-10: Schema validation for all responses

    # Run all integration tests
    EP_INTEGRATION_TESTS=true npm run test:integration

    # Run with coverage
    EP_INTEGRATION_TESTS=true npm run test:integration -- --coverage

    # Run specific test file
    EP_INTEGRATION_TESTS=true npm run test:integration -- getMEPs.integration

    # Run in watch mode (not recommended for integration tests)
    EP_INTEGRATION_TESTS=true npm run test:integration -- --watch

    Integration tests can be run on a schedule to avoid overwhelming the API:

    # .github/workflows/integration-tests.yml (example)
    name: Integration Tests (Scheduled)

    on:
    schedule:
    - cron: '0 2 * * 1' # Weekly on Monday 2 AM UTC
    workflow_dispatch: # Manual trigger

    jobs:
    integration:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
    with:
    node-version: '25'
    - run: npm install
    - run: EP_INTEGRATION_TESTS=true npm run test:integration

    Cause: EP_INTEGRATION_TESTS not set to true

    Solution:

    EP_INTEGRATION_TESTS=true npm run test:integration
    

    Cause: Too many requests to EP API

    Solution:

    • Wait 15 minutes before retrying
    • Reduce concurrent test execution
    • Use captured fixtures for development

    Cause: Slow network or API response

    Solution:

    • Increase test timeout: it('test name', async () => { ... }, 60000)
    • Check network connectivity
    • Verify EP API status

    Cause: API response structure changed

    Solution:

    • Review API response in test output
    • Update schemas in src/schemas/europeanParliament.ts
    • Capture new fixtures with EP_SAVE_FIXTURES=true

    Enable verbose logging for troubleshooting:

    DEBUG=* EP_INTEGRATION_TESTS=true npm run test:integration
    

    Tool Uncached Cached Notes
    get_meps <2s <1000ms Basic retrieval
    get_mep_details <2s <1000ms Individual MEP
    get_plenary_sessions <2s <1000ms Session data
    get_voting_records <3s <1000ms Large datasets
    search_documents <3s <1000ms Full-text search
    get_committee_info <2s <1000ms Committee data
    get_parliamentary_questions <2s <1000ms Question data
    analyze_voting_patterns <5s <1000ms Complex analysis
    track_legislation <2s <1000ms Procedure tracking
    generate_report <5s <1000ms Report generation

    Each integration test includes performance validation:

    it('should complete within acceptable time', async () => {
    const [, duration] = await measureTime(async () => {
    return handleGetMEPs({ limit: 10 });
    });

    expect(duration).toBeLessThan(5000);
    console.log(`Performance: ${duration.toFixed(2)}ms`);
    }, 30000);

    When adding new integration tests:

    1. โœ… Follow existing test structure and patterns
    2. โœ… Include all test categories (retrieval, filtering, pagination, etc.)
    3. โœ… Add fixture capture with descriptive names
    4. โœ… Respect rate limits with delays and retries
    5. โœ… Document any EP API quirks or limitations
    6. โœ… Update this guide with new tools or patterns
    /**
    * Integration Tests: tool_name Tool
    *
    * ISMS Policy: SC-002 (Secure Testing), PE-001 (Performance Testing)
    */

    import { describe, it, expect, beforeEach } from 'vitest';
    import { handleToolName } from '../../../src/tools/toolName.js';
    import { shouldRunIntegrationTests } from '../setup.js';
    import { retry, measureTime } from '../../helpers/testUtils.js';
    import { validatePaginatedResponse } from '../helpers/responseValidator.js';
    import { saveMCPResponseFixture } from '../helpers/fixtureManager.js';

    const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip;

    describeIntegration('tool_name Integration Tests', () => {
    beforeEach(async () => {
    await new Promise(resolve => setTimeout(resolve, 100));
    });

    describe('Basic Retrieval', () => {
    it('should fetch data from real API', async () => {
    const result = await retry(async () => {
    return handleToolName({ limit: 10 });
    });

    saveMCPResponseFixture('tool_name', 'basic-retrieval', result);

    const response = validatePaginatedResponse(result);
    expect(response.data).toBeDefined();
    }, 30000);
    });

    // Add more test categories...
    });


    Integration tests validate that the European Parliament MCP Server correctly interfaces with the real EP Open Data API. By respecting rate limits, capturing fixtures, and following ISMS guidelines, these tests ensure production readiness while maintaining compliance with security and privacy requirements.

    Remember: Integration tests should be run thoughtfully to avoid overwhelming the EP API. Use fixtures for development and reserve live API tests for validation and scheduled runs.