Mask PII in MCP Arguments Instead of Blocking the Call
Sometimes the right answer isn't to block a legitimate MCP call, just to strip the PII out of it first. This rewrites the tool's arguments via `updatedInput` so the call still goes through, but with masked values in place of anything PII-shaped.
1. Save this as the hook script
#!/usr/bin/env python3
"""PreToolUse hook — masks PII-shaped values in an mcp__ call's arguments
via updatedInput rather than blocking the call. Wire to matcher
"mcp__.*"."""
import json, re, sys
data = json.load(sys.stdin)
tool_name = data.get("tool_name", "")
tool_input = data.get("tool_input") or {}
if not tool_name.startswith("mcp__"):
sys.exit(0)
changed = False
masked = dict(tool_input)
for k, v in list(masked.items()):
if isinstance(v, str) and re.search(r"\b\d{3}-\d{2}-\d{4}\b", v):
masked[k] = re.sub(r"\b\d{3}-\d{2}-\d{4}\b", "***-**-****", v)
changed = True
if changed:
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": masked,
}
}))
sys.exit(0)
Save to a path inside your project, e.g. .claude/hooks/mask-pii-in-mcp-arguments.sh, then chmod +x it.
2. Wire it into .claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__.*",
"hooks": [
{"type": "command", "command": "python3 .claude/hooks/mask-pii-in-mcp-arguments.py"}
]
}
]
}
}
Before you use this
A hook runs with your local shell's permissions — review the script above before adding it, the same way you'd review any script you didn't write yourself. See our guide on hook security risks for the specific CVEs this category of feature has already produced.
Related hooks