Skip to main content
Glama
dhirajparihar

ShadowVault MCP Proxy


Stop breaking your AI Agent tools with [REDACTED]

Most PII masking libraries were designed for static document redaction, not autonomous AI agents. Replacing sensitive data with [REDACTED] or <EMAIL_1> completely breaks tool-calling workflows:

  1. Schema & Validator Rejection: When your AI agent attempts to invoke a Stripe API, PostgreSQL tool, or CRM integration, strict downstream validators (Pydantic, regex schemas, database constraints) immediately crash when handed [REDACTED_CARD] instead of a 16-digit numeric card string.

  2. One-Way Irreversibility: Once data is destroyed by one-way redaction, local tools cannot execute real actions. You cannot process a refund, send an email, or dispatch an SMS with [EMAIL]. Bi-directional pseudonymization securely restores real PII at the tool boundary and re-masks outputs before returning to the model.

  3. SSE Streaming Token Tearing: Naive regex replacements leak torn fragments when modern LLMs stream tokens across Server-Sent Events (SSE) chunks (e.g. streaming "u_8f", then "9a1@shadow", then ".vault"). shadow-vault provides a lookahead holdback buffer that reassembles split tokens seamlessly without token tearing.


Related MCP server: maskflow-mcp

Architecture Flow

                     +---------------------------------------+
                     |         END USER / CLIENT             |
                     +---------------------------------------+
                                  |                 ^
                1. Raw User PII   |                 |  8. Hydrated Real PII
                   (e.g. Card)    v                 |     (StreamHydrator SSE)
                     +---------------------------------------+
                     |         SHADOW-VAULT PROXY            |
                     +---------------------------------------+
                        |                          ^
      2. Dehydrated     |                          |  7. Dehydrated Tool
         Safe Prompt    v                          |     Return Value
+------------------------------------+    +------------------------------------+
|         CLOUD LLM / AGENT          |    |          LOCAL MCP TOOL            |
| (OpenAI / Anthropic / LangChain)   |    |      (Stripe / SQL / API)          |
+------------------------------------+    +------------------------------------+
           |                                                 ^
           |  3. Model Tool Call with                        |  4. @vault_guard
           |     Synthetic Tokens                            |     Reversible Hydration
           +-------------------------------------------------+

Quickstart (12 Lines)

Install the core library (zero heavy NLP dependencies):

pip install shadow-vault

Protect any Python function or agent tool in seconds:

from shadow_vault import ShadowVault, vault_guard

vault = ShadowVault()

# 1. Protect your internal tool: automatically receives real PII, returns masked PII
@vault_guard(vault=vault, session_id_arg="session_id")
def charge_customer(email: str, card: str, session_id: str = "default") -> dict:
    # Function executes with REAL PII: email='alice@example.com', card='4532 0151 1283 0366'
    return {"status": "PAID", "receipt": email, "backup_phone": "+91 9876543210"}

# 2. Dehydrate safe prompt for the LLM:
prompt = vault.dehydrate("Charge alice@example.com on card 4532 0151 1283 0366", session_id="s1")
# Prompt: "Charge u_c09753@shadow.vault on card 4000009995970590"

# 3. Model executes tool using synthetic tokens -> returns sanitized output back to agent state:
result = charge_customer(email="u_c09753@shadow.vault", card="4000009995970590", session_id="s1")
# Result: {'status': 'PAID', 'receipt': 'u_c09753@shadow.vault', 'backup_phone': '+919000597059'}

# 4. Ephemeral Agent Runs (Auto-purges memory on exit):
with vault.session("run_123", auto_purge=True) as sess:
    safe_prompt = sess.dehydrate("Refund alice@example.com on card 4532 0151 1283 0366")
    # Run agent tools...
# 100% of mapping records are wiped from RAM/SQLite upon exiting the block!

# 5. Prevent Log Leaks with Drop-In Logging Filter:
import logging
from shadow_vault import VaultLogFilter

