The EP MCP Server implements a 4-layer defense-in-depth security architecture aligned with OWASP best practices, ISO 27001, NIST CSF 2.0, and GDPR requirements. Since the server operates as an MCP stdio process (not a network-exposed server), the primary security concerns are:
Input validation β prevent malformed or malicious MCP tool arguments
API abuse prevention β protect EP Open Data Portal from overuse
Data privacy β GDPR-compliant handling of MEP personal data
Audit trail β full traceability of all data access
The server does not handle authentication tokens, passwords, or payment data, significantly reducing the attack surface.
The EP MCP Server operates as a local stdio process spawned by the MCP client (e.g., Claude Desktop). The security model relies on OS-level process isolation:
No network authentication β the server is not network-exposed
No user credentials β the server does not handle user tokens
Process isolation β only the spawning MCP client can communicate via stdio
EP API access β public open data, no authentication required by EP
Trust Boundaries
flowchart LR subgraph TrustHigh["High Trust Zone"] OS["Operating System"] User["Local User Account"] end
subgraph TrustMedium["Medium Trust Zone"] MCP["MCP Client Process\n(Claude Desktop / Cursor)"] Server["EP MCP Server Process"] end
subgraph TrustLow["Low Trust Zone"] Input["Tool Arguments\n(from AI-generated content)"] end
subgraph External["Untrusted External"] EPAPI["EP Open Data Portal\n(public internet)"] end
OS --> MCP MCP --> Server Server --> Input Input -->|"Zod validation"| Server Server -->|"HTTPS"| EPAPI
Key principle: Tool arguments are treated as untrusted input regardless of their origin, since AI models may generate unexpected parameter values.
π Session and Action Tracking
All user interactions with the MCP server are tracked through the integrated audit and metrics systems:
Session Tracking Model
flowchart LR subgraph SessionContext["Session Context"] STDIO["stdio Connection\n(1 session per process)"] TC["Tool Call Counter"] TS["Session Start Time"] end
STDIO --> AL STDIO --> MS AL --> TC MS --> TS HS --> TC
Tracked Actions
Action Type
Tracked Fields
Storage
Purpose
Tool invocation
Tool name, sanitized params, timestamp, duration
stderr audit log
Full traceability
API request
URL, status, duration, cache hit/miss
MetricsService
Performance monitoring
Rate limit event
Token count, refill status, rejection
stderr audit log
Abuse detection
Error occurrence
Error type (no stack trace), tool context
stderr audit log
Incident response
Cache operation
Key, hit/miss, eviction
MetricsService
Efficiency tracking
Action Tracking Implementation
No persistent session storage β session state is in-memory only (process-scoped)
PII stripping β all logged parameters have personal data fields removed before logging
Structured logging β JSON format on stderr for machine-parseable audit trail
Per-tool metrics β invocation count, error count, average duration per tool
π Data Integrity and Auditing
Data Integrity Controls
Control
Implementation
Verification
Source integrity
All data sourced from official EP API over HTTPS/TLS
TLS certificate validation
Transport integrity
HTTPS with TLS 1.2+ for all API calls
Node.js default TLS verification
Cache integrity
In-memory LRU cache (no persistent storage) β no disk tampering risk
Process isolation
Cache key integrity
Deterministic cache key generation via sorted parameter keys
Prevents cache misses from property insertion order
Schema validation
Zod schemas validate all API responses before processing
TypeScript strict mode + runtime validation
Data quality integrity
OSINT outputs include DataAvailability and dataQualityWarnings (SC-013)
Consumers distinguish "zero" from "unavailable"
Audit immutability
Audit logs written to stderr (append-only within process)
No log modification API exposed
Package integrity
npm lockfile with exact versions, SLSA Level 3 provenance
Provenance attestations, Sigstore signing
Audit Trail Architecture
flowchart TD ToolCall["Tool Invocation"] --> AuditLog["AuditLogger.logToolCall()"] AuditLog --> PIIStrip["PII Stripping\n(remove personal data fields)"] PIIStrip --> Format["JSON Structured Format"] Format --> Stderr["stderr Output\n(append-only)"] Stderr --> External["External Log Collection\n(host-managed)"]
Audit Log Fields
Field
Type
Description
timestamp
ISO 8601
Event occurrence time
toolName
string
MCP tool identifier
parameters
object
Sanitized input parameters (PII removed)
resultStatus
enum
success, error, rate_limited
durationMs
number
Execution duration
errorType
string?
Error category (no stack traces)
cacheHit
boolean?
Whether result came from cache
π‘οΈ Data Protection and GDPR
Personal Data Inventory
Data Category
EP API Endpoint
GDPR Basis
Retention in Cache
Minimization Applied
MEP Names
/meps/{id}
Public role (Art. 6.1.e)
15 min TTL
Name, group only
MEP Contact
/meps/{id}
Legitimate interest
15 min TTL
Official EP address only
MEP Votes
/votes
Public interest
15 min TTL
Vote record, no commentary
MEP Attendance
/plenary-sessions
Public interest
15 min TTL
Session data only
MEP Declarations
/meps/{id}/declarations
Public role
15 min TTL
Official declarations only
GDPR Principles Implementation
Principle
Implementation
Lawfulness
Processing public parliamentary records per Art. 6.1.e (public interest)
Purpose Limitation
Data used solely for parliamentary intelligence queries
Data Minimization
Field selection queries β only request needed attributes
Accuracy
Data sourced directly from official EP API
Storage Limitation
LRU cache with 15-min TTL; no persistent storage
Integrity and Confidentiality
HTTPS transport, no local file system writes
Accountability
Audit logging of all data access requests
π Network Security and Perimeter Protection
Outbound Connections
Destination
Protocol
Port
TLS
Purpose
data.europarl.europa.eu
HTTPS
443
TLS 1.2+
EP Open Data Portal API v2
EP Vocabulary endpoints
HTTPS
443
TLS 1.2+
AT4EU taxonomy lookups
Security Headers (Outbound Requests)
// Applied to all EP API requests headers: { 'Accept': 'application/json', 'User-Agent': 'European-Parliament-MCP-Server/1.1', 'Accept-Encoding': 'gzip, deflate, br' }
No Inbound Network Exposure
Server operates exclusively via stdio (no listening sockets)
No HTTP server, no WebSocket server in current v1.1
All tool errors are reported via the ToolError class which carries toolName, operation, isRetryable, and optional cause β ensuring structured error reporting without leaking internal implementation details. Success responses use buildToolResponse() for consistent JSON formatting.
Error Type
Response to Client
Logged Internally
Zod validation error
Structured field errors
Full error details
EP API error (4xx)
Generic "API error" message
Status code, URL, response body
EP API error (5xx)
Generic "service unavailable"
Full error details
Network timeout
"Request timeout"
URL, timeout duration
Rate limit exceeded
"Rate limit exceeded"
Token state, request details
Unexpected error
"Internal error"
Full stack trace (internal only)
π Defense-in-Depth Strategy
Security Layer Architecture
flowchart TD subgraph Layer1["Layer 1: Process Isolation"] OS["OS Process Boundaries"] STDIO["stdio Transport\n(no network exposure)"] end