SecureMCP
by mj10612
README.md
<div align="center">
# ๐ก๏ธ SecureMCP
**Local English/Korean Masking ยท Subscription Gateway ยท Trusted Restoration**
*์์ดยทํ๊ตญ์ดยท์ฝ๋๋ฅผ ๋ก์ปฌ์์ ๋ง์คํนํ๊ณ , ๋๊ตฌ ์คํ๊ณผ ์ฌ์ฉ์ ํ๋ฉด์์ ์๋ฌธ์ ๋ณต์ํ๋ ๊ฐ์ธ์ ๋ณด ๋ณดํธ ๋๊ตฌ*
[](pyproject.toml)
[](pyproject.toml)
[](.github/workflows/ci.yml)
[](https://github.com/mj10612/SecureMCP/actions/workflows/ci.yml)
[](docs/ARCHITECTURE.md)
[](LICENSE)
---
[English](#english-overview) ยท [ํ๊ตญ์ด ์๋ด](#ํ๊ตญ์ด-์๋ด-korean-overview) ยท [Supported Versions](#supported-versions) ยท [Quick Start](#quick-start) ยท [Features](#features) ยท [Architecture](#system-architecture) ยท [Documentation](#documentation)
---
</div>
## English Overview
**SecureMCP** masks English/Korean text and code locally, with session-based restoration.
Version 0.5 adds an experimental **local subscription gateway** for Claude Code and Codex.
Run `secure-mcp gateway install` once, then use `claude` / `codex` normally. Requests are
masked automatically; responses and local tool arguments are restored automatically. Existing
CLI subscription OAuth is forwarded to the original subscription service; API keys are refused.
No agent hooks are installed. See [subscription gateway](docs/GATEWAY.md) for setup,
automatic startup, tested versions and the exact protection boundary.
Legacy agent hooks remain optional utilities. They cover selected tool text rather than
complete requests; [local integration](docs/LOCAL_INTEGRATION.md) documents their limits.
Mask confidential input **before** sending it to a provider. Restore responses in your trusted
local application and show them to the user there. Model-invoked MCP tool arguments are already
visible to the provider; adding this server to Claude Desktop or Cursor does not automatically
intercept or protect prompts. Restored originals must not be sent back into the model context.
This is heuristic masking, not a proof of anonymity, cryptographic zero knowledge, or regulatory compliance.
---
## Supported Versions
| Component | Supported versions / scope |
| :--- | :--- |
| SecureMCP | **0.5.0** |
| Python | **3.10 ยท 3.11 ยท 3.12 ยท 3.13 ยท 3.14** in CI; package requires Python โฅ 3.10 |
| Operating systems | **Windows ยท macOS ยท Linux** in CI |
| Claude Code gateway | **2.1.287** native fixtures verified; live subscription HTTP 200 verified, model refusal remains |
| Codex gateway | **CLI 0.160.0** native fixture tests and a live ChatGPT subscription request with automatic restoration verified |
| MCP transport | Local **stdio**; CLI HTTP/SSE transports are disabled |
| Natural languages | **English ยท ํ๊ตญ์ด ยท mixed input** |
| Code languages | Python ยท JavaScript ยท TypeScript ยท Go ยท Rust ยท Java ยท C ยท C++ ยท SQL |
The [CI matrix](.github/workflows/ci.yml) covers 15 Python/OS combinations. Code-language
support describes lexer modes, not compatibility with every language release or compiler.
The gateway is experimental. Native fixture tests verify routing/masking/restoration.
Codex passed a live subscription smoke test. Claude's attribution masking bug is fixed;
live requests now return HTTP 200, but a Sonnet safety-filter refusal prevents successful
answer/restoration verification. The earlier 429 was not subscription exhaustion.
This does not certify all-traffic privacy.
---
## Quick Start
### Automatic subscription integration
```bash
uv tool install .
secure-mcp gateway install
secure-mcp gateway status
```
Restart Claude Code/Codex and use their normal commands. Setup preserves login caches and
registers a hidden user-login startup task. It changes user-wide provider settings; no agent
hooks are added. Subscription limits still apply. This is text/code inference protection;
images, remote attachments and unsupported payloads are blocked. See [gateway guide](docs/GATEWAY.md).
### Legacy optional agent hooks
```bash
uv tool install .
secure-mcp init --agent claude
secure-mcp doctor
```
Restart Claude Code after installation. Hooks default to the current project; use `--global`
for user-wide registration. See [local integration](docs/LOCAL_INTEGRATION.md) for supported
tool fields, installation/removal and limitations.
For Codex:
```bash
secure-mcp init --agent codex
secure-mcp doctor --agent codex
```
Restart Codex and review/trust the installed definitions in `/hooks`. Project hooks require a
trusted project. Codex masks tool results and restores `Bash`/`apply_patch` inputs; automatic
screen restoration is unavailable. Use `secure-mcp restore --agent codex --session-id <id>`
with masked text on UTF-8 stdin for local display. See [Codex integration](docs/LOCAL_INTEGRATION.md#codex).
### Development installation and demo
```bash
uv venv
uv pip install -e ".[dev]"
uv run python -m secure_mcp demo
```
### Trusted local Python API
```python
from secure_mcp import LocalPrivacyClient
# Replace echo with your provider adapter. Only its argument may leave the host.
def provider(masked_payload: str) -> str:
return masked_payload
with LocalPrivacyClient() as client:
result = client.request(
"Patient John Doe received 50mg.", provider,
sensitive_terms={"John Doe"},
)
print(result.unmasked_text) # Local display only
```
---
## Features
| Feature | Behavior |
| :--- | :--- |
| ๐ English & Korean | Per-word multilingual handling, conservative Korean particle separation and explicit sensitive terms |
| ๐งฉ Code-aware masking | Language-specific lexer modes for identifiers, literals, numbers and comments |
| ๐ญ Four surrogate strategies | Bracket, Unicode, delimited pseudoword and random hash representations |
| ๐ Subscription gateway | Automatic request masking, shared prompt/code aliases, local tool-argument restoration and automatic answer display; existing OAuth, no API-key fallback |
| ๐ Local agent hooks | Claude Code and Codex tool-text masking and local execution-argument restoration; Claude Code also supports display-only restoration |
| ๐ Session management | Stable per-session mappings, operation locks, idle expiry and opt-in encrypted snapshots |
| ๐ ๏ธ CLI & Python API | Local masking/restoration, hook diagnostics, statistics and a buffered command wrapper |
### Masking policies
| Mode | Behavior |
| --- | --- |
| `content_words` | Mask content words and detected sensitive spans; keep functional grammar. |
| `entities_only` | Mask recognized PII, URLs, secrets, code spans, numbers and capitalized names. Korean and other case-free/non-ASCII words are masked conservatively, including ordinary nouns. |
| `aggressive` | Keep a small structural subset of articles/prepositions/conjunctions; mask auxiliaries, adverbs, pronouns and other words. |
| `code_aware` | Mask identifiers, numbers, literals and comments using the selected language lexer. |
English, Korean and mixed input are handled per word. Unicode names remain atomic. Korean
particle splitting uses known stems and conservative rules; unknown ambiguous words stay whole.
It is not a full morphological analyzer or universal person-name detector. Supply `sensitive_terms`
for domain names, lowercase names, ambiguous names, and custom secrets. `custom_preserve` / CLI
`--preserve` deliberately exempts selected words; recognized sensitive spans still take precedence.
Unknown secret formats and context-dependent names may evade `entities_only`; inspect the payload
or use broader masking. A high masking ratio does not prove absence of sensitive data.
### Surrogate strategies
| Strategy | Representation |
| :--- | :--- |
| `bracket` | `[ENT_1]` |
| `unicode` | `โฆENT_1โง` |
| `pseudoword` | Explicitly delimited pronounceable words, e.g. `โชBrivelโฆโซ` |
| `hash` | Random 96-bit nonce, independent of the original |
Pseudowords use explicit delimiters
to avoid collisions with real words and adjacent tokens. Allocation is stable within a session;
random strategies intentionally differ between sessions. Keep all surrogate spelling intact.
Altered/unknown placeholder candidates are reported in `unmatched_surrogates`; `strict=True`
rejects them. Free-form deletion or invention by a model cannot always be detected or reconstructed.
### Korean restoration
Exact mask/unmask roundtrips keep written particles. For newly generated Korean responses,
opt into `normalize_particles=True` (CLI `--normalize-particles`) to choose ์ด/๊ฐ, ์/๋, ์/๋ฅผ,
๊ณผ/์ and ์ผ๋ก/๋ก from a restored Hangul stem. Pronunciation of foreign names is not guessed.
### Code-aware review representations
Code languages: `python`, `javascript`, `typescript`, `go`, `rust`, `java`, `c`, `cpp`, `sql`.
Use explicit `language` in `mask_code` (CLI `--code-language`) for ambiguous snippets.
Auto detection is best effort. Keywords are language-specific; builtins and shadowed builtin
names are masked. Unicode identifiers, SQL comments/doubled quotes, backticks, Python f-strings
and escaped newlines, C++/Rust raw strings and numeric suffixes/separators are covered by tests.
Code allocations use ASCII names (`smcp_ID_n` and `smcp_LIT_n` inside literals)
and random native integer constants for numbers (reserved `732846` prefix plus 12 digits),
independently of the text strategy, so byte literals remain valid too. Python output
is syntax-checked in tests. Output is an opaque review representation: it need not execute,
type-check, retain numeric types/values, or preserve f-string/template interpolation behavior. This
small lexer is not a complete parser for every version of every supported language.
---
## System Architecture
```mermaid
flowchart LR
Input[Trusted local input] --> Mask[Masking engine]
Mask -->|Masked payload| Provider[AI provider callback]
Provider -->|Surrogate response| Restore[Local restoration]
Restore --> Display[User display]
Vault[Local session mappings] --- Mask
Vault --- Restore
```
The subscription gateway masks configured inference requests before forwarding them and
restores responses before the CLI consumes them. The callback path masks its provider argument.
Legacy agent hooks use a separate,
partial tool-text path; they do not intercept all outgoing context. See the
[architecture](docs/ARCHITECTURE.md) and [local integration](docs/LOCAL_INTEGRATION.md) documents.
---
## CLI and Sessions
```bash
python -m secure_mcp mask "Alice from Google" --session-id example --session-file example.enc --json-output
python -m secure_mcp unmask "[ENT_1] from [ENT_2]" --session-id example --session-file example.enc --strict
python -m secure_mcp mask "john doe" --mode entities_only --sensitive-term "john doe"
```
Use the same hidden password, or `SECURE_MCP_SESSION_PASSWORD`. CLI files use authenticated
Fernet encryption, random salt, PBKDF2-HMAC-SHA256 with 600,000 iterations, atomic writes and a
lock over the complete CLI read/modify/write operation. A concurrent writer fails clearly.
A crash may leave `example.enc.lock`; remove it only after confirming no writer is running.
Files are opt-in; without `--session-file`, mappings only survive in the current process.
Payload schema v2 stores allocations/counters without regenerating mappings. Legacy v1 files
remain readable; unknown schema versions fail explicitly. Delete session files after use.
Legacy bare pseudoword allocations retain their old ambiguity; start a new session to use
the safe delimited representation for every allocation.
Session strategies are immutable; `mode` records the last-used policy. Creating a duplicate ID
fails without changing its TTL or mappings. TTL must be positive and at most one day. The vault
sweeps idle expired sessions at most one cleanup interval later (default one second), and checks
expiration on access. Clear waits for active operations and invalidates retained references.
Library users must use `session.operation()` for custom mutations; built-in engine operations
use the same lock. `vault.close()` stops cleanup and releases all mapping references. Python
cannot promise byte-level memory zeroization. Standalone `PrivacySession` owners manage lifetime
themselves; use `SessionVault` for scheduled expiry.
`masked_ratio` counts masked token occurrences divided by non-whitespace/non-punctuation
occurrences. Deprecated `privacy_entropy_score` is an alias, not information entropy.
`restored_occurrences` counts replacements; `restored_unique_tokens` counts distinct allocations.
`restored_tokens_count` remains a compatibility alias for replacement occurrences.
---
## MCP Tools Reference
`python -m secure_mcp serve` supports local stdio only. HTTP/SSE transports are disabled in the CLI;
directly exposing the Python server over a network requires host-provided authentication and isolation.
| MCP tool | Purpose |
| :--- | :--- |
| `mask_text` | Mask text with a selected policy and session |
| `mask_code` | Create a code review representation using a selected language lexer |
| `create_privacy_session` | Create an isolated mapping session |
| `get_session_stats` | Return counters without original values or mapping entries |
| `clear_privacy_session` | Release the session's mapping references |
Local Python `unmask_text` / `unmask_code` and CLI `unmask` are **not registered as MCP tools**,
so a model cannot enumerate mappings via restoration. Resources: `privacy://policies`, `privacy://status`.
Example desktop configurations are utility setups, not privacy proxies.
### Migration from 0.1
Version 0.2 changes pseudoword delimiters, code identifier/number representations, mapping keys
(`mapping_key(original, token_type, code=...)`), sentence-initial entity classification, keyword
preservation, and the MCP restoration boundary. Direct store readers should use mapping values
or `mapping_key`. Validate explicitly requested strategies; omitted strategies follow the generator.
---
## ํ๊ตญ์ด ์๋ด (Korean Overview)
0.5์์๋ **Claude CodeยทCodex์ ๊ธฐ์กด ๊ตฌ๋
๋ก๊ทธ์ธ์ ์ ์งํ๋ ๋ก์ปฌ ๊ฒ์ดํธ์จ์ด**๋ฅผ ์ ๊ณตํฉ๋๋ค.
`uv tool install .` ์ค์น ํ `secure-mcp gateway install`์ **ํ ๋ฒ** ์คํํ๊ณ ๋ CLI๋ฅผ ์ฌ์์ํ์ธ์.
๊ทธ ๋ค์๋ ํ์์ฒ๋ผ `claude` / `codex`๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค. ์ง์ ์
๋ ฅยทํ
์คํธ ์ฝ๋ยท๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์๋์ผ๋ก
๋ง์คํนํ๊ณ , ๋ต๋ณ๊ณผ ๋ก์ปฌ ์คํ ์ธ์๋ ์๋ ๋ณต์ํฉ๋๋ค. ํจ์๋ช
ยท๋ณ์๋ช
ยท๋ฌธ์์ดยท์ซ์ยท์ฃผ์์ ๋ณด์กดํ๋
์์ธ๋ ์ถ๊ฐํ์ง ์์์ต๋๋ค. ์
๋ ฅ์์ ์ง์นญํ ํจ์์ ์ฝ๋์ ํจ์๋ ๊ฐ์ ์นํํ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ธฐ์กด ๋ก๊ทธ์ธ ํ์ผ์ ์ฝ๊ฑฐ๋ ๋ณต์ฌํ์ง ์์ต๋๋ค. CLI๊ฐ ๊ด๋ฆฌํ๋ OAuth ํค๋์ ๊ฐฑ์ ํ๋ฆ์ ์ฌ์ฉํ๊ณ ,
API ํค ์์ฒญ์ ๊ฑฐ๋ถํ๋ฏ๋ก ์ ๋ฃ API๋ก ์๋ ์ ํํ์ง ์์ต๋๋ค. ์ Hook์ ๋ฑ๋กํ์ง ์์ผ๋ฉฐ,
์ด์์ฒด์ ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์๋ ์์ํ๋๋ก ์ค์ ํฉ๋๋ค. ๊ธฐ์กด Hook ๋ฐฉ์์ ์ ํ ๊ธฐ๋ฅ์ผ๋ก
๋จ๊ฒจ ๋์์ต๋๋ค. [์ค์นยทํด์ ๋ฐ ๋ณดํธ ๋ฒ์](docs/GATEWAY.md)๋ฅผ ํ์ธํ์ธ์.
Claude Code 2.1.287ยทCodex 0.160.0์ ์ค์ CLI๋ฅผ ๋ชจ์ OAuth/๋ก์ปฌ ์๋ฒ๋ก ๊ฒ์ฆํ์ต๋๋ค.
Codex๋ ์ค์ ๊ตฌ๋
์์ฒญยท์๋ ๋ณต์๊น์ง ํ์ธํ์ต๋๋ค. Claude๋ ์๋ณ ๋ธ๋ก ์ฒ๋ฆฌ ์ค๋ฅ๋ฅผ ์์ ํด ์ค์ ๊ตฌ๋
HTTP 200์ ํ์ธํ์ง๋ง, Sonnet ์์ ํํฐ ๊ฑฐ์ ๋ก ์ ์ ๋ต๋ณยท๋ณต์ ๊ฒ์ฆ์ด ๋จ์์ต๋๋ค. ๊ธฐ์กด 429๋ ๊ตฌ๋
ํ๋ ์์ง์ด ์๋์์ต๋๋ค. ์ด๋ฏธ์งยท์๊ฒฉ ์ฒจ๋ถยท๋ฏธ์ง์ ์์ฒญ์ ์ฐจ๋จํ๊ณ ,
๊ฒ์ดํธ์จ์ด ๋ฐ์ ๋๊ตฌ ๋คํธ์ํฌยทํ
๋ ๋ฉํธ๋ฆฌ๊น์ง ๋ณดํธํ๋ค๊ณ ์ฃผ์ฅํ์ง ์์ต๋๋ค.
SecureMCP๋ ์์ดยทํ๊ตญ์ดยทํผํฉ ๋ฌธ์ฅ์ ๋ก์ปฌ์์ ๋ง์คํนํ๊ณ ๋ณต์ํฉ๋๋ค. ํด๋ผ์ฐ๋์ ์์ฒญํ๊ธฐ
**์ ์** `LocalPrivacyClient` ๋๋ ๋ก์ปฌ API/CLI๋ก ์๋ฌธ์ ๊ฐ๋ฆฌ๊ณ , ์๋ต์ ๋ก์ปฌ์์๋ง ๋ณต์ํ์ธ์.
๋ชจ๋ธ์ด ํธ์ถํ๋ MCP ๋๊ตฌ์ ์ธ์๋ ์ด๋ฏธ ์ ๊ณต์์๊ฒ ์ ๋ฌ๋์ด ์์ผ๋ฏ๋ก, Claude Desktop/Cursor์
์๋ฒ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋ง์ผ๋ก ๊ฐ์ธ์ ๋ณด๊ฐ ๋ณดํธ๋์ง๋ ์์ต๋๋ค. ๋ณต์ํ ์๋ฌธ์ ๋ชจ๋ธ ์ปจํ
์คํธ์ ๋ค์
๋ฃ์ผ๋ฉด ์ ๋ฉ๋๋ค. MCP ๋ณต์ ๋๊ตฌ๋ ์ ๊ฑฐํ์ผ๋ฉฐ, ๊ธฐ๋ณธ CLI ์๋ฒ๋ ๋ก์ปฌ stdio๋ง ์ง์ํฉ๋๋ค.
์์ด ๋๋ฌธ์ ์ด๋ฆ๊ณผ Unicode ์ด๋ฆ์ ํ๋์ ํ ํฐ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ํ๊ตญ์ด ์ด๋ฆ๊ณผ ์ผ๋ฐ ๋ช
์ฌ๊ฐ
๊ตฌ๋ถ๋์ง ์๋ `entities_only`์์๋ ๋น๊ธฐ๋ฅ์ด๋ฅผ ๋ณด์์ ์ผ๋ก ๊ฐ๋ฆฝ๋๋ค. ์กฐ์ฌ ๋ถ๋ฆฌ๋ ์๋ ค์ง ์ด๊ฐ๊ณผ
๋ณด์์ ์ธ ๊ท์น์ ์ฌ์ฉํ๋ฉฐ, ๋ชจํธํ ๋ฏธ๋ฑ๋ก ๋จ์ด๋ ํต์งธ๋ก ๊ฐ๋ฆฝ๋๋ค. ๋ชจ๋ ๊ณ ์ ๋ช
์ฌยท๋น๋ฐ๊ฐ ๋๋
ํ๊ตญ์ด ํํ์๋ฅผ ์๋ฒฝํ ์ธ์ํ๋ ๋๊ตฌ๋ ์๋๋๋ค. `sensitive_terms` / `--sensitive-term`์ผ๋ก
ํน์ ์ฉ์ด๋ฅผ ์ง์ ํ๊ณ , ์ ์ ์๋ ๋ฏผ๊ฐ์ ๋ณด์๋ ๋ ๋์ ๋ง์คํน ์ ์ฑ
์ ์ฌ์ฉํ์ธ์.
์ ํํ ์๋ณต ๋ณต์์์๋ ์
๋ ฅ ์กฐ์ฌ๋ฅผ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ๋ชจ๋ธ์ด ์๋ก ๋ง๋ ๋ฌธ์ฅ์๋
`normalize_particles=True` / `--normalize-particles`๋ฅผ ์ ํํ์ฌ ๋ฐ์นจ์ ๋ง๋ ์กฐ์ฌ๋ฅผ ๋ณด์ ํ ์
์์ต๋๋ค. ์์ด ์ด๋ฆยท์ฝ์ด์ ๋ฐ์์ ์ถ์ธกํ์ง ์์ต๋๋ค. `--strict`๋ ํ์งํ ๋ณํยท๋ฏธ๋ฑ๋ก
ํ๋ ์ด์คํ๋์ ๋ณต์์ ๊ฑฐ๋ถํ์ง๋ง, ๋ชจ๋ธ์ด ์์ ํ ์ญ์ ํ ๋ด์ฉ์ ์ฌ๊ตฌ์ฑํ์ง๋ ๋ชปํฉ๋๋ค.
์ธ์
์ ๋ต์ ์์ฑ ํ ๊ณ ์ ๋๋ฉฐ, ์ค๋ณต ID ์์ฑ์ ์ค๋ฅ์
๋๋ค. ๋ง๋ฃ ์ธ์
์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ ๋ฆฌํ๊ณ ,
์ญ์ ์ ์งํ ์ค ์์
์ ์ ๊ธ์ผ๋ก ์กฐ์จํฉ๋๋ค. ๋ณ๋ CLI ํ๋ก์ธ์ค ๊ฐ ๋ณต์์๋ ๋์ผํ ์ํธํ
`--session-file`์ด ํ์ํฉ๋๋ค. ๋ง์คํน ๋น์จ์ ํต๊ณ์ด๋ฉฐ ๊ธฐ๋ฐ์ฑยท์ต๋ช
์ฑยท๊ท์ ์ค์์ ์ฆ๋ช
์ด ์๋๋๋ค.
---
## Development
```bash
python -m ruff check src tests examples
python -m mypy src
python -m pytest -W error --cov=secure_mcp --cov-report=term-missing --cov-fail-under=85
```
---
## Documentation
- [Subscription Gateway / ๊ตฌ๋
๋ก๊ทธ์ธ ์๋ ์ฐ๋](docs/GATEWAY.md)
- [Legacy Local Claude Code & Codex Integration / ๊ธฐ์กด Hook ์๋ด](docs/LOCAL_INTEGRATION.md)
- [System Architecture](docs/ARCHITECTURE.md)
- [Issue Resolution and Review Notes](docs/ISSUE_RESOLUTION.md)
- [Contributing Guidelines](CONTRIBUTING.md)
## License
Licensed under **Apache License 2.0**. See [LICENSE](LICENSE) for details.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessResponsive