Migrate from .env Chaos to Infisical — AI-Led, MCP-Powered

# How We Migrated from Local Env Chaos to Infisical—AI-Led, MCP-Powered **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. ![Infisical Cloud diagram integrating Local Docker, Fly.io, GitHub Actions.](https://lwhufeayzfcmjeejetty.supabase.co/storage/v1/object/public/blog-images/1770476329884-infisical-architecture-hub.webp) ## The Before State Secrets were everywhere. And nowhere consistent. - **Local dev**: `.env.local` copied from someone else's machine or a wiki. Sometimes committed by accident. Often stale. - **Production (Fly.io)**: `fly secrets set` run manually. 18 secrets. No record of who set what or when. - **CI/CD**: GitHub Actions secrets in two repos—`k2k-mega-foundation` (deploy) and `k2k-sidekick` (release). Same keys, different values sometimes. Or missing. - **Rotation**: Update a Supabase key? That's four places. Five if you count the wiki. No audit trail. Drift between environments. The classic mess. ## Why Infisical (And Why Now) We needed one place to store secrets and one way to push them out. Infisical gives you: - **Single source of truth** — Update once, sync everywhere. - **Native integrations** — Fly.io and GitHub Actions sync directly from Infisical. No custom scripts. - **MCP server** — The Infisical MCP lets an AI agent read, create, update, and delete secrets without you touching a UI. That last point mattered. We didn't want a migration we'd babysit. We wanted the agent to do it. ## MCPs: The Engine of the Migration 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. ### Infisical MCP - **list-secrets**, **get-secret**, **create-secret**, **update-secret**, **delete-secret**. Project and environment aware. We used it to: - Audit what we had in `.env.local` and compare to Infisical - Add missing secrets - Verify sync targets ### Fly MCP - **listSecrets**, **setSecrets**, **deploySecrets**, **getLogs**, **listMachines**. We used it to: - Check Fly.io secrets before and after Infisical sync - Confirm deployment after the cutover - Debug when something looked wrong ### GitHub MCP - We used it to confirm Actions secrets were populated from Infisical. No more manual `gh secret set`. The agent didn't guess. It called tools, got data, and acted on it. ## Phase 1: Centralize and Sync ### Goal: Get all secrets into Infisical and auto-sync to Fly.io and GitHub Actions. - **Create Infisical project** — Two environments: local (dev) and prod (Fly + CI). - **Migrate secrets** — Agent used Infisical MCP to `create-secret` for each key we had in `.env.local` and Fly. 18 secrets in prod, 14 in local. - **Wire integrations**: - **Fly.io**: Infisical native integration. Select app `k2k-foundation`, connect, enable auto-sync. Done. - **GitHub Actions**: Same. Connected `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. ### Result: Rotate a secret in Infisical → it propagates to Fly.io and both GitHub repos. One change, four targets. ## Phase 2: Kill the Manual Sync for Local Dev 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: ```bash #!/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. - **Before**: `npm run env:sync && docker compose up` (2 commands) - **After**: `docker compose up` (1 command) Secrets never touch disk in a committed file. Refresh? `docker compose restart webui`. ## The Numbers | 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) | ## MCP + AI: Why It Worked An agent can't migrate secrets by clicking UIs. It needs structured access. MCPs gave us that: - **Infisical MCP** — Agent listed existing secrets, created new ones, verified sync behavior. - **Fly MCP** — Agent checked `listSecrets` before/after, confirmed deploys, read logs when something failed. - **GitHub MCP** — Agent verified Actions secrets were populated. We wrote instructions. The agent executed. No back-and-forth with dashboards. No "I think it's synced." ## What You Need to Replicate This - **Infisical account** — Free tier is enough to start. - **Universal Auth** — For Docker (local) and MCP. Create a Machine Identity, get Client ID + Secret. One identity for CLI/entrypoint, one for the Cursor Infisical MCP if you want the agent to manage secrets. - **Infisical MCP in Cursor** — Add to `~/.cursor/mcp.json`: ```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" } } ``` - **Fly + GitHub integrations** — In Infisical, connect Fly.io and GitHub. Point them at your app and repos. Enable auto-sync. ## Takeaways - MCPs make infrastructure automatable. Structured tools beat scraping CLIs or UIs. - Infisical as hub works. One update, four destinations. No custom glue. - Docker entrypoint + Universal Auth removes the local sync step entirely. Secrets load at startup. No files to manage. - AI-led migration is real. With the right tools (MCPs), an agent can run the migration, verify syncs, and confirm deploys. You define the plan; the agent executes it. 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.*