MCP server and CLI/TUI utility for safe code obfuscation before sending code to an LLM, and safe reverse-application of model output back to your project.
This repository ships a single installer entrypoint: ./install.
It supports installing from source, from a local binary, from a local release archive, or by downloading a versioned
release bundle.
Supported modes:
./install --from-source- build from the current checkout and install./install --binary ./target/release/code-obfuscator- install from a local binary./install --archive ./dist/code-obfuscator-linux-x64.tar.gz --version 0.5.0- install from a local release archive./install --version 0.5.0- download and install a specific release (when release source is configured)
Default installer-managed paths:
- install home:
~/.code-obfuscator - user-local bin (Linux/macOS):
~/.local/bin/code-obfuscator - user-local bin (Windows):
%LOCALAPPDATA%\Programs\code-obfuscator\bin\code-obfuscator.exe
macOS / Linux:
make build
make install
# or
./install --from-source
# or
bash scripts/install.sh --from-sourceWindows PowerShell:
./scripts/install.ps1 -FromSourcecargo build --release --bin code-obfuscator
./install --binary ./target/release/code-obfuscatorMain one-liner:
curl -fsSL https://raw.githubusercontent.com/sawrus/code-obfuscator/main/install | bashInstall a specific version:
curl -fsSL https://raw.githubusercontent.com/sawrus/code-obfuscator/main/install | bash -s -- --version 0.5.0Release binaries source:
make release-artifacts packages release binaries into archive names expected by the installer:
code-obfuscator-linux-x64.tar.gzcode-obfuscator-linux-arm64.tar.gzcode-obfuscator-darwin-x64.tar.gzcode-obfuscator-darwin-arm64.tar.gzcode-obfuscator-windows-x64.zip
Installer download source options:
CODE_OBFUSCATOR_INSTALL_REPO=owner/repofor GitHub ReleasesCODE_OBFUSCATOR_INSTALL_BASE_URL=https://host/pathfor a custom release mirror
Examples:
CODE_OBFUSCATOR_INSTALL_REPO=owner/code-obfuscator ./install --version 0.5.0
CODE_OBFUSCATOR_INSTALL_BASE_URL=https://example.com/code-obfuscator/releases ./install --version 0.5.0By default, the installer attempts to add the user-local bin directory to your shell PATH.
Disable that behavior with --no-modify-path.
flowchart LR
user["User"] --> ide["Agent IDE<br/>e.g. Codex"]
ide --> llm["LLM"]
ide --> mcp["MCP server<br/>code-obfuscator"]
mcp --> project["Project files on disk"]
mcp -. "obfuscated_files / workspace delta" .- llm
sequenceDiagram
actor User
participant IDE as Agent IDE (Codex)
participant MCP as MCP server
participant LLM
participant Project as Project / root_dir
User->>IDE: Request a code change
IDE->>MCP: ls_tree / ls_files / clone(..., options.request_id)
MCP->>Project: Read source files
Project-->>MCP: Source files
MCP-->>IDE: obfuscated_files
IDE->>LLM: Send obfuscated_files only
LLM-->>IDE: Return modified obfuscated_files
IDE->>MCP: status(workspace_dir, options.request_id)
IDE->>MCP: push(workspace_dir, options.request_id)
MCP->>MCP: Deobfuscate and apply workspace delta
MCP->>Project: Apply add/modify/delete in source root
MCP-->>IDE: applied_files / deleted_files
IDE-->>User: Show result
The IDE is the orchestrator: it calls MCP tools, keeps one request_id across clone/status/push, and applies workspace
delta through push.
- Input:
root_dir,max_depth?,max_entries?,include_hidden? - Output:
entries[{path,kind}],truncated
- Input:
root_dir,max_entries?,include_hidden? - Output:
files[],truncated
- Input:
root_dir,file_paths?,options?withrequest_id - Output:
obfuscated_files,stats,events
- Input:
root_dir,workspace_dir,options?withrequest_id - Output:
cloned_files,stats,events
- Input:
workspace_dir,options?withrequest_id - Output:
clean,diff{added,modified,deleted},mapping_state
- Input:
workspace_dir,options?withrequest_id - Output:
applied_files,deleted_files,stats,events
GET /healthGET /mappingPUT /mappingPOST /(MCP JSON-RPC)POST /mcp(MCP JSON-RPC alias)
MCP_DEFAULT_MAPPING_PATHMCP_HTTP_ADDRMCP_LOG_DIRMCP_LOG_MAX_BYTESMCP_LOG_MAX_FILESMCP_LOG_STDOUTMCP_LOG_MODE
MCP_LOG_MODE values:
deep- log all request/response bodies with full payloadsdefault- log request/response bodies in readablekey: valueform with file contents redactedsystem- log only lifecycle, health, warning, and error events
Console sinks are transport-aware:
stdiologs go tostderrso MCP protocol output remains clean onstdouthttplogs go tostdoutso they are visible in Docker container logs- file logs always use the same readable multi-line format in
MCP_LOG_DIR
Batch mode remains available via explicit flags:
code-obfuscator \
--mode forward \
--source ./project-src \
--target ./project-obf \
--mapping ./mapping.jsonDeep mode can run without an explicit mapping file:
code-obfuscator \
--mode forward \
--source ./project-src \
--target ./project-obf \
--deepReverse mode auto-detects mapping.generated.json in --source by default (explicit --mapping has priority):
code-obfuscator \
--mode reverse \
--source ./project-obf \
--target ./project-restoredcode-obfuscator now starts the interactive flow by default when no non-interactive flags are provided.
code-obfuscator
# explicit flag (same behavior)
code-obfuscator --tuiThe TUI prompts for mode (forward/reverse), source and target paths, deep mode, mapping selection, and optional
Ollama/seed settings.
The tool stores user mapping in the application config directory and uses it as default for forward mode when
--mapping is not provided.
Platform paths:
- Linux:
$XDG_CONFIG_HOME/code-obfuscator/mapping.jsonor~/.config/code-obfuscator/mapping.json - macOS:
~/Library/Application Support/code-obfuscator/mapping.json - Windows:
%APPDATA%\code-obfuscator\mapping.json
Mapping source priority:
- Explicit
--mapping - User config mapping
- For
reverse, auto-detectedmapping.generated.jsoninside--source
If forward is started with explicit --mapping, that mapping is also persisted as the new user default.
- Prepare mapping (optional but recommended):
{
"business_secret": "bs"
}- Build CLI:
make build
# or
cargo build --bin code-obfuscator- Obfuscate:
./target/debug/code-obfuscator \
--mode forward \
--source ./test-projects/input \
--target ./tmp/obf \
--mapping ./test-projects/mapping.json- Restore:
./target/debug/code-obfuscator \
--mode reverse \
--source ./tmp/obf \
--target ./tmp/restoredBy default, the server exposes:
ls_treels_filespullclonestatuspush
Legacy direct deobfuscation tools are removed.
- Prepare mapping (optional but recommended):
{
"business_secret": "bs"
}- Build MCP server:
cargo build --bin mcp-server
# or
make mcp-docker-build- Start MCP over HTTP:
MCP_HTTP_ADDR=127.0.0.1:18787 \
MCP_DEFAULT_MAPPING_PATH=./mapping.default.json \
./scripts/run-mcp-docker.shWith MCP_HTTP_ADDR set, ./scripts/run-mcp-docker.sh launches the container in HTTP-only mode.
Use it to keep the MCP server running in a terminal, then connect your IDE by URL. Do not register this script itself as a stdio MCP command.
- Verify:
curl -i http://127.0.0.1:18787/health
curl -i http://127.0.0.1:18787/mappingAll IDE examples below use one canonical Docker runtime pattern (synchronized with scripts/mcp_configure.sh).
Only the config file format differs by IDE.
Transport: stdio
docker run --rm -i \
-e MCP_DEFAULT_MAPPING_PATH=/data/mapping.default.json \
-e MCP_LOG_STDOUT=false \
-v /ABS/PATH/mapping.default.json:/data/mapping.default.json:ro \
-v /ABS/PATH/projects:/workspace/projects:rw \
code-obfuscator-mcp:localImportant for all IDEs:
- Mount mapping as read-only:
/ABS/PATH/mapping.default.json:/data/mapping.default.json:ro - Mount projects as read-write:
/ABS/PATH/projects:/workspace/projects:rw - In MCP calls,
root_dirmust be an in-container path (for example/workspace/projects/my-project), not a host path like/Users/...or/home/... - If you use
push, the project mount must stay:rw
Transport: stdio
~/.codex/config.toml:
[mcp_servers.code_obfuscator]
enabled = true
command = "docker"
args = [
"run", "--rm", "-i",
"-e", "MCP_DEFAULT_MAPPING_PATH=/data/mapping.default.json",
"-e", "MCP_LOG_STDOUT=false",
"-v", "/ABS/PATH/mapping.default.json:/data/mapping.default.json:ro",
"-v", "/ABS/PATH/projects:/workspace/projects:rw",
"code-obfuscator-mcp:local"
]Transport: stdio
~/.cursor/mcp.json:
{
"mcpServers": {
"code_obfuscator": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"MCP_DEFAULT_MAPPING_PATH=/data/mapping.default.json",
"-e",
"MCP_LOG_STDOUT=false",
"-v",
"/ABS/PATH/mapping.default.json:/data/mapping.default.json:ro",
"-v",
"/ABS/PATH/projects:/workspace/projects:rw",
"code-obfuscator-mcp:local"
]
}
}
}Transport: stdio
.mcp.json (or claude mcp add-json payload):
{
"mcpServers": {
"code_obfuscator": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"MCP_DEFAULT_MAPPING_PATH=/data/mapping.default.json",
"-e",
"MCP_LOG_STDOUT=false",
"-v",
"/ABS/PATH/mapping.default.json:/data/mapping.default.json:ro",
"-v",
"/ABS/PATH/projects:/workspace/projects:rw",
"code-obfuscator-mcp:local"
]
}
}
}Transport: stdio
.vscode/mcp.json:
{
"servers": {
"code_obfuscator": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"MCP_DEFAULT_MAPPING_PATH=/data/mapping.default.json",
"-e",
"MCP_LOG_STDOUT=false",
"-v",
"/ABS/PATH/mapping.default.json:/data/mapping.default.json:ro",
"-v",
"/ABS/PATH/projects:/workspace/projects:rw",
"code-obfuscator-mcp:local"
]
}
}
}[mcp_servers.code_obfuscator]
enabled = true
url = "http://127.0.0.1:18787/mcp"Use the canonical Docker template from "MCP integration in agent IDEs" and adapt only the config file format.
- Inspect source structure with
ls_tree/ls_files. - Use
clone(root_dir, workspace_dir, options.request_id)(orpullfor payload-only mode). - Edit only obfuscated files in workspace.
- Run
status(workspace_dir, options.request_id)to inspect delta. - Run
push(workspace_dir, options.request_id)to apply add/modify/delete back to source root.
fail-fast: obfuscated token ... is missing in LLM output for file ...- The model removed or changed an obfuscated token. Re-run the edit and preserve obfuscated tokens.
unknown request_id: ...- Start with
cloneorpulland reuse the sameoptions.request_idforstatus/push.
- Start with
root_dir is not writable for push ... Mount the project volume as :rw- Project Docker volume is mounted read-only. Mount it as
:rwfor apply operations.
- Project Docker volume is mounted read-only. Mount it as
make build
make test
cargo test --test mcp_server
make e2e-blackboxmake e2e-blackbox runs on-demand Codex blackbox scenarios and is not included in make test.
Scenario steps:
- Builds a fresh MCP Docker image via
make mcp-docker-build. - Stages a fixture project under
/workspace/projects/.../api-x-api/query.pywith three SQL blocks. - Reconfigures Codex MCP via
scripts/mcp_configure.shfor two transports:stdioandhttp. - Runs
codex exectwice with prompt fromtest-projects/blackbox/prompt_extract_sql.txt. - Verifies that both runs return the exact extracted SQL blocks from
test-projects/blackbox/query_api_x_expected.txt.
Prompt examples are in skills/code-obfuscator/references/prompt-templates.md.
The blackbox extraction fixture prompt is in test-projects/blackbox/prompt_extract_sql.txt.