Skip to content

Latest commit

 

History

History
673 lines (536 loc) · 31.4 KB

File metadata and controls

673 lines (536 loc) · 31.4 KB

Hack23 Logo

🏛️ European Parliament MCP Server — Architecture

C4 Architecture Model — Context, Container, Component Views
Comprehensive system design documentation for the European Parliament MCP Server

Owner Version Effective Date Review Cycle OpenSSF Best Practices

📋 Document Owner: Hack23 | 📄 Version: 1.2 | 📅 Last Updated: 2026-04-21 (UTC) 🔄 Review Cycle: Quarterly | ⏰ Next Review: 2026-07-21 🏷️ Classification: Public (Open Source MCP Server) ✅ ISMS Compliance: ISO 27001 (A.5.1, A.8.1, A.14.2), NIST CSF 2.0 (ID.AM, PR.DS), CIS Controls v8.1 (2.1, 16.1)


📑 Table of Contents

  1. Security Documentation Map
  2. Executive Summary
  3. C4 Context Diagram
  4. C4 Container Diagram
  5. C4 Component Diagram — Tool Engine
  6. MCP Protocol Surface
  7. Deployment Architecture
  8. Technology Stack
  9. Architectural Decision Records
  10. Security Architecture Summary
  11. ISMS Compliance Mapping

🗺️ Security Documentation Map

Document Current Future Description
Architecture ARCHITECTURE.md FUTURE_ARCHITECTURE.md C4 model, containers, components, ADRs
Security Architecture SECURITY_ARCHITECTURE.md FUTURE_SECURITY_ARCHITECTURE.md Security controls, threat model
Data Model DATA_MODEL.md FUTURE_DATA_MODEL.md Entity relationships, branded types
Flowchart FLOWCHART.md FUTURE_FLOWCHART.md Business process flows
State Diagram STATEDIAGRAM.md FUTURE_STATEDIAGRAM.md System state transitions
Mind Map MINDMAP.md FUTURE_MINDMAP.md System concepts and relationships
SWOT Analysis SWOT.md FUTURE_SWOT.md Strategic positioning
Threat Model THREAT_MODEL.md FUTURE_THREAT_MODEL.md STRIDE, MITRE ATT&CK, attack trees
CRA Assessment CRA-ASSESSMENT.md EU Cyber Resilience Act conformity

🎯 Executive Summary

The European Parliament MCP Server (v1.2.10) is a TypeScript/Node.js application implementing the Model Context Protocol (MCP) to expose structured access to European Parliament datasets. It bridges AI assistants and LLM clients with the EP Open Data Portal API v2, enabling parliamentary intelligence, legislative monitoring, and OSINT analysis workflows.

Key Capabilities

Capability Details
MCP Tools 62 tools in 6 categories (core, advanced, osint, phase4, phase5, feed)
MCP Resources 9 URI-addressable resources
MCP Prompts 7 intelligence-analysis prompts
Data Source EP Open Data Portal API v2
Transport stdio (MCP standard)
Runtime Node.js 25+ / TypeScript 6.0.2
Security 4-layer: Zod → Rate Limiting → Audit Logging → GDPR

🌐 C4 Context Diagram

C4Context
    title System Context — European Parliament MCP Server

    Person(aiUser, "AI User / Developer", "Uses AI assistants to query EP data")
    Person(analyst, "Political Analyst", "Performs legislative intelligence analysis")

    System(mcpServer, "EP MCP Server", "MCP server exposing 62 tools, 9 resources, 7 prompts for EP parliamentary data")

    System_Ext(claudeDesktop, "Claude Desktop / Cursor / Copilot", "MCP-compatible AI client")
    System_Ext(epApi, "EP Open Data Portal API v2", "Official European Parliament open data API at data.europarl.europa.eu/api/v2/")
    System_Ext(epVocab, "EP Controlled Vocabularies", "AT4EU, Europarl taxonomy, authority tables")

    Rel(aiUser, claudeDesktop, "Asks questions about EP")
    Rel(analyst, claudeDesktop, "Runs intelligence workflows")
    Rel(claudeDesktop, mcpServer, "MCP protocol over stdio")
    Rel(mcpServer, epApi, "HTTPS REST requests")
    Rel(mcpServer, epVocab, "Vocabulary lookups")
Loading

📦 C4 Container Diagram

flowchart TD
    subgraph MCPClients["MCP Clients (External)"]
        CC["Claude Desktop"]
        CU["Cursor IDE"]
        CO["GitHub Copilot"]
    end

    subgraph EPMCPServer["EP MCP Server — Node.js Process"]
        direction TB
        MH["MCP Handler\n(stdio transport)"]
        TR["Tool Router\n(62 tools dispatched)"]
        RE["Resource Engine\n(9 URI resources)"]
        PR["Prompt Registry\n(7 prompts)"]
        DI["DI Container\n(singletons)"]
        TC["Tool Categories\n(7 modules)"]
        EC["EP API Clients\n(9 modular clients)"]
        CA["LRU Cache\n(500 entries, 15-min TTL)"]
        RL["Rate Limiter\n(100 tokens/min)"]
        AL["Audit Logger"]
        MS["Metrics Service"]
        HS["Health Service"]
    end

    subgraph ExternalSystems["External Systems"]
        EPA["EP Open Data Portal\nAPI v2"]
        EV["EP Vocabulary\nEndpoints"]
    end

    MCPClients -->|"stdio MCP"| MH
    MH --> TR
    MH --> RE
    MH --> PR
    TR --> DI
    DI --> TC
    TC --> EC
    EC --> CA
    CA -->|"cache miss"| RL
    RL --> EPA
    EC --> EV
    DI -->|"singletons"| AL
    DI -->|"singletons"| MS
    DI -->|"singletons"| HS
Loading

🔧 C4 Component Diagram — Tool Engine

flowchart TD
    subgraph ToolEngine["Tool Engine — src/tools/"]
        direction TB

        subgraph CoreTools["Core Tools (7)"]
            GM["get_meps"]
            GMD["get_mep_details"]
            GPS["get_plenary_sessions"]
            GVR["get_voting_records"]
            SD["search_documents"]
            GCI["get_committee_info"]
            GPQ["get_parliamentary_questions"]
        end

        subgraph AdvancedTools["Advanced Analysis (3)"]
            AVP["analyze_voting_patterns"]
            TL["track_legislation"]
            GR["generate_report"]
        end

        subgraph OSINT1["OSINT Phase 1 (6)"]
            AMI["assess_mep_influence"]
            ACD["analyze_coalition_dynamics"]
            DVA["detect_voting_anomalies"]
            CPG["compare_political_groups"]
            ALE["analyze_legislative_effectiveness"]
            MLP["monitor_legislative_pipeline"]
        end

        subgraph OSINT2["OSINT Phase 2 (2)"]
            ACA["analyze_committee_activity"]
            TMA["track_mep_attendance"]
        end

        subgraph OSINT3["OSINT Phase 3 (2)"]
            ACD2["analyze_country_delegation"]
            GPL["generate_political_landscape"]
        end

        subgraph Phase6["Advanced OSINT (5)"]
            NA["network_analysis"]
            ST["sentiment_tracker"]
            EWS["early_warning_system"]
            CI["comparative_intelligence"]
            CRI["correlate_intelligence"]
        end

        subgraph Phase4["Phase 4 EP API v2 (8)"]
            GCM["get_current_meps"]
            GSP["get_speeches"]
            GP["get_procedures"]
            GAT["get_adopted_texts"]
            GE["get_events"]
            GMA["get_meeting_activities"]
            GMD2["get_meeting_decisions"]
            GMPD["get_mep_declarations"]
        end

        subgraph Phase5["Phase 5 Complete Coverage (15)"]
            GIM["get_incoming_meps"]
            GOM["get_outgoing_meps"]
            GHM["get_homonym_meps"]
            GPD["get_plenary_documents"]
            GCD["get_committee_documents"]
            GPSD["get_plenary_session_documents"]
            GPSDI["get_plenary_session_document_items"]
            GCV["get_controlled_vocabularies"]
            GED["get_external_documents"]
            GMFA["get_meeting_foreseen_activities"]
            GPE["get_procedure_events"]
            GMPSD["get_meeting_plenary_session_documents"]
            GMPSDI["get_meeting_plenary_session_document_items"]
            GPEID["get_procedure_event_by_id"]
            GAGS["get_all_generated_stats"]
        end

        subgraph FeedTools["Feed Endpoints (13)"]
            GMFEED["get_meps_feed"]
            GEFEED["get_events_feed"]
            GPFEED["get_procedures_feed"]
            GATFEED["get_adopted_texts_feed"]
            GMDFEED["get_mep_declarations_feed"]
            GDFEED["get_documents_feed"]
            GPDFEED["get_plenary_documents_feed"]
            GCDFEED["get_committee_documents_feed"]
            GPSDFEED["get_plenary_session_documents_feed"]
            GEDFEED["get_external_documents_feed"]
            GPQFEED["get_parliamentary_questions_feed"]
            GCBFEED["get_corporate_bodies_feed"]
            GCVFEED["get_controlled_vocabularies_feed"]
        end
    end

    subgraph Validators["Zod Validation Layer"]
        ZV["Input Validators\n(schema per tool)"]
    end

    subgraph Clients["EP API Client Layer"]
        BC["baseClient"]
        MC["mepClient"]
        VC["votingClient"]
        COMC["committeeClient"]
        PC["plenaryClient"]
        DC["documentClient"]
        LC["legislativeClient"]
        QC["questionClient"]
        VCC["vocabularyClient"]
    end

    CoreTools --> ZV
    AdvancedTools --> ZV
    OSINT1 --> ZV
    OSINT2 --> ZV
    OSINT3 --> ZV
    Phase6 --> ZV
    Phase4 --> ZV
    Phase5 --> ZV
    FeedTools --> ZV

    ZV --> Clients
Loading

📡 MCP Protocol Surface

Tools (62 total)

Core Data Access Tools (8)

Tool Function Description
get_meps getMEPs List MEPs with country/group filters
get_mep_details getMEPDetails Detailed MEP profile by ID
get_plenary_sessions getPlenarySessions Plenary session listings
get_voting_records getVotingRecords Session voting records
search_documents searchDocuments Legislative document search
get_committee_info getCommitteeInfo Committee details
get_parliamentary_questions getParliamentaryQuestions Written/oral questions
get_server_health getServerHealth Server health & feed availability diagnostics

OSINT Intelligence Tools (10 + 5 Advanced)

Tool Function Description
assess_mep_influence assessMepInfluence 5-dimension influence scoring model
analyze_coalition_dynamics analyzeCoalitionDynamics Coalition cohesion & stress analysis
detect_voting_anomalies detectVotingAnomalies Party defection & anomaly detection
compare_political_groups comparePoliticalGroups Cross-group comparative analysis
analyze_legislative_effectiveness analyzeLegislativeEffectiveness MEP/committee legislative scoring
monitor_legislative_pipeline monitorLegislativePipeline Pipeline status & bottleneck detection
analyze_committee_activity analyzeCommitteeActivity Committee workload & engagement
track_mep_attendance trackMepAttendance MEP attendance patterns & trends
analyze_country_delegation analyzeCountryDelegation Country delegation voting & composition
generate_political_landscape generatePoliticalLandscape Parliament-wide political landscape

Advanced OSINT Intelligence Tools (5 — v1.1)

The following five tools extend the OSINT capability with network analysis, sentiment tracking, early-warning signals, comparative intelligence, and cross-source correlation. Each tool returns confidenceLevel, dataFreshness, sourceAttribution, and methodology fields for full analytical transparency.

Tool Function Description
network_analysis networkAnalysis MEP relationship network mapping via committee co-membership. Computes centrality scores, cluster assignments, bridging MEPs, and network density metrics. Identifies informal power structures and cross-party collaboration pathways.
sentiment_tracker sentimentTracker Track political group institutional positioning based on seat-share proxy. Returns per-group positioning scores (−1 to +1), polarization index, consensus/divisive topics, and significant positioning shifts.
early_warning_system earlyWarningSystem Detect emerging political shifts, coalition fracture signals, and parliamentary stability risks. Generates severity-tiered warnings (CRITICAL/HIGH/MEDIUM/LOW), stability score (0–100), and trend indicators. Configurable sensitivity and focus area.
comparative_intelligence comparativeIntelligence Cross-reference 2–10 MEPs across voting, committee, legislative, and attendance dimensions. Returns ranked profiles, cosine-similarity correlation matrix, z-score outlier detection, and natural cluster analysis.
correlate_intelligence correlateIntelligence Cross-source intelligence correlation combining multiple data dimensions. Identifies patterns across voting, committee, and legislative activity for comprehensive analytical insights.

