Guide · Enterprise Security
MCP server GDPR compliance
The General Data Protection Regulation applies to any processing of personal data about EU residents — including processing that happens inside an MCP tools/call. When an MCP server receives a tool argument containing a customer email address, a user ID that can be linked to a person, health data, or financial records, the server is processing personal data under GDPR. That doesn't make MCP inherently non-compliant, but it does create obligations: lawful basis for processing, data minimization, retention limits, the right to erasure, and — when you're processing on behalf of another controller — a Data Processing Agreement. This guide maps those obligations to concrete implementation choices for MCP server developers.
TL;DR
GDPR applies to your MCP server if tool arguments or results contain data that can identify a living person (directly or indirectly). The most important design choice is at the inputSchema level: tools that accept customer_id are less risky than tools that accept customer_email, which are less risky than tools that accept customer_full_record. Minimize what you accept. Log argument keys, not values. Set explicit retention policies for tool call logs. If you provide MCP services to other businesses, you need a DPA. AliveMCP's monitoring layer collects only operational metadata (timestamps, HTTP status codes, latency) — no personal data flows through monitoring probes, so no DPA is needed for the monitoring relationship.
When GDPR applies to an MCP server
GDPR applies when personal data is processed. Personal data is any information relating to an identified or identifiable natural person. For MCP servers, ask this question about each tool: can the arguments or results of this tool be used to identify a specific living person?
| Tool signature | Personal data? | Reason |
|---|---|---|
search_public_docs(query: str) | No (usually) | Query is about documents, not people — unless users search for their own name |
get_customer(customer_id: str) | Yes | customer_id links to a person; result contains person-identifying data |
send_email(to: str, body: str) | Yes | to is an email address (directly identifies a person) |
run_analytics_query(sql: str) | Depends | Query may return aggregate data (not personal) or individual records (personal) |
get_system_metrics(host: str) | No | Infrastructure data, no person linkage |
log_user_action(user_id: str, action: str) | Yes | user_id + action creates a personal data processing record |
The EU/EEA establishment of either the controller (typically your customer) or the data subjects (the people whose data is processed) is what makes GDPR applicable, not the location of the MCP server itself. A US-hosted MCP server processing EU customer data is within GDPR scope.
Data minimization in tool schema design
Article 5(1)(c) of GDPR requires that personal data be "adequate, relevant, and limited to what is necessary" — the data minimization principle. Applied to MCP tool design, this means accepting the least-identifying argument that still enables the tool to do its job:
# Excessive: accepts full customer record (includes name, email, address, payment info)
@mcp.tool()
async def update_customer_tier(customer: CustomerRecord, new_tier: str) -> str:
"""Update a customer's subscription tier."""
# Only needs the ID and new tier — why accept the full record?
return await _update_tier(customer.id, new_tier)
# Minimal: accepts only what's needed
@mcp.tool()
async def update_customer_tier(customer_id: str, new_tier: str) -> str:
"""Update a customer's subscription tier by ID."""
return await _update_tier(customer_id, new_tier)
# The inputSchema difference matters:
# BAD: {"properties": {"customer": {"type": "object", "properties": {"id": {}, "name": {}, "email": {}, ...}}}}
# GOOD: {"properties": {"customer_id": {"type": "string", "description": "Customer account ID (not email)"}}}
This matters beyond compliance: smaller tool arguments reduce token usage, make it easier to trace what data went where, and limit blast radius if a tool result is logged somewhere it shouldn't be.
Pseudonymization vs anonymization
GDPR treats pseudonymized data (customer_id instead of name/email) as personal data — it's still linkable to a person with the right lookup table. Anonymized data (aggregate stats, irreversibly de-identified) is not personal data. Prefer pseudonymization in tool arguments (use opaque IDs) and anonymization in tool outputs where the LLM doesn't need individual-level data.
Lawful basis for tool call processing
Every processing activity under GDPR requires one of six lawful bases. For MCP servers processing personal data, the most common bases are:
| Lawful basis | When it applies to MCP | Documentation requirement |
|---|---|---|
| Contract (Art. 6(1)(b)) | MCP tool is fulfilling a service the user has contracted for (e.g., querying their own account data) | Terms of service that cover the tool call activity |
| Legitimate interests (Art. 6(1)(f)) | Internal tools processing employee data, fraud detection, security monitoring | Legitimate Interests Assessment (LIA) document |
| Legal obligation (Art. 6(1)(c)) | Tools that generate regulatory reports or compliance-required logs | Reference to the specific legal obligation |
| Consent (Art. 6(1)(a)) | Rarely the right basis for automated MCP tool calls — consent requires freely given, specific, informed opt-in for each processing purpose | Consent records with timestamp and mechanism |
Maintain a Record of Processing Activities (RoPA) that lists each MCP tool that processes personal data, the categories of data processed, the lawful basis, and the retention period. This is a legal requirement for organisations with 250+ employees, and best practice for smaller teams in GDPR scope.
Conversation log retention and deletion
MCP tool calls are often logged as part of broader AI conversation logs (the full message history including tool arguments and results). Those logs contain personal data if any tool argument or result does. Retention obligations:
# Log schema with retention support
CREATE TABLE mcp_tool_call_logs (
id INTEGER PRIMARY KEY,
ts TEXT NOT NULL, -- ISO 8601 timestamp
user_id TEXT, -- pseudonymous user identifier (not email)
tool_name TEXT NOT NULL,
arg_keys TEXT, -- JSON array of argument key names (not values)
result_category TEXT, -- 'success' | 'error' | 'no_data'
session_id TEXT, -- links to conversation session
delete_after TEXT -- ISO date for scheduled deletion (e.g., ts + 90 days)
);
-- Scheduled deletion: run nightly
DELETE FROM mcp_tool_call_logs
WHERE delete_after IS NOT NULL
AND date(delete_after) <= date('now');
-- Right to erasure: delete all logs for a specific user
DELETE FROM mcp_tool_call_logs
WHERE user_id = ? AND ts < datetime('now', '-1 day');
-- Note: keep a tombstone record (user_id hash, deletion_requested_at, fulfilled_at)
-- to prove erasure was performed
Log argument keys, not values. "arg_keys": ["customer_id", "new_tier"] gives you operational traceability without storing the actual customer identifier in the audit log. Your application already has the customer_id in the response — the log doesn't need it too.
Right to erasure (Article 17)
Data subjects can request deletion of their personal data. For MCP servers, this means you need to be able to find and delete all personal data linked to a specific individual across: conversation logs, tool call logs, cached tool results, and any derived data created from tool outputs.
async def fulfill_erasure_request(user_id: str) -> dict:
"""Process a GDPR right-to-erasure request for an MCP server user."""
results = {}
# 1. Delete conversation session data
deleted_sessions = DB.execute(
"DELETE FROM conversation_sessions WHERE user_id = ? RETURNING id",
(user_id,)
).fetchall()
results["sessions_deleted"] = len(deleted_sessions)
# 2. Delete tool call logs
DB.execute(
"DELETE FROM mcp_tool_call_logs WHERE user_id = ?",
(user_id,)
)
results["tool_call_logs_deleted"] = DB.rowcount
# 3. Invalidate any cached tool results associated with this user
await cache.delete_pattern(f"tool_result:*:user:{user_id}")
results["cache_keys_invalidated"] = True
# 4. Log the erasure (keep pseudonymous proof, not personal data)
erasure_id = hashlib.sha256(user_id.encode()).hexdigest()[:16]
DB.execute("""
INSERT INTO erasure_log (pseudonymous_id, requested_at, fulfilled_at)
VALUES (?, ?, ?)
""", (erasure_id, datetime.now(timezone.utc).isoformat(),
datetime.now(timezone.utc).isoformat()))
DB.commit()
results["erasure_log_id"] = erasure_id
return results
The erasure log entry (pseudonymous ID + timestamps) is evidence that you fulfilled the request — keep it even after all the personal data is gone. GDPR requires you to be able to demonstrate compliance, and a bare deletion leaves no proof.
Data Processing Agreements (DPA)
If you operate an MCP server that other businesses use to process their customers' personal data, you are a data processor under GDPR (Article 28). Your customers are data controllers. This relationship requires a DPA — a contract that governs how you handle their data, what security measures you implement, and what happens if there's a breach.
Key DPA clauses for MCP server operators:
- Subject matter and duration: what tool calls you'll process and for how long
- Nature and purpose: what the MCP tools do and why the controller needs this processing
- Categories of data subjects: who the personal data relates to (customers, employees, etc.)
- Security measures: your specific technical controls (encryption in transit, access control, audit logging)
- Sub-processors: any service you use that also processes the data (your hosting provider, your own upstream MCP dependencies)
- Breach notification: you must notify the controller within 72 hours of discovering a personal data breach
- Deletion on termination: what you'll do with data when the customer ends the relationship
Most cloud hosting providers (AWS, Google Cloud, Azure, Fly.io, Railway) offer standard DPAs — sign them before deploying any MCP server that processes personal data. Your hosting provider is a sub-processor for the MCP server's processing activities.
Cross-border data transfers
Transferring personal data from the EU/EEA to a country without an EU adequacy decision (including the US, without a specific transfer mechanism) requires additional safeguards. For MCP servers, this matters when:
- An EU-based agent calls an MCP server hosted in the US that processes EU user data
- An MCP server in the EU sends tool call results to a US-hosted LLM API (OpenAI, Anthropic, etc.)
- EU data is logged to a US-based monitoring or analytics service
The primary transfer mechanisms are Standard Contractual Clauses (SCCs, included in most cloud provider DPAs), binding corporate rules (for intra-group transfers), or the EU–US Data Privacy Framework (for US entities certified under DPF). If you use OpenAI or Anthropic APIs and pass EU personal data in tool call results, check whether those APIs are covered by SCCs in your service agreement — most are, but verify.
AliveMCP's monitoring probes collect operational metadata (HTTP timestamps, status codes, latency measurements) — no tool arguments or results flow through the monitoring layer. The monitoring relationship doesn't involve personal data transfer, so no transfer mechanism is required for the monitoring activity itself.
Frequently asked questions
Does GDPR apply to MCP servers if I'm not an EU company?
Yes, if you process personal data about EU residents. GDPR has extraterritorial reach (Article 3(2)): it applies to organisations outside the EU when they offer goods or services to EU residents or monitor the behaviour of EU residents, regardless of where the organisation is established. An MCP server operated by a US startup that processes EU customer data is within GDPR scope for those processing activities.
Are MCP tool call logs personal data?
It depends on what's in them. If the log contains user IDs, session IDs that can be linked to individuals, IP addresses, or tool argument content that references personal data, the logs are personal data. If logs only contain anonymized metrics (error rates, latency by tool name, no user linkage), they're operational data. Best practice: structure logs from the start to be non-personal by logging argument keys and anonymized user identifiers, so the logs don't create GDPR obligations by themselves.
How long can I retain MCP server logs that contain personal data?
GDPR requires data to be kept "no longer than necessary for the purposes for which the personal data are processed" (storage limitation principle, Article 5(1)(e)). For operational/audit logs, 90 days is defensible for most purposes. For security investigation logs, 1 year is defensible with a documented security purpose. For fraud prevention or legal hold, longer retention with documented justification. Whatever you decide, document the retention period in your RoPA and implement automated deletion — manual deletion processes are unreliable and won't satisfy auditors.
What if an MCP tool result contains personal data I didn't expect?
If a run_sql_query tool returns a result set containing names and emails, the result is personal data even if you intended it to be aggregate. Options: (1) sanitize results at the tool level (strip or hash PII before returning to the LLM); (2) enforce query patterns (only allow pre-approved query templates, not freeform SQL); (3) classify the tool as a personal data processor and apply full GDPR controls. Option (1) is the lowest-friction approach — use a regex or named-entity recognition pass over tool results before they're returned, and log when stripping occurs.
Does a third-party MCP server my agent uses need to sign a DPA with me?
If the third-party MCP server processes personal data on your behalf (your users' data flows through their tools), then yes — they're acting as your sub-processor and a DPA is required. If the third-party MCP server only processes its own data (it's a weather API or a public search engine — no personal data of yours flows to it), no DPA is needed. Many indie MCP server authors don't have DPAs available. Avoid passing personal data to MCP servers that can't provide a DPA — use a stripping middleware layer between your agent and the tool call if you need to use such a server.
Further reading
- MCP server SOC 2 — trust criteria, audit evidence, and compliance controls
- MCP server audit logging — structured event logs for compliance
- MCP server SAML SSO — enterprise single sign-on and user attribution
- MCP server security monitoring — detecting anomalies and access violations
- MCP server secrets management — credentials, rotation, and vault patterns
- MCP server structured logging — JSON logs for compliance and debugging
- AliveMCP — continuous protocol monitoring for MCP servers