Secure LLM Data with FF3 Encryption
FPE Demo MCP Server demonstrates FF3 format-preserving encryption and MCP authentication with fpe_encrypt and fpe_decrypt tools.
Why it matters
Protect sensitive data within LLM workflows using FF3 format-preserving encryption. This asset provides a configurable MCP server for secure data handling and authentication.
Outcomes
What it gets done
Implement FF3 FPE for digit encryption.
Configure authentication via shared secret or JWT.
Support stdio and HTTP transports for data access.
Encrypt and decrypt sensitive data with a visible prefix.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-fpe-demo-mcp | bash Capabilities
Tools your agent gets
Encrypts a string of digits using FF3 format-preserving encryption and returns result with ENC_FPE: prefix
Decrypts previously encrypted data with ENC_FPE: prefix using FF3 format-preserving encryption
Overview
FPE Demo MCP Server
FPE Demo MCP Server is a reference implementation showing FF3 format-preserving encryption and MCP authentication modes together, via fpe_encrypt and fpe_decrypt tools. Use it to learn or prototype FPE-backed MCP authentication, not as a hardened production encryption service.
What it does
FPE Demo MCP Server is a lightweight MCP server that demonstrates authentication and FF3 format-preserving encryption (FPE) over digits, in a clean, readable implementation. It shows how FF3 FPE and MCP authentication work together: MCP is a JSON-RPC protocol that lets LLMs securely call external tools and services, and this server pairs that with FF3 FPE so a digit string, such as a social security number, can be encrypted into a same-format digit string, tagged with an ENC_FPE: prefix so encrypted values are obvious in logs and demos.
When to use - and when NOT to
Use it to learn or prototype how format-preserving encryption and MCP authentication fit together, or as a reference implementation when building your own FPE-backed MCP server. It supports four auth modes - authless for quick tests, debug, test (shared secret or JWT), and production (JWT only) - and both stdio and HTTP Streamable transports, so it works equally for local LLM clients like Claude Desktop or Claude Code and for web-based testing. The project explicitly frames itself as a demo implementation for learning and prototyping, not a hardened production encryption service, so treat it accordingly.
Capabilities
- fpe_encrypt: encrypts a digit-domain string and returns it prefixed as ENC_FPE:...
- fpe_decrypt: decrypts a prior ENC_FPE:... payload back to its original digit string
- FF3 FPE over digits (radix-10)
- Four authentication modes: authless, debug, test with a shared secret or JWT, and production with JWT only
- Both stdio for local MCP clients and HTTP transports, the latter using the MCP Streamable HTTP protocol
- One-click deploy to DigitalOcean App Platform for a public HTTPS URL, useful for testing with web-based LLM connectors like ChatGPT or Claude web connectors
How to install
For local stdio use with an LLM client such as Claude Desktop or Claude Code:
npm install
npm run build
npm start
For HTTP testing, serving at http://127.0.0.1:8765/mcp:
npm run start:http
To deploy publicly, use the one-click Deploy to DigitalOcean App Platform button, which stands up the server with HTTPS. Since App Platform terminates HTTPS and your app runs plain HTTP behind it, set HOST=0.0.0.0 and let DigitalOcean inject PORT. Choose an auth mode via the AUTH_MODE environment variable: authless for quick tests, test with an Authorization: Bearer AUTH_TOKEN header, or production with a Bearer JWT.
Who it's for
Developers learning or prototyping format-preserving encryption inside an MCP server, or looking for a readable reference implementation of MCP authentication modes, authless, shared-secret, and JWT, before building their own. It is released under the Business Source License 1.1 (BUSL-1.1) License.
Source README
FPE Demo MCP - FF3 Format Preserving Encryption Server
FPE Demo MCP is a lightweight MCP (Model Context Protocol) server that demonstrates authentication and format‑preserving encryption (FF3 FPE) in a clean, readable implementation. MCP is a JSON-RPC protocol that enables LLMs to securely call external tools and services.
- ✅ FF3 FPE over digits (radix‑10)
- 🔐 Auth modes:
authless,debug,test(shared secret or JWT),production(JWT only) - 🏷️
ENC_FPE:prefix so encrypted values are obvious in logs/demos - 🌐 Both stdio (local) and HTTP (web) transports
Demo Implementation: This shows how FF3 FPE + MCP authentication work together. Great for learning, prototyping, and understanding the concepts.
🚀 Quick Deploy
What this does: Deploys the MCP server to DigitalOcean App Platform with HTTPS, giving you a public URL for testing with web-based LLMs like ChatGPT or Claude web connectors.
Remote MCP URL: https://<your-app>.ondigitalocean.app/mcp
Auth modes:
AUTH_MODE=authlessfor quick testsAUTH_MODE=test+ headerAuthorization: Bearer <AUTH_TOKEN>AUTH_MODE=production+ Bearer JWT
Note: App Platform terminates HTTPS; your app runs plain HTTP. Set
HOST=0.0.0.0and DO injectsPORT.
Local Testing
MCP stdio (for LLM clients)
npm install
npm run build
# Start MCP server (stdio transport)
npm start
# or: AUTH_MODE=debug npm start
Perfect for: Claude Desktop, Claude Code, any local MCP-compatible tool.
HTTP server (for web testing)
# Basic HTTP server (no CORS)
npm run start:http
# With CORS for browser playground testing
CORS_ORIGIN=https://playground.ai.cloudflare.com npm run start:http
Server runs at http://127.0.0.1:8765/mcp using MCP Streamable HTTP protocol.
Both servers expose the same two tools:
fpe_encrypt- encrypts a digit-domain string and returnsENC_FPE:...fpe_decrypt- decrypts a priorENC_FPE:...payload
Try it (copy‑paste examples)
MCP stdio testing
Encrypt
echo '{
"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"fpe_encrypt","arguments":{"value":"123-45-6789"}}
}' | node dist/src/stdio-server.js
Decrypt
echo '{
"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"fpe_decrypt","arguments":{"value":"ENC_FPE:096616337"}}
}' | node dist/src/stdio-server.js
HTTP MCP testing
Initialize connection
curl -i http://127.0.0.1:8765/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
List tools (use MCP-Session-ID from previous response)
curl -s http://127.0.0.1:8765/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Session-ID: <session-id>' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
Encrypt
curl -s http://127.0.0.1:8765/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Session-ID: <session-id>' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"fpe_encrypt","arguments":{"value":"123-45-6789"}}}'
Both servers normalize input to digits for radix‑10 before encryption.
Auth & Config
AUTH_MODE:authless(default) |debug|test|production- Shared secret (test mode):
AUTH_TOKEN="demo-secret"→ pass as{"user_token":"demo-secret"} - JWT (test/production): Pass as
{"user_token":"Bearer <jwt>"}orAuthorizationheader- JWT Secret: Uses
demo-secretby default, or setAUTH_JWT_SECRETfor different signing key - JWT Algorithm: HS256 (symmetric key)
- Optional Claims: Set
AUTH_JWT_ISSfor issuer validation,AUTH_JWT_AUDfor audience validation
- JWT Secret: Uses
FPE Configuration (defaults provided):
export FPE_KEY=00112233445566778899aabbccddeeff # 32-char hex key
export FPE_TWEAK=abcdef12345678 # 14-char hex tweak
How it works (short version)
- MCP server: exposes
fpe_encrypt/fpe_decrypttools via stdio JSON-RPC. - Auth:
authless/debug→ skiptest→ shared secret or JWT (HS256)production→ JWT only (for testing stricter auth)
- FPE (FF3):
- Radix-10 cipher (digits only) using AES key + tweak.
- Input normalized to digits (e.g., SSN
123-45-6789→123456789) before encryption. - Ciphertext returned as
ENC_FPE:<digits>to be visually obvious in the demo.
Beyond this demo
This demo shows the core concepts. For real-world usage, you'd need:
- Key Management: KMS integration (AWS KMS, GCP KMS, HashiCorp Vault)
- Per-record tweaks: Unique tweaks per user/record to prevent pattern analysis
- Audit trails: Comprehensive logging for compliance (PCI, SOX, GDPR)
- Input validation: Schema enforcement and rate limiting
- Metadata tracking: Database fields to track encryption state, not string prefixes
- Infrastructure: Load balancing, monitoring, backup/recovery
- Compliance: Security reviews, penetration testing, certifications
FAQ
Why the ENC_ prefix?
It's a teaching aid - newcomers can see that a value is encrypted. In real systems, you'd likely omit it.
Why only digits?
FF3 operates over a radix. We start with radix-10 because it’s the clearest demo (SSNs, phones). You can extend to radix-36 (0-9a-z) if your library/config supports it.
Can I switch to RS256 JWT?
Yes - load a PEM public key and set the algorithm to RS256. The verification call stays the same.
Browser vs Remote Usage
For browser playground testing (like Cloudflare AI Playground), use the HTTP server with CORS:
CORS_ORIGIN=https://playground.ai.cloudflare.com npm run start:http
For remote server-to-server usage (ChatGPT, Claude via API, or production integrations), CORS is not needed:
npm run start:http
The MCP HTTP transport works with both browser-based and server-to-server clients. Browser clients require CORS headers, while server-to-server clients (like ChatGPT Actions or Claude's server integrations) don't need CORS.
For production deployment with web-based LLMs, see our Deployment Guide which covers DigitalOcean App Platform and other hosting options.
Docs
- Deployment Guide → docs/DEPLOYMENT.md
- Using with Claude/ChatGPT/others → docs/USAGE-LLMS.md
- Architecture → docs/ARCHITECTURE.md
- JSON Schemas → docs/SCHEMAS.md
- FF3 limitations → docs/LIMITATIONS.md
BSL 1.1 - see LICENSE.md.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.