Design Principles for Advanced Tools:

  • All outputs include dataAvailable: boolean — tools degrade gracefully when EP API data is limited
  • confidenceLevel: 'HIGH' | 'MEDIUM' | 'LOW' reflects data completeness at execution time
  • dataFreshness and sourceAttribution provide full data provenance for OSINT analysis
  • methodology documents the analytical approach for reproducibility and audit
  • dataQualityWarnings: string[] surfaces data limitations and proxy metrics to end users
  • Input validation via Zod schemas with .refine() cross-field constraints and strict typing throughout
  • Standardized error handling via ToolError (toolName, operation, isRetryable) and buildToolResponse() for consistent response building

EP Data Access Tools (8)

Tool Function Description
get_current_meps getCurrentMEPs Currently serving MEPs
get_speeches getSpeeches Plenary speeches
get_procedures getProcedures Legislative procedures
get_adopted_texts getAdoptedTexts Adopted legislative texts
get_events getEvents Parliamentary events
get_meeting_activities getMeetingActivities Meeting activity records
get_meeting_decisions getMeetingDecisions Meeting decision outcomes
get_mep_declarations getMEPDeclarations MEP financial declarations

EP Complete Coverage Tools (15)

Tool Function Description
get_incoming_meps getIncomingMEPs Incoming MEPs (new members)
get_outgoing_meps getOutgoingMEPs Outgoing MEPs (departing members)
get_homonym_meps getHomonymMEPs MEPs with duplicate names
get_plenary_documents getPlenaryDocuments Plenary-specific documents
get_committee_documents getCommitteeDocuments Committee-specific documents
get_plenary_session_documents getPlenarySessionDocuments Session-specific documents
get_plenary_session_document_items getPlenarySessionDocumentItems Document items within sessions
get_controlled_vocabularies getControlledVocabularies EP controlled vocabulary terms
get_external_documents getExternalDocuments External reference documents
get_meeting_foreseen_activities getMeetingForeseenActivities Planned meeting activities
get_procedure_events getProcedureEvents Events linked to a procedure
get_meeting_plenary_session_documents getMeetingPlenarySessionDocuments Plenary session documents for a meeting
get_meeting_plenary_session_document_items getMeetingPlenarySessionDocumentItems Plenary session document items for a meeting
get_procedure_event_by_id getProcedureEventById Get a specific procedure event by ID
get_all_generated_stats getAllGeneratedStats Precomputed parliamentary analytics

Advanced Analysis Tools (3)

Tool Function Description
analyze_voting_patterns analyzeVotingPatterns Multi-session voting analysis
track_legislation trackLegislation End-to-end legislative tracking (real EP API data)
generate_report generateReport Structured analysis report generation

Feed Endpoint Tools (13)

Tool Function Description
get_meps_feed getMEPsFeed Atom feed of MEP updates
get_events_feed getEventsFeed Atom feed of parliamentary events
get_procedures_feed getProceduresFeed Atom feed of legislative procedures
get_adopted_texts_feed getAdoptedTextsFeed Atom feed of adopted texts
get_mep_declarations_feed getMEPDeclarationsFeed Atom feed of MEP declarations
get_documents_feed getDocumentsFeed Atom feed of parliamentary documents
get_plenary_documents_feed getPlenaryDocumentsFeed Atom feed of plenary documents
get_committee_documents_feed getCommitteeDocumentsFeed Atom feed of committee documents
get_plenary_session_documents_feed getPlenarySessionDocumentsFeed Atom feed of plenary session documents
get_external_documents_feed getExternalDocumentsFeed Atom feed of external documents
get_parliamentary_questions_feed getParliamentaryQuestionsFeed Atom feed of parliamentary questions
get_corporate_bodies_feed getCorporateBodiesFeed Atom feed of corporate bodies
get_controlled_vocabularies_feed getControlledVocabulariesFeed Atom feed of controlled vocabularies

