Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here

Summary

Zero-dependency MCP server + PreToolUse hook that lets an agent read and edit .env files through a length-preserving, blurred view — secrets never leave the file. Blocks raw .env access via Read/Edit/Write/Grep/Glob/Bash.

Install to Claude Code

/plugin install envcloak@envcloak

Run in Claude Code. Add the marketplace first with /plugin marketplace add YushkoVolodymyr/envcloak if you haven't already.

README.md

envcloak

A tiny MCP server that lets a Claude Code agent read and edit .env files

without ever seeing real secret values — while keeping the file informative enough to actually debug with.

  • Zero dependencies. Pure Python 3.8+ standard library. No pip, no npm.
  • Self-contained. Everything lives in this one folder.
  • Installable as a Claude Code plugin. One command registers the MCP server

and the .env-blocking hook — see Install.

  • Tested. python3 -m unittest (54 tests).

How it works

When the agent reads a file it gets a blurred, length-preserving view:

NODE_ENV=production
API_KEY=xx_xxxx_0xX00XxXxxXXxxxxX0xxx0xx
DATABASE_URL=xxxxxxxx://xxxxx:x0xx0x@xx:0000/xxx
PORT=8080

The masking rules:

| Input | Output | Why | |------------------|------------|------------------------------------------------| | Latin letter | x / X | hides content, keeps case & length | | digit | 0 | hides content, keeps length | | punctuation/space| unchanged | keeps structure (://, @, ., -, quotes) | | non-ASCII | x | so unicode can't leak |

So a secret keeps its shape (a JWT still looks like xxx.xxx.xxx, a URL keeps its scheme/host/port skeleton) but not its value. Crucially the blurred text is the exact same length as the real file, character for character — that is what makes char-range edits safe.

Non-secret config is shown in clear via an allow-list, because that is what you need when debugging: NODE_ENV, *_ENV, LOG_LEVEL, DEBUG, PORT,

*_PORT, TZ, LANG, plus any boolean value (true/false/yes/no/on/off) and empty values. Edit the list in config.json.

Safety properties

  • No round-trip corruption. The agent never needs to know a secret to edit

one. env_set_value refuses to write a value that looks like a mask (only

x/X/0 + punctuation), so a masked value can't be echoed back over a real one. Renames touch only the key.

  • Structural-only range edits. env_replace_range refuses to overlap any

masked value (use env_set_value/env_rename_key for those).

  • Path fence. Only env-looking files (.env, .env, .env.) are

accepted. Extend via allowed_path_globs in config.json.

  • Atomic writes preserving the original file mode.
  • File-level destructive ops require confirm: true (env_delete_file,

overwriting via env_create_file).

To make this airtight, the agent must not be able to read env files any other way (Read tool, cat, grep, …). The plugin does this for you — see Install:

1. A PreToolUse hook (block-env-files.py) — the enforcer. It blocks raw .env access (Read/Edit/Write/Grep/Glob/Bash, including cat/grep/wildcards/exfiltration) across every project in every permission mode. 2. An allow rule for the envcloak MCP tools baked into ~/.claude/settings.json at SessionStart, so the secure env_read path never prompts.

> Why no permissions.deny rules? Earlier versions (≤1.0.2) also baked > Read(.env.) deny rules. That breaks Claude Code's auto mode: its safety > classifier sees env_read reading a .env while a deny rule exists and rejects > it as "circumventing the deny rule by switching tools."* An allow rule can't > override the classifier. So as of 1.1.0 the plugin injects no .env deny > rules and, at SessionStart, retracts any it wrote before. Raw-read blocking > is the hook's job; the deny rules were redundant with it anyway.

Tools

| Tool | Purpose | |---------------------|------------------------------------------------------------| | env_read | Blurred view + per-key summary (masked vs clear) | | env_set_value | Set an existing key's value (round-trip guarded) | | env_rename_key | Rename a var; value preserved untouched | | env_add_key | Add a new key | | env_delete_key | Delete a key | | env_replace_range | Advanced structural splice by blurred-view offsets | | env_create_file | Create a new env file (confirm to overwrite) | | env_delete_file | Delete a file (confirm required) |

Install as a Claude Code plugin (recommended)

envcloak ships as a self-contained plugin: installing it registers the

envcloak MCP server and wires the .env-blocking hook for you — no manual settings.json editing. The repo is its own marketplace, so:

# In Claude Code:
/plugin marketplace add YushkoVolodymyr/envcloak
/plugin install envcloak@envcloak

Then restart Claude Code (or run /hooks). Verify with:

claude mcp list        # -> envcloak: ... ✔ Connected

Requirement: a Python 3.8+ interpreter on PATH. The MCP server and hooks launch as ${ENVCLOAK_PYTHON:-python3}, and a SessionStart hook auto-detects the right interpreter so you usually don't have to: it probes python3, python,

python3.x and the Windows py -3 launcher, runs each candidate to confirm it actually works (this skips the Microsoft Store python3 alias, which resolves on PATH but exits without running), then bakes the winner's absolute path into ~/.claude/settings.jsonenv.ENVCLOAK_PYTHON. Restart Claude Code once after first install so the server and hook pick it up.

The detector is tools/resolve-python.sh (one POSIX-shell hook entry covering Linux, macOS, and Windows under Git Bash / MSYS2). On native Windows with no POSIX shell, run the PowerShell equivalent once, then restart:

powershell -NoProfile -ExecutionPolicy Bypass -File tools\resolve-python.ps1

You can always override detection by setting ENVCLOAK_PYTHON yourself (it takes priority):

export ENVCLOAK_PYTHON=python     # macOS/Linux with only `python`
setx ENVCLOAK_PYTHON py           # Windows, py launcher (then restart)

Zero Python dependencies.

What the plugin activates (in every project, while enabled):

  • a SessionStart hook that (a) auto-detects a working Python interpreter

and bakes it into ~/.claude/settings.json (see the requirement note above), (b) merges .env permissions.deny rules + an mcp__envcloak allow rule into the same file, and (c) injects a one-line reminder into the session so the agent reaches for env_read first;

  • the envcloak MCP server (the env_read / env_set_value / … tools);
  • a PreToolUse hook that blocks raw .env access via

Read/Edit/Write/Grep/Glob/Bash. The Bash gate covers bash,

cmd.exe and PowerShell — it blocks reads (including wildcards like .e* that the shell would expand to a real .env) and blocks copy/move/rename commands that would land a protected file under a readable name (secret exfiltration). Renaming/moving between protected names is allowed (e.g. mv .env.local .env).

Example/template files (.env.example, .env.sample, .env.template,

.env.dist, .env.schema) carry no secrets and stay readable.

Disable or remove anytime with /plugin (or /plugin uninstall envcloak@envcloak).

Permission rules (automatic)

The SessionStart hook reconciles ~/.claude/settings.json for you — no manual editing, idempotent, and it preserves your unrelated rules:

{
  "permissions": {
    "allow": [
      "mcp__plugin_envcloak_envcloak", "mcp__plugin_envcloak_envcloak__env_read", "…",
      "mcp__envcloak", "mcp__envcloak__env_read", "…"
    ]
  }
}

The allow list covers the secure tools under both name shapes Claude Code might use: the plugin-namespaced mcp__plugin_envcloak_envcloak__<tool> (what a plugin install actually invokes) and the plain mcp__envcloak__<tool> (a non-plugin claude mcp add install) — server-wide and per-tool for each. The per-tool, correctly-namespaced entries are what auto mode matches; that mode auto-denies any tool not matched by name in permissions.allow, so a wrong or missing name means the secure env_read is rejected there.

No .env deny rules. The hook does not add permissions.deny entries, and at SessionStart it retracts any envcloak wrote in ≤1.0.2 (Read/Edit/Write on

.env, .env., the old */ variants, and config-derived globs). They broke

auto mode (the classifier flagged env_read as deny-rule circumvention) and were redundant with the always-on PreToolUse hook.

If you run in a strict, non-auto setup and want belt-and-suspenders settings denies, add them by hand — but expect auto mode to then reject env_read.

Configure

config.json:

{
  "reveal_keys": ["NODE_ENV", "*_ENV", "LOG_LEVEL", "DEBUG", "PORT", "*_PORT"],
  "reveal_boolean_values": true,
  "reveal_numeric_values": false,
  "partial_reveal": 0,
  "allowed_path_globs": []
}
  • reveal_keys — glob patterns (case-insensitive) shown in clear.
  • reveal_numeric_values — reveal plain numbers (off by default: a long digit

run can be a secret).

  • partial_reveal — keep N real chars at each end of a masked value

(dashboard-style "ends in a3f2"). 0 = fully masked. Leaks a few bytes when set.

  • allowed_path_globs — extra path/basename globs beyond *.env that the MCP

will touch (a custom env-file location). Note: the PreToolUse hook protects

.env/.env.* by basename; extend the hook separately if your custom files don't match that. Changes apply on the next /plugin reload + restart.

Develop / test

python3 -m unittest -v          # run the 54 tests

envcloak_core.py is pure logic (parse / blur / edit) and has no I/O, so it is trivially testable. server.py is the thin MCP/JSON-RPC stdio wrapper.

Known limitations

  • Length is preserved, which leaks the length of a secret (fine for almost all

threat models; turn values into fixed-width if that matters to you).

  • The dotenv parser handles comments, export , single/double quotes, inline

comments, and multiline quoted values — but not every exotic shell-expansion edge case. ${VAR} interpolation is masked as ordinary text.

Related plugins

Browse all →