logging.getLogger().addFilter(VaultLogFilter(vault))
# Accidental logger.info(real_card) statements are scrubbed before reaching log sinks!

🔬 Zero-Key Reproducible Demos & Verification

Run the self-contained walkthroughs and cryptographic audits (requires NO API keys and NO external dependencies):

# 1. Independent Security & Cryptographic Self-Audit (6 automated checks):
shadow-vault verify
# or: python -m shadow_vault.verify

# 2. End-to-End Real Agent Zero-Leak Wire-Inspection Proof:
python examples/verify_agent_zero_leak.py

# 3. Autonomous Model Context Protocol (MCP) Stdio Gateway & AES-256 Vault:
python examples/demo_mcp_gateway.py

📚 Cookbooks & Interactive Tutorials

Resource

Description

Link

Interactive Google Colab Quickstart

Zero-install interactive walkthrough of dehydration, @vault_guard, streaming holdback buffer, and audit checks

Open In Colab

Claude Desktop MCP Guide

Configure Anthropic's Claude Desktop application (claude_desktop_config.json) with shadow-vault mcp-proxy

Read Cookbook

LangGraph Customer Support Agent

StateGraph multi-turn billing & dispute agent ensuring 0% raw PII in graph checkpoints or memory

Run Script

Agent Zero-Leak Wire Verification

Automated 5-assertion proof that 0% sensitive values touch external networks

Run Script


🎮 Interactive Web Playground

Experience the 3-panel visual privacy playground directly in your browser with real-time token highlighting and sub-millisecond latency counters:

🌐 Live Demo (Zero Install): https://dhirajparihar.github.io/shadow-vault/

  • Panel 1 (User & Local MCP Tool): Displays raw prompt with real PII and verifies @vault_guard restoring real values before local tools execute.

  • Panel 2 (What Cloud LLMs See): Highlights format-preserving synthetic @shadow.vault tokens in green over the wire.

  • Panel 3 (Live SQLite Vault): Inspects the live in-memory mapping table, BLAKE2b deduplication, and sub-millisecond latency counters.

  • Pre-Loaded Scenarios: Includes Fintech UPI/PAN Refund Agent, Healthcare Patient Booking Agent, and DevOps API Key Log Analyzer.


Supported Entities (Global + India)

shadow-vault uses zero-dependency regexes coupled with strict mathematical checksum algorithms so random numbers are never falsely flagged:

Entity Type

Mathematical Checksum / Algorithm

Real Input Example

Format-Preserving Synthetic Output

CREDIT_CARD

Luhn Checksum (mod 10) (13–19 digits)

4532 0151 1283 0366

4000009995970590 (passes Luhn!)

AADHAAR

Verhoeff Dihedral $D_5$ Algorithm

3675 9834 6016

999905970594 (passes Verhoeff!)

PAN_CARD

Indian Income Tax Format ([A-Z]{5}[0-9]{4}[A-Z]{1})

ABCDE1234F

SHDWV7059Z

UPI_ID

Evaluated before email (@okaxis, @okhdfcbank, @paytm, etc.)

dhiraj@okaxis

u_a81c25@okshadow

EMAIL

RFC-5322 (ignores @shadow.vault & UPI handles)

alice@example.com

u_c09753@shadow.vault

PHONE

E.164, Indian mobile (+91 [6-9]\d{9}), US/NANP

+91 9876543210

+919000597059 (valid 10-digit mobile)

LOCATION / ADDRESS

Street suffix pattern matching (St, Ave, Blvd, etc.)

742 Evergreen Terrace

452 Shadow Vault Way

SSN

US Social Security Number (Area/Group/Serial checks)

219-45-7890

900-99-7059 (unissued area code)

API_KEY

OpenAI sk-..., GitHub ghp_..., Google AIza..., Bearer

sk-abcdef1234567890abcdef...

sk-sv-shadow-c0975300000000000000