Tool Category Summary

Category Count Tools
Core 8 get_meps, get_mep_details, get_plenary_sessions, get_voting_records, search_documents, get_committee_info, get_parliamentary_questions, get_server_health
Advanced Analysis 3 analyze_voting_patterns, track_legislation, generate_report
OSINT Phase 1 6 assess_mep_influence, analyze_coalition_dynamics, detect_voting_anomalies, compare_political_groups, analyze_legislative_effectiveness, monitor_legislative_pipeline
OSINT Phase 2 2 analyze_committee_activity, track_mep_attendance
OSINT Phase 3 2 analyze_country_delegation, generate_political_landscape
Advanced OSINT 5 network_analysis, sentiment_tracker, early_warning_system, comparative_intelligence, correlate_intelligence
Phase 4 EP API v2 8 get_current_meps, get_speeches, get_procedures, get_adopted_texts, get_events, get_meeting_activities, get_meeting_decisions, get_mep_declarations
Phase 5 Complete Coverage 15 get_incoming_meps, get_outgoing_meps, get_homonym_meps, get_plenary_documents, get_committee_documents, get_plenary_session_documents, get_plenary_session_document_items, get_controlled_vocabularies, get_external_documents, get_meeting_foreseen_activities, get_procedure_events, get_meeting_plenary_session_documents, get_meeting_plenary_session_document_items, get_procedure_event_by_id, get_all_generated_stats
Feed Endpoints 13 get_meps_feed, get_events_feed, get_procedures_feed, get_adopted_texts_feed, get_mep_declarations_feed, get_documents_feed, get_plenary_documents_feed, get_committee_documents_feed, get_plenary_session_documents_feed, get_external_documents_feed, get_parliamentary_questions_feed, get_corporate_bodies_feed, get_controlled_vocabularies_feed
Total 62

Resources (9 total)

URI Pattern Description
ep://meps List of all current MEPs
ep://meps/{id} Individual MEP details by ID
ep://committees/{id} Committee details by ID
ep://plenary-sessions Plenary session listing
ep://votes/{id} Vote record by ID
ep://political-groups Political group listing
ep://procedures/{id} Legislative procedure by ID
ep://plenary/{id} Plenary session by ID
ep://documents/{id} Parliamentary document by ID

Prompts (7 total)

Prompt Name Purpose
mep_briefing Generate comprehensive MEP profile briefing
coalition_analysis Analyze political coalition dynamics
legislative_tracking Track legislative procedure progress
political_group_comparison Compare political groups on key metrics
committee_activity_report Summarize committee work and outputs
voting_pattern_analysis Analyze MEP or group voting patterns
country_delegation_analysis Analyze national delegation composition

🚀 Deployment Architecture

flowchart TD
    subgraph Developer["Developer Workstation"]
        IDE["IDE (Cursor / VS Code)"]
        ClaudeApp["Claude Desktop"]
    end

    subgraph Runtime["Node.js Runtime"]
        NPX["npx / node dist/index.js"]
        PROC["EP MCP Server Process"]
        ENV[".env Configuration"]
    end

    subgraph EPInfra["European Parliament Infrastructure"]
        CDN["EP CDN / Load Balancer"]
        API["EP Open Data Portal API v2\nhttps://data.europarl.europa.eu/api/v2/"]
    end

    IDE -->|"MCP stdio"| PROC
    ClaudeApp -->|"MCP stdio"| PROC
    NPX --> PROC
    ENV --> PROC
    PROC -->|"HTTPS/TLS"| CDN
    CDN --> API
Loading

Deployment Modes:

  • Local stdio: Primary mode — spawned by MCP client as subprocess
  • npm package: Distributed via npm for easy installation
  • Docker: Optional containerized deployment for CI/CD

🛠️ Technology Stack

