blog · 10 September 2026 · 7 minutes
ProxyKey MCP: giving an AI agent API access without handing over a key
We already wrote about why a credential proxy exists and why "zero-knowledge" is impossible for one by design — that proxy is ProxyKey, our own project. This post is the practical follow-up: how to connect Claude Code or Cursor to ProxyKey over MCP, what the 13 available tools are, why "read the key" is deliberately not one of them, and how the scenario we built all of this for actually plays out — an agent deploying a bot that doesn't have a token yet.
Why an agent needs MCP to a vault, not just a key in .env
An agent like Claude Code or Cursor lays out environment variables, writes configs, and sometimes logs what it's doing. Anything that enters a model's context has to be treated as published: context gets logged, traced, and can be pulled out through prompt injection. Handing that agent a live OpenAI key or a Telegram bot token is functionally the same as handing it to a random script on the internet.
The ProxyKey MCP server solves this at the protocol level, not with a policy the agent is trusted to follow. The agent gets a tool, not a secret. None of the 13 methods has an operation that returns a key's value. The agent can create, revoke, and rotate passes, and inspect limits and request logs — but it cannot read the original, because that endpoint simply doesn't exist in the API.
Connecting: Claude Code and Cursor
The first step is a human one: sign in at
app.proxykey.org
(GitHub OAuth or a magic link, free), open the MCP section, and create a
token in the form mcp_…. Only that token goes to the agent —
never the real provider keys.
For Claude Code, one command:
claude mcp add --transport http proxykey https://mcp.proxykey.org/mcp \
--header "Authorization: Bearer mcp_YOUR_TOKEN"
For Cursor and Claude Desktop, an entry in mcp.json:
{
"mcpServers": {
"proxykey": {
"url": "https://mcp.proxykey.org/mcp",
"headers": { "Authorization": "Bearer mcp_YOUR_TOKEN" }
}
}
}
From there the agent sees ProxyKey's tools like any other MCP tools and can call them on its own, without a human in the loop on every step.
13 tools — and why "read the key" is not one of them
The full set of what's exposed to the agent over MCP:
Catalogue and metadata
list_providers lists providers and their auth model. list_secrets shows stored keys, metadata only, never values. get_manual_secret_setup returns a link for a human to enter the real key.
Pass management
create_pass, create_pending_pass, update_pass, rotate_pass, revoke_pass, delete_pass, rebind_pass_ip — the full lifecycle of a virtual token.
Observability
list_passes, get_pass_logs, get_pass_stats — the agent sees each pass's status, limits, IP binding, and request history.
Notice: none of the 13 operations has a parameter that returns a secret's value. This isn't "the agent has agreed not to look" — that capability simply isn't in the API contract. For the same reason, the MCP surface can't turn on request-body logging either — that stays human-only in the panel, because otherwise a key could be reconstructed indirectly through the logs.
The pending-secret scenario: an agent deploys a bot without a token
This is the exact reason we built all of this. A common situation: an agent is deploying a Telegram bot, writing the code, wiring up the webhook — but there's no BotFather token yet, because the bot hasn't been created.
Instead of stalling and waiting on a human, the agent calls
create_pending_pass. The pass (vlt_…) is issued
immediately and can go straight into the bot's config — but proxying real
traffic is blocked with the status original_key_required until
the secret is filled in. The agent then calls
get_manual_secret_setup and hands the resulting link to a
human.
The human opens the panel, pastes in the real token once, and the pass activates automatically — no second call from the agent required. The bot comes alive. At no point did the agent see the secret's value; it went through the panel, not through the model's context.
What a human sees in the panel
The panel is the only place a real key's value ever lands — the form used for initial setup or for filling in a pending secret. From there the interface shows the list of stored secrets (metadata only, no values), the list of passes with their status, IP binding and limits, and a per-pass request log — metadata, with no authorization headers and no key material.
The split is simple: anything that could expose a secret's value is human-only, through the panel. Anything the agent needs for day-to-day work — issuing, revoking, rotating, monitoring — is available over MCP.
The proxy call itself
Once a pass is issued, the application or agent points at the proxy instead of the provider — only the host and the key change; the path and body stay the same:
# before
curl https://api.openai.com/v1/chat/completions -H "Authorization: Bearer sk-..."
# after
curl https://api.proxykey.org/p/openai/v1/chat/completions -H "Authorization: Bearer vlt_openai_..."
Streaming (SSE), request bodies, and headers pass through unchanged.
Telegram bots keep their usual URL shape:
/p/telegram-bot/<pass>/getMe.
A limitation worth stating plainly
A hosted proxy cannot be zero-knowledge by design: to put a key into a request to the provider, the proxy has to decrypt it in memory at the moment it handles that request. Which means a process with full access — and, by extension, the service operator — can in principle obtain the plaintext. That isn't a bug specific to ProxyKey; it's a property of every hosted solution in this category. We covered this in detail on the security page: what the encryption actually protects against (a database leak, a stolen backup, a log leak) and what it doesn't (a fully compromised server). The agent's MCP access doesn't add new risk on top of that — if anything it's more restricted than a human's access through the panel.
When you don't need this
- You have one key and one consumer. If a key is used in a single place you fully control and no agent ever touches it, a proxy just adds a point of failure with no real upside.
- Your threat model won't tolerate a third party in the request chain. The proxy sees the traffic, even if it only logs metadata. If that's unacceptable, run your own instance of the pattern, or skip it entirely.
- Latency in the single-digit milliseconds actually matters. The extra hop plus a validation-cache lookup adds overhead. For LLM calls it's invisible against the generation time; for some low-latency, non-LLM APIs it can matter — worth running the numbers yourself.
The takeaway
The model is simple: a secret enters the system exactly once, through the panel, and never leaves the server in plaintext again. The agent gets a tool with a deliberately narrow contract — everything it needs to automate issuing and managing access, and nothing that could leak through the model's context. For agents that deploy their own services and bots, that removes the usual blocker — what to do about a key the agent doesn't have yet — without a human on every step.
Setting up agent access to external APIs?
Tell us what services and bots your agent deploys — we'll point out where you still need a human in the loop and what can safely be handed to a tool.
Telegram · @juzubiyyah