💡 For Unstructured Names & Ambiguous Free-Text Entities: ShadowVault provides a first-class Microsoft Presidio NER adapter (from shadow_vault.integrations.presidio import PresidioDetector). It pairs high-precision spaCy / transformer NER models with ShadowVault's format-preserving token synthesis and @vault_guard tool boundary hydration.


Why shadow-vault? (Ecosystem Positioning)

Architectural Capability

shadow-vault

Rizzo PII

Microsoft Presidio

LangChain PIIMiddleware

Primary Focus

AI Agent Tools & MCP

Document Anonymization (Italian Legal)

Document Redaction / NLP Extraction

Simple Prompt Pre-filtering

Format-Preserving Tokens

Yes (Pydantic & regex valid)

No (replaces with <LOC>, <PER>)

No (replaces with <EMAIL>)

No (replaces with [REDACTED])

Reversible Tool Boundaries

Yes (auto-hydrates at tool)

No (one-way document masking)

Manual (requires custom glue)

No (one-way irreversible)

Model Context Protocol (MCP)

Yes (stdio JSON-RPC gateway)

No

No

No

SSE Stream Safe (No Tearing)

Yes (lookahead holdback buffer)

No

No

No

Zero-ML Core Footprint

Yes (~0 MB, pure Python)

No (trained local model weights)

No (~500MB spaCy / PyTorch)

Yes

At-Rest Database Encryption

AES-256-GCM + Blind Index

SQLite / Local File Plaintext

External DB Dependent

None

Fail-Closed Policy Controls

Yes (REDACT / RAISE / BLOCK)

No

No

No

Positioning Note: If you are anonymizing static PDF/Word legal contracts in Italian, use Rizzo PII. If you need an enterprise NLP server for bulk text extraction, use Microsoft Presidio. If you are running autonomous AI agents (LangGraph, CrewAI, Claude Desktop) that make downstream tool calls and cannot tolerate broken schemas or leaked credentials, use ShadowVault.


Framework Integrations

1. LangChain & LangGraph

from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from shadow_vault import ShadowVault, protect_tool, ShadowVaultChatWrapper

vault = ShadowVault()
session_id = "agent_session"

# Protect Tools: Inputs hydrated before execution, outputs dehydrated before returning
@tool
def lookup_db(card_number: str) -> dict:
    """Fetch record from database."""
    return {"card": card_number, "balance": 1500}

safe_tool = protect_tool(lookup_db, vault=vault, session_id=session_id)

# Protect ChatModel: Prompts dehydrated before cloud LLM, tool-call arguments kept synthetic
llm = ChatOpenAI(model="gpt-4o")
safe_llm = ShadowVaultChatWrapper(llm=llm, vault=vault, session_id=session_id)

2. Model Context Protocol (MCP) Stdio Gateway

Wrap any existing MCP server (Node.js, Python, Go, Rust) with a zero-code transparent privacy gateway:

# Sits between your Agent/Claude Desktop and downstream MCP servers over stdio:
shadow-vault mcp-proxy --session-id user_42 -- uvx mcp-server-sqlite --db /path/to/data.sqlite

Claude Desktop / Cursor Configuration (claude_desktop_config.json):

{
  "mcpServers": {
    "secure-sqlite": {
      "command": "shadow-vault",
      "args": [
        "mcp-proxy",
        "--session-id", "claude_session",
        "--fail-closed",
        "--",
        "uvx", "mcp-server-sqlite", "--db", "/path/to/database.db"
      ]
    }
  }
}

Or intercept programmatic JSON-RPC messages in Python:

from shadow_vault import ShadowVault, MCPVaultInterceptor

vault = ShadowVault()
interceptor = MCPVaultInterceptor(vault=vault)

# 1. Intercept incoming tool call from model (restores real PII before tool executes):
safe_request = interceptor.intercept_request(mcp_request, session_id="user_session")

# 2. Intercept outgoing tool response before it reaches LLM (re-dehydrates result):
safe_response = interceptor.intercept_response(mcp_response, session_id="user_session")

🔒 Enterprise Security: Envelope Encryption & Blind Indexing