Layer Technology Version Purpose
Runtime Node.js 25+ Server runtime
Language TypeScript 6.0.2 Type-safe implementation
MCP SDK @modelcontextprotocol/sdk 1.29.0 MCP protocol implementation
Validation Zod 4.3.6 Runtime schema validation and branded types
HTTP Client undici 8.1.0 Fast HTTP/1.1 client for EP API requests
Caching lru-cache 11.3.5 LRU cache (500 entries, 15-min TTL)
Testing Vitest latest Unit and integration testing
Linting ESLint 10.1.0 Code quality enforcement
Unused Detection Knip latest Dead code detection
Build tsc 6.0.2 TypeScript compilation
Package Manager npm 10.x Dependency management

📊 Data Quality Management

All OSINT intelligence tools implement a cross-cutting data quality framework that ensures analytical transparency and reliability. This is a key improvement introduced in v1.1 to provide explicit signals about data completeness and confidence.

Data Quality Components

Component Type Purpose
DataAvailability Enum AVAILABLE, PARTIAL, ESTIMATED, UNAVAILABLE — status of underlying EP API data
dataQualityWarnings string[] Array of human-readable warnings flagging data limitations, proxy metrics, or unavailable sources
confidenceLevel Enum HIGH, MEDIUM, LOW — confidence in computed value based on actual data availability
MetricResult<T> Generic wrapper Wraps metric value with availability, confidence, source, and optional reason fields

MetricResult Wrapper Pattern

interface MetricResult<T = number> {
  value: T | null;                      // Computed value, or null when unavailable
  availability: DataAvailability;       // AVAILABLE | PARTIAL | ESTIMATED | UNAVAILABLE
  confidence: 'HIGH' | 'MEDIUM' | 'LOW' | 'NONE';
  source?: string;                      // Human-readable data source description
  reason?: string;                      // Explanation for unavailable/estimated data
}

Standardized Error Handling

All tool handlers use the ToolError class for structured error reporting and buildToolResponse() for consistent success responses:

// ToolError — structured error with retryability signal
class ToolError extends Error {
  readonly toolName: string;
  readonly operation: string;
  readonly isRetryable: boolean;
  readonly cause?: Error;
}

// buildToolResponse — standard JSON response wrapper
function buildToolResponse(data: unknown): ToolResult {
  return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
}

📐 Architectural Decision Records

ADR-001: Dependency Injection Container Pattern

Status: Accepted | Date: 2026-02-26

Context: Multiple services (RateLimiter, MetricsService, AuditLogger, HealthService) need to be shared across the 62 tool handlers. Using ad-hoc singleton globals creates tight coupling and reduces testability.

Decision: Implement a lightweight DI container that manages singleton lifecycle for all shared services. Services are registered once at startup and injected into tool handlers via constructor injection.

Consequences:

  • ✅ Improved testability — services can be mocked in tests
  • ✅ Clear dependency graph
  • ✅ Single initialization point for monitoring setup
  • ⚠️ Minor startup overhead for container initialization

Registered Singletons: RateLimiter, MetricsService, AuditLogger, HealthService


ADR-002: Branded Types via Zod

Status: Accepted | Date: 2026-02-26

Context: EP API identifiers (procedure IDs, MEP IDs, country codes, dates) are structurally strings or numbers but carry semantic constraints. Using plain primitives allows incorrect values to flow through the system silently.

Decision: Use Zod's .brand() feature to create branded types for all EP domain identifiers. This enforces correct formats at both compile time (TypeScript) and runtime (Zod parse).

Key Branded Types:

  • ProcedureID — format YYYY/NNNN(TYPE), e.g., 2024/0001(COD)
  • CountryCode — ISO 3166-1 alpha-2, e.g., DE, FR
  • DateString — ISO 8601 format YYYY-MM-DD
  • MEP_ID — positive integer identifier

Consequences:

  • ✅ Runtime type safety for all EP identifiers
  • ✅ Validation errors surface at system boundary
  • ✅ TypeScript prevents passing wrong identifier types
  • ⚠️ Slightly more verbose schema definitions

ADR-003: LRU Cache Strategy

Status: Accepted | Date: 2026-02-26

Context: The EP Open Data Portal API v2 has rate limits and non-trivial latency. Parliamentary data (MEP lists, committee info, plenary schedules) changes infrequently. Repeated calls for the same data waste API quota.

