@Grec0/ Secure Env Elicit
БесплатноНе проверенA secure wrapper that launches other MCP servers, replacing environment secrets with placeholders and eliciting them via an encrypted browser form, never exposi
Описание
A secure wrapper that launches other MCP servers, replacing environment secrets with placeholders and eliciting them via an encrypted browser form, never exposing secrets to the model or client.
README
Stop putting secrets in your mcp.json. This MCP server is a wrapper that launches other MCP servers for you: their config lives inside this package's config file with ${secure:…} placeholders instead of real values, and when a server needs to start, the missing values are collected from you through a browser form (MCP URL elicitation) and kept AES-256-GCM encrypted in memory — never written to disk, never visible to the model or the MCP client.
flowchart LR
subgraph wrapper["mcp-secure-env-elicit"]
vault[("in-memory vault<br/>AES-256-GCM")]
end
subgraph servers["your real MCP servers"]
s1["oracle · stdio"]
s2["jira · stdio"]
s3["sonarqube · Streamable HTTP"]
s4["metrics · SSE"]
end
client["Claude / MCP client"] -- "stdio" --> wrapper
wrapper -- "spawned · env resolved" --> s1 & s2
wrapper -- "connected · auth headers injected" --> s3 & s4
browser["your browser<br/>https://127.0.0.1:48910/auth"] -. "loopback HTTPS" .-> vault
Why
Most companies never get SSO wired into every internal tool: the database has its own credentials, SonarQube its own token, Jira yet another one. So each developer wires up their own MCP servers by hand, configs get passed around over chat with no agreed format, and the same API keys end up duplicated in plain text across every agent's config on every machine — files that then land in dotfile repos, screenshots, and backups:
flowchart TB
subgraph devA["Dev A"]
a1["Claude Code · mcp.json<br/>🔑 keys in plain text"]
a2["Copilot · mcp.json<br/>🔑 same keys again"]
end
subgraph devB["Dev B"]
b1["Codex CLI · config file<br/>🔑 same keys again"]
b2["Cursor · mcp.json<br/>🔑 same keys again"]
end
tools["internal tools without SSO<br/>DB · SonarQube · Jira · …"]
a1 --> tools
a2 --> tools
b1 --> tools
b2 --> tools
devA -. "config sharing = pasting keys over chat" .- devB
This wrapper flips that picture. MCP is the one interface every coding agent already speaks — Claude Code, Claude Desktop, Copilot, Codex CLI, Cursor, whatever comes next — so the wrapper becomes the single place where env secrets are handled. Every agent of every dev points at the same wrapper config (a local file or a shared git repo) that contains placeholders only; each dev types the real values once per session, and they live encrypted in that process's memory and nowhere else:
flowchart TB
repo[("one config file for the whole team<br/>git repo · mcp-secure-env.config.json<br/>servers + secrets metadata — placeholders only")]
subgraph devA["Dev A's machine"]
a1["Claude Code"]
a2["Copilot"]
wA["mcp-secure-env-elicit"]
vA[("Dev A's values<br/>in memory only")]
a1 & a2 -- "stdio" --> wA
wA -.- vA
end
subgraph devB["Dev B's machine"]
b1["Codex CLI"]
b2["Cursor · any MCP client"]
wB["mcp-secure-env-elicit"]
vB[("Dev B's values<br/>in memory only")]
b1 & b2 -- "stdio" --> wB
wB -.- vB
end
repo -- "same git url in --config" --> wA
repo -- "same git url in --config" --> wB
wA --> tools["internal tools via wrapped MCP servers<br/>stdio · Streamable HTTP · SSE"]
wB --> tools
The result: one file in one repo describes every server and every secret's metadata for the whole team — every agent of every dev reads the same config, the MCP client config contains zero secrets, and onboarding a new dev (or a new agent) is "point it at the repo". The only thing that stays per-person is the secret values, typed by each dev into their own local form and held only in their own wrapper's memory — no key handover, ever.
How it works
The wrapper sits between your MCP client and the real servers. It speaks stdio to the client, proxies every tool of every child it spawns, and owns the only copy of your secret values — sealed in an in-memory vault.
sequenceDiagram
autonumber
participant Client as Claude / MCP client
participant Wrapper as mcp-secure-env-elicit
participant Browser as Browser form (loopback HTTPS)
participant Child as Wrapped server (stdio or remote)
Client->>Wrapper: secure_env_start "oracle"
Wrapper->>Wrapper: resolve placeholders against the vault
alt values missing
Wrapper-->>Client: elicitation with a single-use sign-in URL
Note over Client,Browser: the URL carries a token, never a secret
Browser->>Wrapper: you fill and submit the form
Wrapper->>Wrapper: values sealed AES-256-GCM into RAM
Client->>Wrapper: secure_env_start again
end
alt stdio server
Wrapper->>Child: spawn with decrypted env vars
else remote server (HTTP / SSE)
Wrapper->>Child: connect with resolved url + headers
end
Child-->>Client: tools proxied as oracle__*
The life of a secret, start to finish:
- Declared. The wrapper config references it as
${secure:ORACLE_PASSWORD}— insideenvvalues orargsfor stdio servers, insideheadersor theurlfor remote ones. No real value exists anywhere in any file. - Requested. When a server starts and some of its placeholders have no value in the vault yet, the wrapper raises a URL-mode elicitation. Clients that support it pop a dialog that opens the sign-in page; clients that don't receive the URL in the tool result — open it manually and re-run the command after submitting. Links are single-use and stay valid for the whole 10-minute window, even if the tool call already returned.
- Collected. You type the values into the form and submit. They travel only over loopback HTTPS, straight from your browser into the wrapper process — never through the MCP protocol, so neither the model nor the client ever sees them. There is deliberately no "set secret" tool.
- Sealed. Each value is immediately encrypted with AES-256-GCM under a key minted at process start and held only in the wrapper's memory. Nothing is ever written to disk.
- Used. Values are decrypted only at spawn time, directly into the child's environment (or into the request headers of a remote server). The same
NAMEshared by several servers is asked once and reused. - Gone. The key and every value die with the process. Restart your MCP client and you'll be asked again — that's the price of never persisting anything, softened by browser autofill (see Trusted TLS).
This is what the operator actually sees — the sign-in form for the oracle example below, and the confirmation after submitting (dark theme):
Quick start
1. Add the wrapper to your MCP client (e.g. .mcp.json for Claude Code):
{
"mcpServers": {
"secure-env": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@grec0/mcp-secure-env-elicit", "--config", "C:/path/to/mcp-secure-env.config.json"]
}
}
}
2. Write the wrapper config (mcp-secure-env.config.json) describing the servers to wrap:
{
"theme": "dark",
"servers": {
"oracle": {
"command": "npx",
"args": ["-y", "@grec0/mcp-oracle-db"],
"env": {
"ORACLE_CONNECTION_STRING": "${secure:ORACLE_USER}/${secure:ORACLE_PASSWORD}@//db.example.com:1521/XEPDB1"
},
"autoStart": true
}
},
"secrets": {
"ORACLE_USER": { "description": "Oracle schema user", "input": "text" },
"ORACLE_PASSWORD": { "description": "Oracle schema password" }
}
}
3. Use it. Ask your client to call secure_env_start with {"server": "oracle"} (or let autoStart do it). If values are missing you get a link like https://127.0.0.1:48910/auth?token=… — open it, fill the form, submit, run the command again. Done: the oracle tools now appear as oracle__<tool>.
Placeholders
${secure:NAME} works anywhere inside env values or args strings for stdio servers, and inside headers values or the url for remote ones — including embedded in larger strings (connection URLs, DSNs, Bearer … prefixes).
Optionally pick the form widget: ${secure:NAME:type} with text, password, email, number, url or tel. Types can also be set in the secrets metadata ("input": "email"). When nothing is explicit, the widget is inferred from the name: variables matching PASSWORD, PASS, PWD, SECRET, TOKEN, API_KEY, ACCESS_KEY, PRIVATE_KEY, CREDENTIAL, AUTH render as password inputs; names containing MAIL render as email inputs.
Shared config in a git repo
Instead of a local path, --config accepts a git URL — so one repo (private is fine) holds the team's wrapper config, and every dev just points at it:
"args": ["-y", "@grec0/mcp-secure-env-elicit", "--config", "https://git.example.com/org/mcp-configs.git#teams/backend.json"]
- The
#path/inside/repo.jsonfragment names the file (or use--config-file <path>); without it,mcp-secure-env.config.jsonat the repo root is assumed. - The repo is cloned shallowly on the default branch into
~/.mcp-secure-env-elicit/repos/. Only the first-ever start pays for the network: afterwards the cached copy is used immediately and refreshed in the background, so startup stays well inside MCP client connect timeouts and config changes reach each dev on their next restart. - Tip: MCP clients typically allow ~30s for a server to start, and a cold
npxdownload plus the first clone can exceed it. If the very first connection times out, just reconnect — everything is cached by then. Pinning an exact version (@grec0/[email protected]) also makes npx noticeably faster on slow networks. - Authentication rides on the system git: Git Credential Manager on Windows, SSH keys, cached HTTPS credentials — whatever already lets the dev
git clonethat repo works here too. No extra tokens to mint: grant read access to the repo and that is it. (First time ever on a machine, rungit clone <url>once in a terminal — or let the credential manager's window appear — so the credentials get cached.) - Offline-friendly: if the remote is unreachable but a cached clone exists, the cached copy is used with a warning — being off VPN never blocks startup.
- Remember the config contains placeholders only, so read access to the repo reveals no secret values; each dev still provides their own through the local sign-in form.
Remote servers (HTTP / SSE)
Not every MCP server is a local process. Entries with a type of http, https, or sse connect to a remote MCP endpoint instead of spawning one, and their headers (and even the url) accept the same placeholders:
{
"servers": {
"sonarqube": {
"type": "https",
"url": "https://tools.example.com/sonar-mcp-server/mcp",
"headers": { "SONARQUBE_TOKEN": "${secure:SONARQUBE_TOKEN}" }
},
"db": {
"type": "sse",
"url": "https://tools.example.com/mcp-sse-db/sse",
"headers": { "X-Api-Key": "${secure:DB_API_KEY}" },
"insecureTls": true
}
}
}
http/httpsuse the modern Streamable HTTP transport and automatically fall back to SSE if the endpoint turns out to be a legacy one — so"type": "https"works for both kinds without you having to know.sseforces the legacy SSE transport (headers are sent on the stream request too).insecureTls: trueaccepts a server certificate that is not publicly trusted (self-signed or internal CA), scoped to that server's requests only. It covers requests made by the wrapper; a stdio child that talks to an internal host itself needs TLS configured in its ownenvinstead (for Node ≥ 22.15 children:"NODE_USE_SYSTEM_CA": "1", orNODE_EXTRA_CA_CERTS).- No
type(or"type": "stdio") keeps the spawn behaviour:command,args,env,cwd.
Tools
| Tool | Description |
|---|---|
secure_env_status |
State of each configured server: stopped/starting/running/error, missing secret names (never values), pending sign-in URL, tool count. |
secure_env_start |
Start a server. Returns the sign-in URL if values are missing; call again after submitting. |
secure_env_stop |
Stop a running server and remove its tools. |
<server>__<tool> |
Every tool of every running child, forwarded verbatim (schema included). The tool list refreshes via notifications/tools/list_changed. |
Trusted TLS & browser autofill
The sign-in page must be HTTPS (MCP clients only open https: URLs for elicitation), so the wrapper auto-generates a self-signed certificate under ~/.mcp-secure-env-elicit/tls/. It works as-is, but browsers refuse to save passwords on untrusted pages — trust the certificate once with npx -y @grec0/mcp-secure-env-elicit trust-cert (restart the browser afterwards) and your password manager will offer to remember the values and refill them in two clicks after every restart. Prefer your own certificate (mkcert, an internal CA, or a real domain pointed at 127.0.0.1)? Set "tls": { "certPath": "…", "keyPath": "…" } in the config. Keep PORT stable (default 48910): autofill is keyed to the page origin.
Themes
The sign-in page ships with several looks: light (default), dark, ocean, forest, terminal, sunset. Pick one with:
--theme darkon the command line, orMCP_SECURE_ENV_THEME=dark, or"theme": "dark"in the config file.
Configuration reference
| Where | What |
|---|---|
--config <path or git url> / MCP_SECURE_ENV_CONFIG |
Config file location — a local path or a …repo.git[#file] URL (see Shared config in a git repo). Defaults: ./mcp-secure-env.config.json, then ~/.mcp-secure-env-elicit/config.json. |
--config-file <path> |
File inside the config repo when --config is a git URL and has no #fragment. |
--theme <name> / MCP_SECURE_ENV_THEME / "theme" |
Sign-in page theme. |
HOST / PORT |
Loopback server binding. Defaults 127.0.0.1:48910. Keep the port stable for browser autofill. |
"servers" (stdio) |
command, args, env (with placeholders), optional cwd, optional autoStart. Server names cannot contain _. |
"servers" (remote) |
type (http/https/sse), url, headers (with placeholders), optional insecureTls, optional autoStart. |
"secrets" |
Optional per-secret description and input. |
"tls" |
Optional certPath/keyPath for a trusted certificate. |
Note on autoStart: servers whose secrets are still missing are not prompted at boot — a wrapper hosts many servers and asking for everything on startup would be a wall of prompts. They wait quietly and elicit when first started (secure_env_start).
Security model, honestly
- Secret values are held AES-256-GCM encrypted in the wrapper's memory, under a key minted per process. They are decrypted only at spawn time, directly into the child's environment.
- Nothing is ever written to disk by the wrapper except TLS material (which contains no secrets).
- Values never enter the MCP conversation: there is deliberately no "set secret" tool, so the model cannot be handed a secret even by accident. The only input path is the loopback form.
- Error messages are redacted: transport and fetch errors can echo the request URL or upstream response bodies, so every secret value (plain and percent-encoded) is scrubbed to
[secret]before an error reaches stderr,secure_env_status, or a tool result. There is a regression test for it. - The child process receives the secrets as plain environment variables — that is the contract of the servers being wrapped. Anyone able to inspect the child's environment (same OS user) can read them, exactly as if you had configured the server directly.
- Prefer placeholders in
envoverargs: command lines are visible in process listings.
Limitations
- Only tools are proxied for now (no resources or prompts).
Development
npm install
npm run check # lint + typecheck + tests + build
License
MIT
Установка @Grec0/ Secure Env Elicit
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/gcorroto/mcp-secure-env-elicitFAQ
@Grec0/ Secure Env Elicit MCP бесплатный?
Да, @Grec0/ Secure Env Elicit MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для @Grec0/ Secure Env Elicit?
Нет, @Grec0/ Secure Env Elicit работает без API-ключей и переменных окружения.
@Grec0/ Secure Env Elicit — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить @Grec0/ Secure Env Elicit в Claude Desktop, Claude Code или Cursor?
Открой @Grec0/ Secure Env Elicit на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Playwright
Browser automation, scraping, screenshots
автор: MicrosoftPuppeteer
Browser automation and web scraping.
автор: modelcontextprotocolopentabs-dev/opentabs
Plugin-based MCP server + Chrome extension that gives AI agents access to web applications through the user's authenticated browser session. 100+ plugins with a
автор: opentabs-devrobhunter/agentdeals
1,500+ developer infrastructure deals, free tiers, and startup programs across 54 categories. Search deals, compare vendors, plan stacks, and track pricing chan
автор: robhunterCompare @Grec0/ Secure Env Elicit with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории browse
