An ephemeral credential broker for LLM agents, exposed over MCP.
Have questions about the codebase? Ask them on DeepWiki for AI-generated docs and answers about this repository.
Handing long-lived API keys to an LLM agent is a bad idea: keys end up in
transcripts, logs and model context, and once they leak they stay valid until
someone notices and rotates them by hand. ProxyCreds keeps the real
credentials in an encrypted vault and hands agents nothing but opaque,
short-lived tokens (pcx_..., 10-minute TTL by default). The real secret is
injected server-side, at the last possible moment:
- API keys — the agent calls an injection gateway (
/gw/<service>/...) that validates the token, enforces per-grant method/path policies, injects the real key and forwards the request upstream. - Proxy credentials (residential/datacenter proxies) — the agent points a normal HTTP proxy client at the ProxyCreds relay; the relay authenticates the ephemeral token and tunnels through the real upstream proxy.
- SSH access — the agent connects to the ProxyCreds bastion using its token as the SSH password; the bastion opens the real session to the target host with the real key/password and bridges it transparently.
If a token leaks it's usually already expired, it can be revoked in one click, and it's useless anywhere except through ProxyCreds itself.
LLM agent ──MCP──> ProxyCreds ──> encrypted vault (real creds never leave)
│ │
│ pcx_token ├── policies (agent × service × scopes × TTL)
└──network──> gateway / relay / bastion ──real cred injected──> real API / proxy / host
└── audit log (every token event and request)
| Path | Description |
|---|---|
backend/ |
FastAPI control plane, injection gateway, proxy relay, SSH bastion, MCP server (Python 3.12) |
dashboard/ |
Next.js admin dashboard (services, agents, policies, tokens, audit) |
docker-compose.yml |
Full stack: Postgres + backend + dashboard |
cd backend
python -m venv .venv
.venv/Scripts/activate # Windows — use bin/activate on Unix
pip install -r requirements.txt
uvicorn proxycreds.main:app --reload --port 8000In dev, everything you need is created on first run — you don't have to generate anything by hand:
- the SQLite database (
backend/proxycreds.db), - the master key (
backend/.master_key) used for envelope encryption, - the SSH bastion host key (
backend/.bastion_host_key).
The proxy relay (port 8080) and SSH bastion (port 2222) start automatically alongside the API. All three generated files are git-ignored; for production you provide your own master key instead (see below).
cd dashboard
npm install
npm run devOpen http://localhost:3000, create your organization, then:
- Services — add a credential (e.g. a GitHub PAT with upstream base URL
https://api.github.comand formatBearer {secret}), an upstream proxy, or an SSH target. - Agents — create an agent key (
pca_..., shown once). - Policies — grant the agent access to a service with method/path scopes and a TTL.
- Setup MCP — copy the generated MCP config into your agent
(
.cursor/mcp.json, Claude Desktop config, and so on).
{
"mcpServers": {
"proxycreds": {
"command": "python",
"args": ["-m", "proxycreds.mcp_server"],
"env": {
"PYTHONPATH": "/path/to/ProxyCreds/backend",
"PROXYCREDS_API_URL": "http://localhost:8000",
"PROXYCREDS_AGENT_KEY": "pca_<your-agent-key>"
}
}
}
}PYTHONPATH must point at the backend directory so the module resolves. On
Windows — or any setup with a virtualenv — set command to the venv Python
(e.g. C:\...\backend\.venv\Scripts\python.exe) so the dependencies are found.
Restart your agent after editing the config.
Tools exposed to the agent:
| Tool | Description |
|---|---|
list_services() |
Services this agent can reach (names and policies only, no secrets) |
request_access(service, reason) |
Get an ephemeral pcx_ token plus usage instructions |
renew_token(token_id) |
Extend a token before it expires |
release_token(token_id) |
Revoke a token once you're done |
The agent then calls, for example, GET http://localhost:8000/gw/github/user
with Authorization: Bearer pcx_..., and the real PAT is injected server-side.
MCP is optional. The same flow works over a plain HTTP API, so humans, scripts
and CI can share scoped access without ever seeing the real credential. See
README_API.md for the full agent-API reference, with
curl/Python examples for API, proxy and SSH services.
The whole stack — Postgres, backend (API + gateway + relay + SSH bastion) and dashboard — comes up with a single command:
docker compose up -d --buildThen open http://localhost:3000. Exposed ports:
| Port | Service |
|---|---|
| 3000 | Dashboard |
| 8000 | API + injection gateway |
| 8080 | Proxy relay |
| 2222 | SSH bastion |
On first boot the master key and the SSH bastion host key are generated
automatically and stored in a named volume (pc_keys), so they survive
container rebuilds. That's fine for trying it out or a single-host deployment.
For a real production setup, set your own master key so it doesn't live only inside a Docker volume — losing it means losing every stored credential:
cp .env.example .env
# generate a key and paste it into .env as PC_MASTER_KEY:
python -c "import base64,secrets;print(base64.b64encode(secrets.token_bytes(32)).decode())"
# also set POSTGRES_PASSWORD, PC_*_PUBLIC_HOST / URL, then:
docker compose up -d --buildPut a TLS-terminating reverse proxy (Caddy, Traefik, nginx) in front for real
deployments and set PC_GATEWAY_PUBLIC_URL, PC_RELAY_PUBLIC_HOST and
PC_SSH_BASTION_PUBLIC_HOST accordingly.
- Envelope encryption — master key → per-org DEK (AES-256-GCM) → credential secrets. Secrets are decrypted in memory only at injection time and dropped immediately afterwards.
- Opaque tokens —
pcx_tokens are 256-bit random, stored hashed (SHA-256), bound to an agent × service × grant, and TTL-capped (1h max). - Policies — allowed HTTP methods and path globs per grant for APIs, and destination host allow-lists for proxies; denied requests are audited.
- SSRF guard — upstreams that resolve to private, loopback or link-local addresses are rejected, re-checked at request time to defend against DNS rebinding.
- Header scrubbing — agent-supplied
Authorization/Cookieheaders are stripped before forwarding;Set-Cookieand auth headers are stripped from responses. The gateway can also redact the real secret if an upstream echoes it back. - Kill switches — revoke a single token, disable an agent (which revokes all of its tokens), or disable a service.
- Audit — every token issuance, renewal, revocation, gateway request, relay connection, SSH session and policy denial is logged, without secrets.
- Multi-tenant — all data is scoped by organization, with a separate encryption key per org.
- Request-signing schemes (AWS SigV4 and similar) can't be proxied transparently; the plan is to support them through native ephemeral credentials (STS) instead.
- Rate limiting is in-memory per process; move it to Redis for multi-replica deployments.
cd backend
python -m pytest tests -qThe suite covers vault write-only behavior, the token lifecycle (issue/renew/release/revoke), gateway injection against a mocked upstream, policy enforcement (methods and paths), the SSH bastion, audit logging, and tenant isolation.