Decision: Implement a shared LRU cache with 500 maximum entries and 15-minute TTL. All EP API client modules share a single cache instance registered in the DI container.

Cache Configuration:

max: 500 entries
ttl: 900,000 ms (15 minutes)
allowStale: false
updateAgeOnGet: false

Cache Key Pattern: {clientName}:{endpoint}:{sortedParams}

Consequences:

  • ✅ Reduced EP API calls by ~70% for repeated queries
  • ✅ Sub-millisecond response for cache hits
  • ✅ Respects EP API rate limits
  • ⚠️ 15-minute staleness acceptable for parliamentary data

ADR-004: Zod Validation-First Approach

Status: Accepted | Date: 2026-02-26

Context: MCP tool handlers receive untyped args from AI clients. Without validation, malformed inputs can cause cryptic errors, security vulnerabilities, or corrupted API calls to the EP API.

Decision: Every tool handler validates its input schema using Zod before any business logic executes. Validation failures return structured MCP error responses immediately.

Validation Pipeline:

MCP args (unknown) → Zod.parse() → typed input → EP API call
                         ↓ (on failure)
                    ZodError → MCP error response

Consequences:

  • ✅ Type-safe handler implementations
  • ✅ Clear error messages for AI clients
  • ✅ Security: malformed inputs rejected at boundary
  • ✅ Eliminates defensive null-checks in business logic

ADR-005: Data Quality Signaling for OSINT Outputs

Status: Accepted | Date: 2026-04-01

Context: OSINT intelligence tools (assess_mep_influence, analyze_coalition_dynamics, etc.) compute analytical metrics from EP API data. However, the EP API does not expose all data needed for every metric (e.g., voting statistics are unavailable per MEP). Without explicit signaling, consumers cannot distinguish between "metric is zero" and "metric is unavailable."

Decision: Introduce a data quality framework across all OSINT tools:

  • DataAvailability enum (AVAILABLE, PARTIAL, ESTIMATED, UNAVAILABLE) for every metric
  • dataQualityWarnings: string[] on every OSINT output to surface data limitations
  • MetricResult<T> generic wrapper with value, availability, confidence, and source
  • Confidence levels computed from a combination of data availability and heuristic volume/coverage thresholds

Consequences:

  • ✅ Consumers can distinguish "zero" from "unavailable" for all metrics
  • ✅ Proxy metrics are explicitly labeled as ESTIMATED
  • ✅ Data limitations are surfaced to end users via warnings array
  • ✅ Analytical transparency meets ISMS A.8.11 (data integrity) requirements
  • ⚠️ Slightly larger response payloads due to quality metadata

🔒 Security Architecture Summary

The server implements a 4-layer security architecture:

  1. Layer 1 — Zod Validation: All tool inputs validated against strict schemas before processing
  2. Layer 2 — Rate Limiting: Token bucket algorithm, 100 tokens/minute, prevents EP API abuse
  3. Layer 3 — Audit Logging: All tool invocations logged with parameters (PII-stripped) for compliance
  4. Layer 4 — GDPR Compliance: MEP personal data handled with data minimization and purpose limitation

See SECURITY_ARCHITECTURE.md for full details. For OWASP LLM Top 10 (2025) mapping and MCP-protocol-specific threat analysis, see THREAT_MODEL.md.


✅ ISMS Compliance Mapping

Control Standard Clause Implementation
Asset Management ISO 27001 A.8.1 All 62 tools documented as information assets
Secure Development ISO 27001 A.14.2 TypeScript strict mode, Zod validation, ESLint
Access Control ISO 27001 A.9.1 MCP stdio transport, no network exposure
Audit Logging ISO 27001 A.12.4 AuditLogger singleton, all invocations logged
Data Protection GDPR Art. 5 Data minimization in all MEP queries
Identify: Assets NIST CSF 2.0 ID.AM Component and tool inventory maintained
Protect: Data NIST CSF 2.0 PR.DS Encryption in transit (HTTPS to EP API)
Software Inventory CIS Controls v8.1 2.1 package.json, SBOM via npm
Secure Config CIS Controls v8.1 16.1 TypeScript strict, no dangerous defaults

See FUTURE_ARCHITECTURE.md for the architectural evolution roadmap.