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 signaturePersonal 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)Yescustomer_id links to a person; result contains person-identifying data
send_email(to: str, body: str)Yesto is an email address (directly identifies a person)
run_analytics_query(sql: str)DependsQuery may return aggregate data (not personal) or individual records (personal)
get_system_metrics(host: str)NoInfrastructure data, no person linkage
log_user_action(user_id: str, action: str)Yesuser_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 basisWhen it applies to MCPDocumentation 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 monitoringLegitimate Interests Assessment (LIA) document
Legal obligation (Art. 6(1)(c))Tools that generate regulatory reports or compliance-required logsReference 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 purposeConsent 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:

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:

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

Know when your MCP server is down — before users do

AliveMCP probes your server's MCP endpoint every minute, detects protocol errors and transport failures, and pages you before users notice.

Start monitoring free