Unlike naive caches that store raw sensitive values in plaintext SQLite, shadow-vault provides authenticated envelope encryption at rest and cryptographic blind indexing:

from shadow_vault import ShadowVault, VaultStore

# Enable AES-256-GCM / authenticated encryption at rest:
vault = ShadowVault(
    db_path="./vault.db",
    encryption_key="my-master-vault-encryption-key", # Or via SHADOW_VAULT_KEY env var
)
  • Zero Plaintext on Disk: All real_val entries written to SQLite are authenticated ciphertexts (enc:gcm:v1:... or enc:std:v1:...). Direct inspection of .db files reveals zero real PII.

  • HMAC-SHA256 Blind Indexing: Fast $O(1)$ database lookups without leaking plaintext or search patterns to anyone with read access to the database.

  • Tenant & Session Salting: Support for custom salts prevents cross-session rainbow table correlation.


🛡️ Context-Aware Tool Policies & Fail-Closed Protection

Different agent tools require different privacy boundaries. A Slack notification tool should never receive raw credit cards, while a Stripe tool needs card details but not Aadhaar or SSNs:

from shadow_vault import ShadowVault, ToolPolicy, FailClosedAction, vault_guard

vault = ShadowVault(fail_closed=True)

# 1. Restrict hydration by entity type:
stripe_policy = ToolPolicy(
    tool_name="stripe_charge",
    allowed_entities={"CREDIT_CARD", "EMAIL"},
    fail_closed=True,
    fail_action=FailClosedAction.RAISE,
)

# 2. Block hydration completely for untrusted tools:
slack_policy = ToolPolicy(
    tool_name="post_slack_alert",
    allow_hydration=False, # Receives format-preserving synthetic tokens only
)

@vault_guard(vault=vault, policy=slack_policy)
def post_slack_alert(message: str, card: str, session_id: str = "default"):
    # card is guaranteed to remain synthetic (e.g. 4000009995970590)
    ...

3. OpenAI-Compatible FastAPI Proxy Server

Deploy a drop-in proxy for any OpenAI SDK client:

import uvicorn
from shadow_vault import ShadowVault, create_proxy_app

vault = ShadowVault()
app = create_proxy_app(vault=vault, upstream_base_url="https://api.openai.com/v1")

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Point your client to http://localhost:8000/v1:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="your-api-key",
    default_headers={"X-Session-ID": "session_42"}
)

# Streaming SSE response with real-time token re-hydration:
stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Send bill to alice@example.com"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

4. Pluggable Presidio & NER Adapters (Person Names)

For workloads requiring Named Entity Recognition (NER) for Person names or custom NLP entities, install the optional Presidio integration without burdening the zero-dependency core:

pip install "shadow-vault[presidio]"

Plug the detector directly into your ShadowVault engine:

from shadow_vault import ShadowVault
from shadow_vault.integrations.presidio import PresidioDetector

vault = ShadowVault()
# Plug in Microsoft Presidio / spaCy analyzer:
vault.register_custom_detector(PresidioDetector())

# Dehydrates names with format-preserving synthetic representations:
prompt = vault.dehydrate("Schedule follow-up with Dr. Gregory House.", session_id="s1")
# Prompt: "Schedule follow-up with Anon_Gregory_House."

# Fully reversible at tool boundaries:
hydrated = vault.hydrate(prompt, session_id="s1")
# Restored: "Schedule follow-up with Dr. Gregory House."

Benchmark & Performance Profile (1,000 Iterations)

Measured on a realistic 2,000-token prompt containing 12 distinct PII entities, structured MCP tool-call dictionaries, and 500-chunk SSE streams using benchmarks/run_benchmarks.py:

Latency Profile

Workload / Operation

Input Payload Size

P50 Latency

P95 Latency

P99 Latency

Target Met

Dehydrate Prompt (12 Entities)

~2,000 tokens (4.6 KB)

2.876 ms

4.043 ms

4.531 ms

Sub-5ms

Hydrate MCP Tool Arguments

