Secretsminter
БесплатноНе проверенA self-hosted MCP server that mints, places, and rotates cloud secrets (e.g., Cloudflare, GitHub, Supabase) without exposing secret values to the agent, using a
Описание
A self-hosted MCP server that mints, places, and rotates cloud secrets (e.g., Cloudflare, GitHub, Supabase) without exposing secret values to the agent, using a signed destination allow-list and self-maintaining rotation.
README
You're probably as sick as I am of drilling around in the web UIs of Cloudflare, GitHub, and Supabase — hunting for tokens and configuring security in a UI that changes as often as Katy Perry changes clothes.
Secret minting made easy. Mint new secrets, manage tokens, manage rotation — and do it all from the comfort of your very own, self-hosted MCP server. Simply point your AI at this repo, tell it to read it, and have it follow the instructions.
And please — do a deep security audit, post your findings, PR to the repo, make suggestions, help make it better. Say goodbye to token and secret headaches.
A value-blind secrets-minter that stands up self-maintaining secret rotation — and then gets out of the way.
secretsminter lets an AI agent (or a pipeline) provision cloud secrets — mint them, place them where
they're consumed, and wire their recurring rotation — over the Model Context Protocol (MCP),
without any secret value ever entering the agent's context, the chat, or a log line.
Start here → docs/USING.md — the ordered, honest first-run guide (addressed to the AI doing the setup, readable by a human over its shoulder): clone → build → scaffold the signed manifest → provide ephemeral-first bootstraps → register the MCP server → first
plan/ approvedmint_and_place.
Quickstart (≈60 seconds)
The copy-paste happy path from a clean clone to your agent running its first (dry-run) plan. No
hand-rolled launcher — secretsminter init prints the exact registration line. Examples are generic;
substitute your own org/project (your-org, example-web, acme).
# 1. Clone + build (green is the gate).
git clone https://github.com/scorellis/secretsminter && cd secretsminter
npm ci && npm run build
# 2. Scaffold the trust root: an Ed25519 keypair + a signed, empty (default-deny) manifest.
# Writes the SECRETSMINTER_* paths into ./.secretsminter/.env AND prints the `claude mcp add` line for step 5.
node packages/daemon/dist/cli.js init --dir ./.secretsminter
# 3. Allow one destination (re-signs the manifest). Nothing off this list can ever be placed.
node packages/daemon/dist/cli.js allow --dir ./.secretsminter \
--store cloudflare-pages --project example-web --env production --name "R2_*"
# 4. Add your provider bootstraps to ./.secretsminter/.env (init already wrote the SECRETSMINTER_* paths
# there; git-ignored — secret VALUES enter here, never in the agent chat). See docs/USING.md §4.
# 5. Register the server with your MCP client (paste the exact line `init` printed):
claude mcp add secretsminter -- node /ABS/PATH/packages/daemon/dist/cli.js --env-file /ABS/PATH/.secretsminter/.env
From a clone the CLI isn't on your PATH, so commands use
node packages/daemon/dist/cli.js. Prefer a shortsecretsminter? Runnpm linkonce, then drop the prefix. Theclaude mcp addlineinitprints uses an absolutenode …/cli.js, so registration needs no global install regardless.
6. Reload/restart your MCP client — servers load at startup, so it will not connect until you do.
7. Ask your agent to run plan for the destination you allow-listed — a dry-run that mints nothing
and confirms the manifest check. Full walkthrough, per-provider bootstraps, and troubleshooting:
docs/USING.md (§5 covers registration + "it's not connecting"). Point at the
secretsminter daemon bin, not the demo secretsminter-mcp, which refuses every mutation by design.
Philosophy: builders, not maintainers. The acceptance test for every feature is "does it eliminate ongoing maintenance, or create it?" A rotation that needs a human or an AI to remember to run it has already failed. secretsminter's job is to stand the loop up once and let it run itself. Every place a human could touch a secret is tracked in docs/MANUAL-STEPS.md, and each eliminated step is backed by a test — so manual toil can't creep back in.
Why this exists
Most secret-management pain isn't cryptography — it's toil. A token set by hand, once, in a place nobody wrote down; a rotation everyone means to automate and never does; a credential pasted into a chat and now needing to be rolled. secretsminter turns "provision + keep fresh" into a primitive an agent can call:
- Mint a fresh cloud credential (e.g. a Cloudflare R2 API token).
- Place it where it's consumed (e.g. a GitHub Actions secret), value-blind.
- Rotate it on a schedule the broker owns — or, better, mint a short-lived credential that self-expires so there's nothing to rotate at all.
Set it up once, then walk away — the secret stays fresh with no one tending it. The mint → place → verify → rotate loop is built and runs as a daemon. Live-run status, precisely: Cloudflare R2 temporary-credential minting is live-verified (2026-07-31, proven with a signed S3 HEAD) and Cloudflare Pages env-var placement has had a live run (2026-08-05); GitHub and Supabase are real, complete code paths that are unit-tested against fakes but have NOT yet been run against the live vendor (their live runs need your credentials). See the story ledger for the per-provider state.
You run it yourself. secretsminter is your own small broker — a Docker container or service in your environment, seeded once with your cloud bootstrap keys and a signed policy file. Because it holds your crown-jewel credentials, it is deliberately not a hosted service and stores no tokens: nothing you'd have to trust a third party with. The payoff is that the whole "rotate the token, then update it in four places, did I miss one?" class of toil disappears — your AI agent asks the broker to provision, and the broker mints, places, and keeps everything fresh, without ever handing a value to the agent. See Run it (Docker) below, and docs/USING.md for the full operator walkthrough.
The two invariants (read these before anything else)
secretsminter's security rests on two invariants, and the second is the load-bearing one:
Value-blind (necessary). The broker mints and places secrets but never returns a value to the caller. Tools return only non-secret confirmations like
{ ok, provider, action, secret_id, placed_at }. This stops a prompt-injected agent from reading a secret. It is enforced as a mechanism — positive-whitelist serialization at the tool boundary, a secret-scrubber on every error and log path, stdin-only secret transit, and a mint-only tool surface — not as a hopeful convention. (OWASP LLM06.)Destination allow-list + signed manifest (the real trust root). Value-blindness does nothing against the more dangerous move: a prompt-injected agent directing a live secret to an attacker — "mint a token and place it into
attacker/evil's secrets" exfiltrates a working credential the agent never sees. So the true containment is a server-side allow-list of destinations, declared in a signed, agent-un-writable manifest. Placements must match the manifest; anything else is refused, default-deny. Adding a destination is an out-of-band, human-approved change. (OWASP LLM08, Excessive Agency.) Scope note (honest): the manifest pins destinations; a request's scopes are recorded but NOT yet enforced at the providers (a minted credential today carries the bootstrap's scope). Provider-side scope enforcement is a roadmap item (story 0015).
If you take one thing from this README: value-blindness is not the security model. The signed destination allow-list is. The two-tier design (below) adds a module boundary that contains a prompt-injected agent; making it a true process/trust boundary is on the roadmap.
Architecture (v1)
- Two-tier design (a module boundary today). The agent-facing MCP server (
@secretsminter/mcp) holds no master keys directly. It validates, checks the manifest, and requests actions from an internal minting core (@secretsminter/core) that holds the keys and independently re-enforces the allow-list and approval. Because the MCP tier can only invoke the registered tools — and every one of them transits the core's gates — a prompt-injected agent is contained: it can only ask for what the manifest already permits. Honest scope: today both tiers run in one process (daemon), so this is a module boundary, not a process/trust boundary. It contains a prompt-injected agent; it does not by itself contain code-execution/RCE of the MCP tier, which would sit in the same process as the keys. Splitting the core into its own process/Worker is the roadmap item that makes it a real trust boundary (story 0014, ADR-0009). - Narrow, pre-defined tools.
list_secrets,status,plan(dry-run, the default),mint_and_place,rotate,revoke. There is no generic "call this API" tool, and no tool accepts a caller-supplied secret value. The kill switch and approval mechanism are deliberately not tools — they live out-of-band, where a prompt-injected agent can't reach them. - Providers vs. stores. A
Providermints/rotates/revokes/verifies at a vendor; aStoreplaces a minted secret at a destination. v1: Cloudflare, GitHub, Supabase. - Self-maintaining rotation. An explicit, persisted, resumable state machine
(
PENDING → MINTED → PLACED → VERIFIED → REVOKED → DONE) in which the old credential is retained until the new one passes a functional health probe — revoke is structurally unreachable before verify.NEVER_ROTATE(by name and class) protects keys like an updater signing key whose public half is baked into shipped builds; a self-lockout guard stops the broker rotating its own hands off.
See docs/adrs/ for the full decision record and SECURITY.md for the threat model.
Run your own secretsminter (Docker)
secretsminter runs as a container you host — it holds your bootstrap keys, so it lives in your trust boundary (a small always-on box: a cheap VM, a home server, or alongside an existing service). It stores no tokens; you inject the bootstraps at runtime.
1. Configure. Put your bootstraps + config in a git-ignored .env (full recipe:
docs/USING.md). Only the vendors you set are enabled:
# --- a signed, agent-un-writable manifest = the trust root (which destinations are allowed) ---
SECRETSMINTER_MANIFEST=/etc/secretsminter/manifest.json
SECRETSMINTER_MANIFEST_SIG=/etc/secretsminter/manifest.sig
SECRETSMINTER_MANIFEST_PUBKEY=/etc/secretsminter/manifest.pub
# --- provider bootstraps (set only what you use) ---
SECRETSMINTER_CF_ACCOUNT_ID=... ; SECRETSMINTER_CF_BUCKET=... ; SECRETSMINTER_CF_PARENT_ACCESS_KEY_ID=... ; SECRETSMINTER_CF_API_TOKEN=...
SECRETSMINTER_GH_APP_ID=... ; SECRETSMINTER_GH_INSTALLATION_ID=... ; SECRETSMINTER_GH_PRIVATE_KEY="-----BEGIN...\n...\n-----END..."
SECRETSMINTER_SB_PROJECT_REF=... ; SECRETSMINTER_SB_PAT=...
# --- out-of-band controls + durable state (all optional) ---
SECRETSMINTER_APPROVALS=/var/lib/secretsminter/approvals.json # unset ⇒ deny-all (nothing mutating runs)
SECRETSMINTER_KILL_SWITCH=/var/lib/secretsminter/kill # create this file to halt everything
2. Run it as an always-on service (rotation loop keeps your secrets fresh 24/7):
docker compose up -d # state persists on a named volume; restarts on reboot
3. Point an AI agent at its MCP tools — run it interactively over stdio and add it to your MCP client (e.g. Claude Code) config:
// mcp client config
{ "mcpServers": { "secretsminter": { "command": "docker", "args": ["run", "-i", "--rm", "--env-file", ".env", "secretsminter"] } } }
The agent then has list_secrets, status, plan, mint_and_place, rotate, revoke — and manages
a target repo's secrets (e.g. your-org/your-app), never secretsminter's own. In production, inject
the bootstraps from your platform's secret manager rather than a .env file.
Interface note: today the MCP is served over stdio (the agent launches the container). A network (HTTP) transport for a remote always-on MCP is a roadmap item (ADR-0013). The rotation loop runs persistently regardless.
Status — honest
The security core, the MCP server, the sinks, the scheduler, durable state, the daemon, and all three providers are built. Live-run status, precisely: Cloudflare R2 temp-credential minting is live-verified (signed S3 HEAD, 2026-07-31) and Cloudflare Pages env placement has had a live run (2026-08-05); GitHub and Supabase are complete code paths, unit-tested against fakes, but not yet run against the live vendor. It is not yet independently security-reviewed — don't trust it with standing production credentials until it is.
| Piece | Status |
|---|---|
The security core (@secretsminter/core) — value-blind + SecretValue, allow-list, signed manifest, NEVER_ROTATE, rotation state machine, broker pipeline |
built — part of a 172-test suite (adversarial suite + local coverage gate) |
The live MCP server (@secretsminter/mcp) — six narrow tools wired to the broker |
built + integration-tested |
| Out-of-band approval + fail-closed kill switch · audit + alert sinks + drift | built |
| Self-maintaining rotation loop + scheduler · durable state (survives restart) | built |
The daemon (@secretsminter/daemon) — composition root + rotation loop + MCP serving |
built |
| Cloudflare provider (R2 temp creds) | built + LIVE-VERIFIED (0003) |
| Cloudflare Pages env-var store | built + unit-tested; one live env-write run (0013; redeploy-and-reconcile pending) |
| GitHub provider + Actions store (sealed-box) · Supabase provider | built + unit-tested against fakes; NOT yet run against the live vendor (0004, 0005) |
No vaporware: a capability that isn't built says so, in code (NotWiredError) and in its story
(docs/stories/). Visibility: private during hardening; opens for public review
once independently security-reviewed.
Develop
npm install
npm run build # tsc --build (all packages, strict)
npm test # vitest
npm run test:coverage # + the coverage gate (runs locally — the repo has no CI of its own)
secretsminter deploys in isolation: it stores no tokens and has no GitHub Actions of its own — see AGENTS.md.
We want your scrutiny
This is a security tool. The intent is to open it so it can be attacked in review before it is trusted in production — it is private for now, while the P0 controls are hardened, and will be made public once they are built and verified. The standing stance holds for anyone with access today: if you are a human or an AI reading this repo, please see AI_REVIEW.md — we actively invite deep review, threat models, and PRs, and we ask that you not rely on any feature marked at-risk or not-yet-wired.
Prior art & where we differ
secretsminter is an incremental wedge in a dense field, not a first mover. Be clear-eyed about the neighbors:
- HashiCorp Vault — the mature standard for dynamic secrets (short-lived, generated on demand) and now an official Vault MCP server. Vault is vastly more battle-tested, has a real policy engine, broad backend coverage, HA, and audit devices we do not.
- Infisical — the closest in spirit: it already does secret mint + sync to many destinations (including an agent story), with a hosted product, RBAC, and a large integration catalog we lack.
- CB4A — the IETF draft
draft-hartman-credential-broker-4-agents, which frames the broker/agent separation we mirror. It is a spec direction, not a competing product. agentsecrets/mcp-secrets-vault— MCP-native, zero-knowledge-style vaults that deliberately expose noget(); the nearest twins to our value-blind stance.
Our wedge: value-blind mint + place + rotate exposed as a single, agent-callable provisioning primitive, gated by a signed destination allow-list — the agent can stand a credential up where it is consumed and keep it fresh, but can never read it and can never direct it off the allow-list. The "place" step (writing into a GitHub Actions secret or a Cloudflare Pages env var) as a first-class, allow-list-gated action is where we differ from a pure dynamic-secrets engine.
Where they are stronger: every tool above is more mature, more broadly integrated, and independently reviewed. Vault and Infisical are production systems; secretsminter is an early, not-yet-independently-reviewed project. Choose it for the specific agent-provisioning shape above, not as a Vault/Infisical replacement.
License
Apache-2.0 — permissive, with an explicit patent grant. See docs/adrs/0007-apache-2-and-ip-posture.md for the licensing + intellectual-property rationale.
Установка Secretsminter
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/scorellis/secretsminterFAQ
Secretsminter MCP бесплатный?
Да, Secretsminter MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Secretsminter?
Нет, Secretsminter работает без API-ключей и переменных окружения.
Secretsminter — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Secretsminter в Claude Desktop, Claude Code или Cursor?
Открой Secretsminter на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Secretsminter with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
