envpact-mcp-server

August 13, 2026 · View on GitHub

Bring your private, Git-backed secrets vault to any AI coding agent — generate .env files on demand, never paste an API key into a prompt again.

License: MIT Stars Last commit TypeScript npm version CI Live

Model Context Protocol server for envpact — bring centralized secret management to AI coding agents (Cursor, Windsurf, Claude Code, Cline, Goose, ChatGPT Desktop, and any other MCP-aware client).

Stop pasting API keys into prompts. Let your agent generate .env files from your private vault on demand.

Links: Repo · Live docs · envpact umbrella · Dashboard

Part of the envpact ecosystem.

If this is useful, please star the repo — it helps other developers find it.

Architecture

flowchart LR
    subgraph agent["AI coding agent"]
        A[Cursor / Windsurf / Claude Code / Cline]
    end
    subgraph mcp["envpact-mcp (this server)"]
        T[MCP tools: generate_env, pull/push_secret,<br/>add_secret, rotate_secret, sync_github, ...]
    end
    vault[(~/.envpact/secrets/<br/>private GitHub vault)]
    envf[.env file in project]
    gha[GitHub Actions secrets]

    A -- MCP stdio / HTTP --> T
    T -- read/resolve --> vault
    T -- write --> envf
    T -- sync_github --> gha
    worker["Cloudflare Worker<br/>(remote SSE / Streamable HTTP)"] -. same 11 tools .-> vault
    A -. MCP over HTTP .-> worker

What it does

When you ask your AI agent "set up a Next.js project that uses OpenAI and Stripe", modern agents can scaffold the code but get stuck at the .env step. With envpact-mcp installed:

  • The agent sees your project's .env.example requirements.
  • It calls generate_env and the file is written from your private vault.
  • New keys it discovers are added back to the vault via add_secret/add_shared_secret.
  • Optionally syncs to GitHub Actions via sync_github so CI works end-to-end.

You never paste a secret into an agent prompt.

Installation

The MCP server is published to npm as envpact-mcp. Configure your AI client:

Claude Desktop / Claude Code

~/.config/claude/claude_desktop_config.json:

{
  "mcpServers": {
    "envpact": {
      "command": "npx",
      "args": ["-y", "envpact-mcp"]
    }
  }
}

Cursor

.cursor/mcp.json in your project, or ~/.cursor/mcp.json globally:

{
  "mcpServers": {
    "envpact": {
      "command": "npx",
      "args": ["-y", "envpact-mcp"]
    }
  }
}

Windsurf

~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "envpact": {
      "command": "npx",
      "args": ["-y", "envpact-mcp"]
    }
  }
}

Cline (VS Code)

In Cline's MCP settings panel, add a stdio server with command npx and args ["-y", "envpact-mcp"].

Prerequisites

You need an envpact vault. If you don't have one yet:

npx envpact-cli --init auto
# Creates chirag127/envpact-secrets (private) and clones it to
# ~/.envpact/secrets/ — same vault every component reads.

Available Tools

ToolDescription
generate_envResolve secrets, write .env for the current project.
list_projectsList all projects in the vault.
list_sharedList shared secret names (values are masked).
add_secretAdd/update a project secret.
add_shared_secretAdd/update a shared secret.
rotate_secretRotate a shared secret; reports affected projects.
sync_githubPush resolved secrets to GitHub Actions.
pull_secretPull one key from vault → .env (per-key, conflict-safe).
push_secretPush one key from .env → vault (per-key, conflict-safe).
sync_statusReport per-key sync status across .env.example.
generate_global_envMirror every shared secret into ~/.envpact/.env (v3.1).

Schema details: see SHARED_SPEC §7.

v3.1 UX additions

  • Dual-render timestamps (UTC + IST). Every conflict refusal from pull_secret / push_secret and every entry in sync_status now carries the canonical UTC ISO string AND a human IST rendering (YYYY-MM-DD HH:MM:SS IST). Conflict payloads also expose recommended_side: "vault" | "local" set to whichever side is newer. The user keeps the final decision; recommended_side is just a hint.
  • Global vault .env. generate_global_env mirrors every shared.* entry into a single file at ~/.envpact/.env, generated from ~/.envpact/.env.example.global (auto-created on first run, byte-faithful template format). Encrypted values emit # KEY: encrypted comments; missing keys emit # KEY: not in vault. Output is mode 0600 (best-effort on Windows).

