infisical
Our journey from scattered secrets across various environments to a unified Infisical setup, with AI-driven migrations and MCPs.
TL;DR: We went from secrets scattered across .env.local, Fly.io, and two GitHub Action repos to a single Infisical source of truth. An AI agent drove the migration using MCPs. Zero manual secret setup now. Here's how.

Secrets were everywhere. And nowhere consistent.
.env.local copied from someone else's machine or a wiki. Sometimes committed by accident. Often stale.fly secrets set run manually. 18 secrets. No record of who set what or when.k2k-mega-foundation (deploy) and k2k-sidekick (release). Same keys, different values sometimes. Or missing.No audit trail. Drift between environments. The classic mess.
We needed one place to store secrets and one way to push them out. Infisical gives you:
That last point mattered. We didn't want a migration we'd babysit. We wanted the agent to do it.
Model Context Protocol (MCP) turns infrastructure into structured tools. Instead of parsing CLI output or clicking dashboards, the agent calls tools and gets JSON back.
.env.local and compare to Infisicalgh secret set.The agent didn't guess. It called tools, got data, and acted on it.
create-secret for each key we had in .env.local and Fly. 18 secrets in prod, 14 in local.k2k-foundation, connect, enable auto-sync. Done.k2k-mega-foundation and k2k-sidekick to Infisical prod. Overwrite mode—Infisical is source of truth.No bash one-liners. No bespoke sync scripts. Infisical does it.
Phase 1 still had a wart: local dev required npm run env:sync before docker compose up. A human (or agent) had to remember it.
We fixed that with a Docker entrypoint that fetches secrets at container startup:
#!/bin/bash
set -e
# Authenticate with Infisical Universal Auth
INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id="${INFISICAL_UNIVERSAL_AUTH_CLIENT_ID}" \
--client-secret="${INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET}" \
--silent --plain 2>/dev/null)
[ -z "$INFISICAL_TOKEN" ] && { echo "Infisical auth failed"; exit 1; }
export INFISICAL_TOKEN
# Export secrets to temp file, source, then exec
infisical export --projectId=YOUR_PROJECT --env=local --format=dotenv > /tmp/.env.infisical
set -a && source /tmp/.env.infisical && set +a
rm -f /tmp/.env.infisical
exec "$@"
Dockerfile.dev installs the Infisical CLI and sets this as ENTRYPOINT. Universal Auth credentials live in ui/.env (gitignored). Developer runs docker compose up—secrets load automatically. No .env.local. No sync step.
npm run env:sync && docker compose up (2 commands)docker compose up (1 command)Secrets never touch disk in a committed file. Refresh? docker compose restart webui.
| Metric | Before | After |
|---|---|---|
| Places to update a secret | 4+ | 1 |
| Manual sync steps | 2 (local + prod) | 0 |
| Secrets in git | Risk of .env.local commit | 0 |
| Audit trail | None | Infisical logs everything |
| Sync targets | — | 4 (local Docker, Fly.io, 2× GitHub) |
An agent can't migrate secrets by clicking UIs. It needs structured access. MCPs gave us that:
listSecrets before/after, confirmed deploys, read logs when something failed.We wrote instructions. The agent executed. No back-and-forth with dashboards. No "I think it's synced."
~/.cursor/mcp.json:
"infisical": {
"command": "npx",
"args": ["-y", "@infisical/mcp"],
"env": {
"INFISICAL_UNIVERSAL_AUTH_CLIENT_ID": "your-client-id",
"INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET": "your-client-secret"
}
}
If you're still juggling .env.local, fly secrets, and gh secret set, it's worth a weekend to consolidate. Infisical + MCPs makes it tractable. And once it's done, you never touch secret sync again.
FRUS — Technical consultancy. We build production systems and write what works.