agent-data-residency-mcp 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_data_residency_mcp-1.0.0/.cursorrules +13 -0
- agent_data_residency_mcp-1.0.0/.gitignore +37 -0
- agent_data_residency_mcp-1.0.0/LICENSE +21 -0
- agent_data_residency_mcp-1.0.0/PKG-INFO +36 -0
- agent_data_residency_mcp-1.0.0/README.md +67 -0
- agent_data_residency_mcp-1.0.0/pyproject.toml +30 -0
- agent_data_residency_mcp-1.0.0/server.py +391 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Agent Data Residency MCP - Auto-trigger Rules
|
|
2
|
+
|
|
3
|
+
When the user asks about GDPR Chapter V, cross-border data transfers, adequacy decisions, Standard Contractual Clauses (SCCs), Binding Corporate Rules (BCRs), Schrems II, data localization, EU→US data transfers, or "where does this data live?" for agent-to-agent communication, use agent-data-residency-mcp tools:
|
|
4
|
+
|
|
5
|
+
- **check_residency_policy**: Verdict on source→target transfer (permitted / restricted / prohibited)
|
|
6
|
+
- **get_transfer_basis**: List GDPR Chapter V mechanisms with documentation requirements
|
|
7
|
+
- **list_adequacy_decisions**: All 16 current EU adequacy decisions
|
|
8
|
+
- **check_eu_ai_act_data_governance**: Article 10 duties for high-risk systems
|
|
9
|
+
- **log_transfer**: Pro+ — immutable audit log entry
|
|
10
|
+
|
|
11
|
+
Install: `pip install agent-data-residency-mcp`
|
|
12
|
+
|
|
13
|
+
Closes the last A2A gap: programmatic transfer-basis lookup at agent runtime, not months later in audit.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
build/
|
|
7
|
+
develop-eggs/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
lib/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.installed.cfg
|
|
20
|
+
*.egg
|
|
21
|
+
|
|
22
|
+
# Virtual environments
|
|
23
|
+
.venv/
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.vscode/
|
|
30
|
+
.idea/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# OS
|
|
36
|
+
.DS_Store
|
|
37
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MEOK AI Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-data-residency-mcp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Agent data residency + GDPR Chapter V transfer-basis runtime guard. Programmatically answer 'where does this data live?' for agent-to-agent transfers. Adequacy decisions, SCCs, BCRs, EU AI Act Article 10.
|
|
5
|
+
Project-URL: Homepage, https://meok.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/meok-ai-labs/agent-data-residency-mcp
|
|
7
|
+
Author-email: MEOK AI Labs <hello@meok.ai>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 MEOK AI Labs
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: a2a,agent-to-agent,ai-governance,compliance,data-residency,gdpr,mcp,mcp-server,meok,model-context-protocol
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
35
|
+
Requires-Python: >=3.10
|
|
36
|
+
Requires-Dist: mcp>=1.0.0
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Agent Data Residency MCP
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/agent-data-residency-mcp/)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://meok.ai)
|
|
6
|
+
|
|
7
|
+
**The only MCP server that answers "where does this data live?" at agent runtime.**
|
|
8
|
+
|
|
9
|
+
When agent A (EU) talks to agent B (US), where does data flow? Is GDPR Chapter V satisfied? Does the transfer need an adequacy decision, SCCs, or BCRs? This MCP gives programmatic answers.
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
Enterprises rolling out multi-agent systems hit a runtime question nobody answers cleanly: **when agent A in Frankfurt invokes a tool on agent B in Virginia, what just happened legally?**
|
|
14
|
+
|
|
15
|
+
Most MCPs ignore the transfer. Compliance teams audit it months later. This MCP makes the answer a single tool call.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install agent-data-residency-mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Tools
|
|
24
|
+
|
|
25
|
+
| Tool | Purpose |
|
|
26
|
+
|------|---------|
|
|
27
|
+
| `check_residency_policy` | Source→target verdict (permitted / restricted / prohibited) with legal basis |
|
|
28
|
+
| `get_transfer_basis` | List GDPR Chapter V mechanisms: adequacy, SCCs, BCRs, derogations, UK IDTA |
|
|
29
|
+
| `list_adequacy_decisions` | All 16 current EU adequacy decisions with scope + warnings |
|
|
30
|
+
| `check_eu_ai_act_data_governance` | Article 10 duties + cross-refs to GDPR Chapter V |
|
|
31
|
+
| `log_transfer` | Pro+ — immutable audit log entry (pairs with agent-audit-logger-mcp) |
|
|
32
|
+
|
|
33
|
+
## Example
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
result = check_residency_policy(
|
|
37
|
+
source_region="DE",
|
|
38
|
+
target_region="US",
|
|
39
|
+
data_classification="personal"
|
|
40
|
+
)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"verdict": "permitted-with-conditions",
|
|
47
|
+
"rationale": "Adequacy decision for united-states (2023-07-10). Scope: EU-US Data Privacy Framework certified organisations only",
|
|
48
|
+
"legal_basis": "GDPR Article 45 — adequacy decision",
|
|
49
|
+
"warning": "Subject to ongoing CJEU scrutiny. Schrems III risk."
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Pairs with
|
|
54
|
+
|
|
55
|
+
- `agent-audit-logger-mcp` — immutable A2A audit trail
|
|
56
|
+
- `agent-policy-enforcement-mcp` — define per-region transfer policies
|
|
57
|
+
- `eu-ai-act-compliance-mcp` — Article 10 data-governance check
|
|
58
|
+
|
|
59
|
+
## Pricing
|
|
60
|
+
|
|
61
|
+
- **Free**: 10 calls/day. All check tools.
|
|
62
|
+
- **Pro** £79/mo: unlimited + `log_transfer` audit trail. [Subscribe](https://buy.stripe.com/14A4gB3K4eUWgYR56o8k836)
|
|
63
|
+
- **Enterprise** £1,499/mo: white-label + on-premise. hello@meok.ai
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT © MEOK AI Labs
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agent-data-residency-mcp"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Agent data residency + GDPR Chapter V transfer-basis runtime guard. Programmatically answer 'where does this data live?' for agent-to-agent transfers. Adequacy decisions, SCCs, BCRs, EU AI Act Article 10."
|
|
9
|
+
license = {file = "LICENSE"}
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
authors = [{name = "MEOK AI Labs", email = "hello@meok.ai"}]
|
|
12
|
+
keywords = ["mcp", "mcp-server", "model-context-protocol", "ai-governance", "gdpr", "data-residency", "agent-to-agent", "a2a", "compliance", "meok"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Topic :: Software Development :: Libraries",
|
|
18
|
+
]
|
|
19
|
+
dependencies = ["mcp>=1.0.0"]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://meok.ai"
|
|
23
|
+
Repository = "https://github.com/meok-ai-labs/agent-data-residency-mcp"
|
|
24
|
+
|
|
25
|
+
[tool.hatch.build.targets.wheel]
|
|
26
|
+
packages = ["."]
|
|
27
|
+
only-include = ["server.py"]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
agent-data-residency-mcp = "server:main"
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Agent Data Residency MCP Server
|
|
4
|
+
================================
|
|
5
|
+
By MEOK AI Labs | https://meok.ai
|
|
6
|
+
|
|
7
|
+
The only MCP server that answers "where does this data live?" at agent runtime.
|
|
8
|
+
|
|
9
|
+
When agent A (EU) talks to agent B (US), where does data flow? Is GDPR
|
|
10
|
+
Chapter V satisfied? Is the EU AI Act data-governance hook tripped? Does
|
|
11
|
+
the transfer need an adequacy decision, SCCs, or BCRs?
|
|
12
|
+
|
|
13
|
+
This MCP closes the last A2A gap identified in MEOK's portfolio:
|
|
14
|
+
- Programmatic transfer-basis lookup (GDPR Articles 44-49)
|
|
15
|
+
- EU AI Act Article 10 data-governance alignment
|
|
16
|
+
- Adequacy decisions matrix (UK, Japan, Korea, Switzerland, Canada, etc.)
|
|
17
|
+
- Per-region data classification routing
|
|
18
|
+
|
|
19
|
+
Install: pip install agent-data-residency-mcp
|
|
20
|
+
Run: python server.py
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
import os
|
|
26
|
+
from datetime import datetime, timedelta, timezone
|
|
27
|
+
from typing import Optional
|
|
28
|
+
from collections import defaultdict
|
|
29
|
+
from mcp.server.fastmcp import FastMCP
|
|
30
|
+
|
|
31
|
+
import os as _os
|
|
32
|
+
|
|
33
|
+
_MEOK_API_KEY = _os.environ.get("MEOK_API_KEY", "")
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
sys.path.insert(0, os.path.expanduser("~/clawd/meok-labs-engine/shared"))
|
|
37
|
+
from auth_middleware import check_access as _shared_check_access
|
|
38
|
+
_AUTH_ENGINE_AVAILABLE = True
|
|
39
|
+
except ImportError:
|
|
40
|
+
_AUTH_ENGINE_AVAILABLE = False
|
|
41
|
+
|
|
42
|
+
def _shared_check_access(api_key: str = ""):
|
|
43
|
+
"""Fallback when shared auth engine is not available."""
|
|
44
|
+
if _MEOK_API_KEY and api_key and api_key == _MEOK_API_KEY:
|
|
45
|
+
return True, "OK", "pro"
|
|
46
|
+
if _MEOK_API_KEY and api_key and api_key != _MEOK_API_KEY:
|
|
47
|
+
return False, "Invalid API key. Get one at https://meok.ai/api-keys", "free"
|
|
48
|
+
return True, "OK", "free"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def check_access(api_key: str = ""):
|
|
52
|
+
"""Unified access check."""
|
|
53
|
+
return _shared_check_access(api_key)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
FREE_DAILY_LIMIT = 10
|
|
57
|
+
_usage: dict[str, list[datetime]] = defaultdict(list)
|
|
58
|
+
STRIPE_PRO = "https://buy.stripe.com/14A4gB3K4eUWgYR56o8k836"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _rl(tier="free") -> Optional[str]:
|
|
62
|
+
if tier in ("pro", "professional", "enterprise"):
|
|
63
|
+
return None
|
|
64
|
+
now = datetime.now(timezone.utc)
|
|
65
|
+
cutoff = now - timedelta(days=1)
|
|
66
|
+
_usage["anonymous"] = [t for t in _usage["anonymous"] if t > cutoff]
|
|
67
|
+
if len(_usage["anonymous"]) >= FREE_DAILY_LIMIT:
|
|
68
|
+
return f"Free tier limit ({FREE_DAILY_LIMIT}/day). Pro £79/mo: {STRIPE_PRO}"
|
|
69
|
+
_usage["anonymous"].append(now)
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ── GDPR Adequacy decisions (current as of 2026-05-13) ─────────────────
|
|
74
|
+
ADEQUACY_DECISIONS = {
|
|
75
|
+
"andorra": {"decided": "2010-10-19", "status": "adequate", "scope": "general"},
|
|
76
|
+
"argentina": {"decided": "2003-06-30", "status": "adequate", "scope": "general"},
|
|
77
|
+
"canada": {"decided": "2001-12-20", "status": "adequate", "scope": "PIPEDA commercial only"},
|
|
78
|
+
"faroe-islands": {"decided": "2010-03-05", "status": "adequate", "scope": "general"},
|
|
79
|
+
"guernsey": {"decided": "2003-11-21", "status": "adequate", "scope": "general"},
|
|
80
|
+
"isle-of-man": {"decided": "2004-04-28", "status": "adequate", "scope": "general"},
|
|
81
|
+
"israel": {"decided": "2011-01-31", "status": "adequate", "scope": "general"},
|
|
82
|
+
"japan": {"decided": "2019-01-23", "status": "adequate", "scope": "mutual adequacy under PIPA"},
|
|
83
|
+
"jersey": {"decided": "2008-05-08", "status": "adequate", "scope": "general"},
|
|
84
|
+
"new-zealand": {"decided": "2012-12-19", "status": "adequate", "scope": "general"},
|
|
85
|
+
"south-korea": {"decided": "2021-12-17", "status": "adequate", "scope": "PIPA"},
|
|
86
|
+
"switzerland": {"decided": "2000-07-26", "status": "adequate", "scope": "general (revised FADP 2023)"},
|
|
87
|
+
"united-kingdom": {"decided": "2021-06-28", "status": "adequate", "scope": "general (review by 2025)"},
|
|
88
|
+
"united-states": {
|
|
89
|
+
"decided": "2023-07-10",
|
|
90
|
+
"status": "adequate-partial",
|
|
91
|
+
"scope": "EU-US Data Privacy Framework certified organisations only",
|
|
92
|
+
"warning": "Subject to ongoing CJEU scrutiny. Schrems III risk.",
|
|
93
|
+
},
|
|
94
|
+
"uruguay": {"decided": "2012-08-21", "status": "adequate", "scope": "general"},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# ── EU AI Act Article 10 data-governance hooks ─────────────────────────
|
|
98
|
+
EU_AI_ACT_DATA_RULES = {
|
|
99
|
+
"high-risk-systems": {
|
|
100
|
+
"article": "EU AI Act Article 10",
|
|
101
|
+
"duties": [
|
|
102
|
+
"Training, validation, testing datasets must meet quality criteria",
|
|
103
|
+
"Examination for biases that may affect health, safety, fundamental rights",
|
|
104
|
+
"Data governance and management practices for high-risk AI systems",
|
|
105
|
+
"Datasets must be relevant, representative, free of errors, complete",
|
|
106
|
+
],
|
|
107
|
+
"transfers": "Cross-border training data flows must respect GDPR Chapter V",
|
|
108
|
+
},
|
|
109
|
+
"biometric-data": {
|
|
110
|
+
"article": "EU AI Act Article 5(1)(e) + GDPR Article 9",
|
|
111
|
+
"duties": [
|
|
112
|
+
"Real-time remote biometric ID prohibited in public spaces (with narrow exceptions)",
|
|
113
|
+
"Special category personal data — heightened protection",
|
|
114
|
+
"Explicit consent or substantial public interest required",
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# ── Transfer basis matrix ──────────────────────────────────────────────
|
|
120
|
+
TRANSFER_BASES = {
|
|
121
|
+
"adequacy-decision": {
|
|
122
|
+
"article": "GDPR Article 45",
|
|
123
|
+
"scope": "Country/sector with EU adequacy decision",
|
|
124
|
+
"documentation": "Adequacy decision reference (Commission Implementing Decision)",
|
|
125
|
+
},
|
|
126
|
+
"standard-contractual-clauses": {
|
|
127
|
+
"article": "GDPR Article 46(2)(c)/(d)",
|
|
128
|
+
"scope": "Most third-country transfers without adequacy",
|
|
129
|
+
"documentation": "EU SCCs 2021 Module 1-4 + Transfer Impact Assessment",
|
|
130
|
+
"since_schrems_ii": "Must include supplementary measures",
|
|
131
|
+
},
|
|
132
|
+
"binding-corporate-rules": {
|
|
133
|
+
"article": "GDPR Article 47",
|
|
134
|
+
"scope": "Intra-group transfers across countries",
|
|
135
|
+
"documentation": "BCRs approved by lead DPA",
|
|
136
|
+
},
|
|
137
|
+
"derogations-specific-situations": {
|
|
138
|
+
"article": "GDPR Article 49",
|
|
139
|
+
"scope": "Narrow exceptions: explicit consent, contract necessity, vital interests",
|
|
140
|
+
"documentation": "Article 49 ground + DPIA",
|
|
141
|
+
"warning": "Not for systematic or repetitive transfers",
|
|
142
|
+
},
|
|
143
|
+
"uk-international-data-transfer-agreement": {
|
|
144
|
+
"article": "UK GDPR Article 46 + IDTA",
|
|
145
|
+
"scope": "Post-Brexit UK→third-country transfers",
|
|
146
|
+
"documentation": "IDTA 2022 + UK Addendum to EU SCCs",
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
mcp = FastMCP(
|
|
152
|
+
"Agent Data Residency",
|
|
153
|
+
instructions=(
|
|
154
|
+
"By MEOK AI Labs — Agent data residency + GDPR Chapter V transfer-basis runtime guard. "
|
|
155
|
+
"Use check_residency_policy to determine if a source→target transfer is permitted. "
|
|
156
|
+
"Use get_transfer_basis to identify the legal mechanism. Use log_transfer to record. "
|
|
157
|
+
"Free tier: 10/day. Pro tier: unlimited + signed compliance attestations."
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@mcp.tool()
|
|
163
|
+
def check_residency_policy(
|
|
164
|
+
source_region: str,
|
|
165
|
+
target_region: str,
|
|
166
|
+
data_classification: str = "personal",
|
|
167
|
+
api_key: str = "",
|
|
168
|
+
) -> str:
|
|
169
|
+
"""Check if a cross-border data transfer between agents is permitted.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
source_region: ISO country code or EU/EEA/UK (e.g., "DE", "FR", "US", "UK", "EU").
|
|
173
|
+
target_region: ISO country code or region of the receiving agent.
|
|
174
|
+
data_classification: One of: personal, sensitive-personal, biometric, health, financial, special-category, public.
|
|
175
|
+
api_key: Optional MEOK API key.
|
|
176
|
+
|
|
177
|
+
Returns: JSON with verdict (permitted/restricted/prohibited), legal basis, required documentation.
|
|
178
|
+
"""
|
|
179
|
+
allowed, msg, tier = check_access(api_key)
|
|
180
|
+
if not allowed:
|
|
181
|
+
return json.dumps({"error": msg, "upgrade_url": STRIPE_PRO})
|
|
182
|
+
if err := _rl(tier):
|
|
183
|
+
return json.dumps({"error": err, "upgrade_url": STRIPE_PRO})
|
|
184
|
+
|
|
185
|
+
src = source_region.lower().strip()
|
|
186
|
+
tgt = target_region.lower().strip()
|
|
187
|
+
classification = data_classification.lower().strip()
|
|
188
|
+
|
|
189
|
+
# EU/EEA inbound = always OK if source is EU/EEA member
|
|
190
|
+
eu_eea = {"eu", "eea", "at", "be", "bg", "hr", "cy", "cz", "dk", "ee", "fi", "fr",
|
|
191
|
+
"de", "gr", "hu", "ie", "it", "lv", "lt", "lu", "mt", "nl", "pl", "pt",
|
|
192
|
+
"ro", "sk", "si", "es", "se", "is", "li", "no"}
|
|
193
|
+
|
|
194
|
+
src_in_eu = src in eu_eea
|
|
195
|
+
tgt_in_eu = tgt in eu_eea
|
|
196
|
+
|
|
197
|
+
if src_in_eu and tgt_in_eu:
|
|
198
|
+
return json.dumps({
|
|
199
|
+
"verdict": "permitted",
|
|
200
|
+
"rationale": "Intra-EU/EEA transfer — no Chapter V mechanism required.",
|
|
201
|
+
"legal_basis": "GDPR + national law of source/target member state",
|
|
202
|
+
"documentation": "Standard records of processing (Article 30)",
|
|
203
|
+
"regulation": "GDPR + EU AI Act Article 10 if high-risk",
|
|
204
|
+
"tier": tier,
|
|
205
|
+
}, indent=2)
|
|
206
|
+
|
|
207
|
+
# EU/EEA outbound — check adequacy
|
|
208
|
+
if src_in_eu and not tgt_in_eu:
|
|
209
|
+
# Map country code to adequacy key
|
|
210
|
+
country_map = {
|
|
211
|
+
"us": "united-states", "usa": "united-states",
|
|
212
|
+
"uk": "united-kingdom", "gb": "united-kingdom",
|
|
213
|
+
"jp": "japan", "kr": "south-korea", "ch": "switzerland",
|
|
214
|
+
"ca": "canada", "il": "israel", "nz": "new-zealand",
|
|
215
|
+
"ar": "argentina", "uy": "uruguay",
|
|
216
|
+
}
|
|
217
|
+
ad_key = country_map.get(tgt, tgt)
|
|
218
|
+
if ad_key in ADEQUACY_DECISIONS:
|
|
219
|
+
decision = ADEQUACY_DECISIONS[ad_key]
|
|
220
|
+
verdict = "permitted-with-conditions" if decision.get("warning") else "permitted"
|
|
221
|
+
return json.dumps({
|
|
222
|
+
"verdict": verdict,
|
|
223
|
+
"rationale": f"Adequacy decision for {ad_key} ({decision['decided']}). Scope: {decision['scope']}",
|
|
224
|
+
"legal_basis": "GDPR Article 45 — adequacy decision",
|
|
225
|
+
"warning": decision.get("warning"),
|
|
226
|
+
"documentation": "Adequacy decision reference + standard records",
|
|
227
|
+
"regulation": "GDPR Chapter V",
|
|
228
|
+
"tier": tier,
|
|
229
|
+
}, indent=2)
|
|
230
|
+
else:
|
|
231
|
+
# No adequacy → SCCs needed
|
|
232
|
+
return json.dumps({
|
|
233
|
+
"verdict": "restricted",
|
|
234
|
+
"rationale": f"No adequacy decision for '{tgt}'. Transfer requires Chapter V mechanism.",
|
|
235
|
+
"legal_basis_options": [
|
|
236
|
+
"GDPR Article 46(2)(c) — Standard Contractual Clauses (SCCs 2021)",
|
|
237
|
+
"GDPR Article 47 — Binding Corporate Rules (intra-group)",
|
|
238
|
+
"GDPR Article 49 — Derogations (narrow; explicit consent / contract necessity)",
|
|
239
|
+
],
|
|
240
|
+
"required_documentation": [
|
|
241
|
+
"Signed EU SCCs (Module 1-4 depending on roles)",
|
|
242
|
+
"Transfer Impact Assessment (TIA) post-Schrems II",
|
|
243
|
+
"Supplementary technical / organisational / contractual measures",
|
|
244
|
+
],
|
|
245
|
+
"warning": "Since Schrems II (Case C-311/18), SCCs alone are NOT sufficient. TIA + supplementary measures required.",
|
|
246
|
+
"regulation": "GDPR Chapter V",
|
|
247
|
+
"tier": tier,
|
|
248
|
+
}, indent=2)
|
|
249
|
+
|
|
250
|
+
# Special category data — heightened scrutiny
|
|
251
|
+
if classification in ("biometric", "health", "sensitive-personal", "special-category"):
|
|
252
|
+
return json.dumps({
|
|
253
|
+
"verdict": "restricted-heightened",
|
|
254
|
+
"rationale": f"Special category data (Article 9). Transfer requires explicit consent OR substantial public interest OR healthcare necessity.",
|
|
255
|
+
"additional_basis_required": "GDPR Article 9(2) ground in addition to Article 45/46/49 transfer basis",
|
|
256
|
+
"eu_ai_act_check": "EU AI Act Article 5(1)(e) — real-time remote biometric ID in public spaces is PROHIBITED",
|
|
257
|
+
"regulation": "GDPR Articles 9 + 45-49 + EU AI Act Article 5",
|
|
258
|
+
"tier": tier,
|
|
259
|
+
}, indent=2)
|
|
260
|
+
|
|
261
|
+
# Non-EU source / non-EU target — GDPR doesn't apply unless data subject is in EU
|
|
262
|
+
return json.dumps({
|
|
263
|
+
"verdict": "out-of-gdpr-scope",
|
|
264
|
+
"rationale": f"Both source ({src}) and target ({tgt}) are outside EU/EEA. Check local law.",
|
|
265
|
+
"caveat": "GDPR Article 3 may still apply if EU data subjects are affected (extraterritorial scope).",
|
|
266
|
+
"regulation": "Check applicable national/regional law",
|
|
267
|
+
"tier": tier,
|
|
268
|
+
}, indent=2)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@mcp.tool()
|
|
272
|
+
def get_transfer_basis(transfer_type: str = "", api_key: str = "") -> str:
|
|
273
|
+
"""List GDPR Chapter V transfer mechanisms.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
transfer_type: Optional filter — one of: adequacy-decision, standard-contractual-clauses, binding-corporate-rules, derogations-specific-situations, uk-international-data-transfer-agreement.
|
|
277
|
+
|
|
278
|
+
Returns: JSON with full transfer-basis matrix and applicable scenarios.
|
|
279
|
+
"""
|
|
280
|
+
allowed, msg, tier = check_access(api_key)
|
|
281
|
+
if not allowed:
|
|
282
|
+
return json.dumps({"error": msg, "upgrade_url": STRIPE_PRO})
|
|
283
|
+
|
|
284
|
+
if transfer_type:
|
|
285
|
+
key = transfer_type.lower().strip()
|
|
286
|
+
if key in TRANSFER_BASES:
|
|
287
|
+
return json.dumps({key: TRANSFER_BASES[key], "tier": tier}, indent=2)
|
|
288
|
+
return json.dumps({
|
|
289
|
+
"error": f"Unknown transfer type. Use one of: {', '.join(TRANSFER_BASES.keys())}",
|
|
290
|
+
"tier": tier,
|
|
291
|
+
}, indent=2)
|
|
292
|
+
|
|
293
|
+
return json.dumps({
|
|
294
|
+
"transfer_bases": TRANSFER_BASES,
|
|
295
|
+
"regulation": "GDPR Chapter V (Articles 44-49)",
|
|
296
|
+
"post_schrems_ii_warning": "SCCs require Transfer Impact Assessment + supplementary measures since CJEU Case C-311/18 (16 July 2020)",
|
|
297
|
+
"tier": tier,
|
|
298
|
+
}, indent=2)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@mcp.tool()
|
|
302
|
+
def list_adequacy_decisions(api_key: str = "") -> str:
|
|
303
|
+
"""Return all current EU adequacy decisions with status, date, and scope."""
|
|
304
|
+
allowed, msg, tier = check_access(api_key)
|
|
305
|
+
if not allowed:
|
|
306
|
+
return json.dumps({"error": msg, "upgrade_url": STRIPE_PRO})
|
|
307
|
+
return json.dumps({
|
|
308
|
+
"adequacy_decisions": ADEQUACY_DECISIONS,
|
|
309
|
+
"total_count": len(ADEQUACY_DECISIONS),
|
|
310
|
+
"regulation": "GDPR Article 45 — Commission Implementing Decisions",
|
|
311
|
+
"source": "ec.europa.eu/info/law/law-topic/data-protection/international-dimension-data-protection/adequacy-decisions_en",
|
|
312
|
+
"tier": tier,
|
|
313
|
+
}, indent=2)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@mcp.tool()
|
|
317
|
+
def check_eu_ai_act_data_governance(system_type: str = "high-risk", api_key: str = "") -> str:
|
|
318
|
+
"""Check EU AI Act Article 10 data-governance duties for an AI system.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
system_type: One of: high-risk-systems, biometric-data.
|
|
322
|
+
|
|
323
|
+
Returns: JSON with Article 10 duties + cross-references to GDPR Chapter V.
|
|
324
|
+
"""
|
|
325
|
+
allowed, msg, tier = check_access(api_key)
|
|
326
|
+
if not allowed:
|
|
327
|
+
return json.dumps({"error": msg, "upgrade_url": STRIPE_PRO})
|
|
328
|
+
key = system_type.lower().strip().replace("_", "-")
|
|
329
|
+
if key in EU_AI_ACT_DATA_RULES:
|
|
330
|
+
return json.dumps({key: EU_AI_ACT_DATA_RULES[key], "tier": tier}, indent=2)
|
|
331
|
+
return json.dumps({
|
|
332
|
+
"eu_ai_act_data_rules": EU_AI_ACT_DATA_RULES,
|
|
333
|
+
"tier": tier,
|
|
334
|
+
}, indent=2)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@mcp.tool()
|
|
338
|
+
def log_transfer(
|
|
339
|
+
source_region: str,
|
|
340
|
+
target_region: str,
|
|
341
|
+
data_classification: str,
|
|
342
|
+
transfer_basis: str = "",
|
|
343
|
+
purpose: str = "",
|
|
344
|
+
api_key: str = "",
|
|
345
|
+
) -> str:
|
|
346
|
+
"""Log a cross-border data transfer for audit trail (Pro+).
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
source_region: Source country/region.
|
|
350
|
+
target_region: Target country/region.
|
|
351
|
+
data_classification: Data classification (personal, sensitive, etc.).
|
|
352
|
+
transfer_basis: Legal basis used (adequacy, sccs, bcrs, etc.).
|
|
353
|
+
purpose: Transfer purpose.
|
|
354
|
+
|
|
355
|
+
Returns: JSON receipt with timestamp + transfer ID.
|
|
356
|
+
"""
|
|
357
|
+
allowed, msg, tier = check_access(api_key)
|
|
358
|
+
if not allowed:
|
|
359
|
+
return json.dumps({"error": msg, "upgrade_url": STRIPE_PRO})
|
|
360
|
+
if tier == "free":
|
|
361
|
+
return json.dumps({
|
|
362
|
+
"error": "Transfer logging requires Pro tier (immutable audit trail).",
|
|
363
|
+
"upgrade_url": STRIPE_PRO,
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
import hashlib
|
|
367
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
368
|
+
transfer_id = hashlib.sha256(
|
|
369
|
+
f"{timestamp}|{source_region}|{target_region}|{data_classification}".encode()
|
|
370
|
+
).hexdigest()[:16]
|
|
371
|
+
|
|
372
|
+
return json.dumps({
|
|
373
|
+
"transfer_id": transfer_id,
|
|
374
|
+
"timestamp": timestamp,
|
|
375
|
+
"source_region": source_region,
|
|
376
|
+
"target_region": target_region,
|
|
377
|
+
"data_classification": data_classification,
|
|
378
|
+
"transfer_basis": transfer_basis or "unspecified",
|
|
379
|
+
"purpose": purpose or "unspecified",
|
|
380
|
+
"status": "logged",
|
|
381
|
+
"audit_chain": "Pair with agent-audit-logger-mcp for tamper-evident bundle export",
|
|
382
|
+
"tier": tier,
|
|
383
|
+
}, indent=2)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def main():
|
|
387
|
+
mcp.run()
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if __name__ == "__main__":
|
|
391
|
+
main()
|