5 Synthetic PII Args

26.6 μs (0.0266 ms)

45.9 μs

73.4 μs

< 0.1 ms

StreamHydrator (Per Chunk)

500 Token Chunks

50.0 μs (0.0500 ms)

63.0 μs

72.3 μs

< 0.1 ms

Full 500-Chunk Stream Total

500 SSE Token Chunks

25.00 ms

31.49 ms

36.16 ms

Real-Time

Memory Overhead (tracemalloc)

Metric

Measured Footprint

Comparison vs. Heavy NLP (spaCy / Presidio)

Memory per Active Session

0.028 KB (28 bytes)

~12,500x lighter (~500 MB model load vs. 0.04 KB)

Peak Heap Overhead (500 Active Sessions)

28.56 KB

Zero GPU / Torch dependencies required

Storage Engine

SQLite In-Memory / WAL

Built-in TTL expiration prunes inactive sessions

Checksum Accuracy & False-Positive Rejection

Test Scenario

Sample Size

False-Positive Rejection Rate

Theoretical Guarantee

Random 16-Digit IDs (Order & Tracking Numbers)

10,000

90.03%

Modulo 10 Luhn algorithm rejects non-card numbers

Random 12-Digit IDs (Transaction References)

10,000

89.95%

Verhoeff dihedral group $D_5$ check rejects non-IDs

Single-Digit Substitution & Transposition Errors

Exhaustive

100.0%

100% mathematical error detection guarantee

To re-run the benchmark suite locally:

python benchmarks/run_benchmarks.py

🛡️ Security Assurance & Threat Model

ShadowVault maintains an explicit, audited threat model and security disclosure policy:

  • THREAT_MODEL.md: Trust boundaries, STRIDE attacker vectors, AEAD cryptographic specifications, blind indexing derivations, and explicit non-goals.

  • SECURITY.md: Vulnerability disclosure SLA, responsible reporting contacts, and supported release branches.

  • Adversarial Security Suite: Automated regression tests verifying cross-session isolation, SQL injection prevention, high-concurrency race condition handling, and bit-flipping ciphertext rejection.

  • Reproducible Verification CLI: Run shadow-vault verify to independently execute 6 automated security checks covering AEAD roundtrips, blind index entropy, checksum integrity, and fail-closed leak blocking.

Known Boundaries & Honest Limitations

  1. Named Entity Recognition (Person Names): Free-text unstructured names (e.g. "Dr. Gregory House") require the optional Presidio/spaCy NER adapter (pip install "shadow-vault[presidio]"). The core engine focuses on deterministic identifiers.

  2. Structural Preservation: Format-preserving tokens intentionally maintain length and type (e.g. 16-digit cards). While the value is synthetic, an observer can deduce the field type.

  3. In-Process Keys: Process memory dumps are out-of-scope for application libraries. Enforce OS-level container isolation and set persistent vault keys via SHADOW_VAULT_KEY.


Running Tests

pytest -v
# 82 passed in 3.26s (100% pass rate)

Contributing

Contributions are welcome! Read CONTRIBUTING.md to see how you can add a new regional PII detector in under 20 lines of code.


License

Distributed under the MIT License. See LICENSE for details.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP agents to safely query multi-tenant data with structural tenant isolation, ensuring every tool call is scoped to a verified credential and outputs are redacted of internal identifiers and PII-like fields.
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Proxy that wraps any MCP server and masks PII in outbound tool-call arguments before they reach the backend tool, restoring the originals in the results. Covers generic PII plus Indian identifiers (Aadhaar, PAN, GSTIN, UPI, IFSC, ABHA) that most detectors miss.
    2
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to safely connect to MCP servers by sanitizing sensitive data in tool results and restoring it in tool arguments, so the model never sees PII while downstream tools still receive real values.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables data-loss prevention for Model Context Protocol traffic by inspecting tool calls in both directions, redacting sensitive values with stable placeholders, and providing audit logging, manual scanning, and data source connectors.
    1 npm
    MIT