Per-key Sync (v3)

The vault is flat and single-environment per project with {value, _modified_at} entries. The agent can sync one key at a time without touching the rest of .env:

You: "Pull the latest OPENAI_API_KEY from the vault."

Agent: calls pull_secret({key: 'OPENAI_API_KEY'}) → writes the new value to .env, updates .env.example.lock. If you'd edited .env since the last sync, the call returns an isError payload with status: 'local_newer'; the agent retries with force: true only after asking you.

You: "What's the sync status of this project?"

Agent: calls sync_status() → reports each key as synced / local_newer / vault_newer / both_diverged / local_only / vault_only. NEVER returns values.

Example Agent Conversations

You: "Set up envpact for this project. The .env.example needs OPENAI_API_KEY and DATABASE_URL."

Agent: calls generate_env.env written, missing DATABASE_URL. Asks: "Should DATABASE_URL be a shared secret or project-specific?"

You: "Shared, value is postgres://prod-host/db."

Agent: calls add_shared_secret({key: 'DATABASE_URL', value: '...'}), then add_secret({project: 'this-app', key: 'DATABASE_URL', value: 'shared.DATABASE_URL'}), then generate_env again. Done — .env complete.

You: "OPENAI_API_KEY was leaked. Rotate it everywhere."

Agent: calls rotate_secret({key: 'OPENAI_API_KEY', new_value: 'sk-new...'}) → reports 12 affected projects. Calls sync_github for each.

Remote / SSE Variant

A Cloudflare Worker variant supporting MCP over Streamable HTTP is deployed at https://mcp.envpact.oriz.in/mcp and listed on Smithery at https://smithery.ai/server/@chirag127/envpact-mcp. The Worker exposes the same 11 tools, with two natural Worker deviations: pull_secret returns the resolved value as the response text body (no .env to write), and generate_global_env returns the rendered global .env body as text instead of writing to disk. See worker/README.md for the full deviation list.

Security Model

  • Vault values never leave your machine in tool responses — only the tool params (e.g. when you ask the agent to set a value) carry plaintext.
  • list_shared returns only names; values are never echoed.
  • The MCP server reads/writes ~/.envpact/secrets/ directly. The vault is your existing private GitHub repo.
  • All vault commits are signed-off (-s) and authored by envpact-mcp.

Tech stack

  • Node.js (>=18), TypeScript/ESM, pnpm workspace.
  • @modelcontextprotocol/sdk for the MCP server; zod for tool schemas.
  • Cloudflare Worker (worker/) for the remote SSE / Streamable-HTTP variant.
  • Packaged as .mcpb bundle and published to npm as envpact-mcp.

Repo structure

src/            # MCP server (stdio) — tool handlers
worker/         # Cloudflare Worker (remote SSE / Streamable HTTP variant)
mcpb/           # .mcpb bundle manifest + build
docs/           # full API + usage reference (served at *.oriz.in)
scripts/        # test + build-mcpb helpers
server.json     # official MCP registry descriptor
smithery.yaml   # Smithery listing config
RepoRole
envpactCore (Python) vault library
envpact-npm-cliZero-dependency Node CLI (envpact-cli)
envpact-mcp-serverMCP server for AI agents (this repo)
envpact-gh-actionGitHub Action — resolve secrets in CI
envpact-registry-publisher-npm-cliPublish MCP servers to every registry

Part of the oriz family

One of ~80 oriz projects — small, sharp, open-source tools. The live docs run $0 on the Cloudflare free tier.

Contributing

PRs welcome — see CONTRIBUTING.md. Conventional commits are the changelog.

Status

Stable. Published to npm; remote Worker variant listed on Smithery.

License

MIT © 2026 Chirag Singhal · chirag@oriz.in — see LICENSE.

Documentation