Agent Secret
FreeNot checkedMCP server for one-time secret sharing, enabling AI agents to securely claim and store secrets (e.g., API keys) via claim codes without exposing them in chat tr
About
MCP server for one-time secret sharing, enabling AI agents to securely claim and store secrets (e.g., API keys) via claim codes without exposing them in chat transcripts.
README
█████╗ ██████╗ ███████╗███╗ ██╗████████╗
██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝
███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║
██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║
██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝
███████╗███████╗ ██████╗██████╗ ███████╗████████╗
██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝╚══██╔══╝
███████╗█████╗ ██║ ██████╔╝█████╗ ██║
╚════██║██╔══╝ ██║ ██╔══██╗██╔══╝ ██║
███████║███████╗╚██████╗██║ ██║███████╗ ██║
╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝
· zero-knowledge · one-time · self-destructing ·
v1.0.0
Cloudflare Workers Zero-knowledge Agent needs just a fetch License
encrypt in the browser · hand your agent a self-destructing link · the server never sees it
⚡ what it does
You need to get an API key into an AI agent. Paste it into the chat and it lives in the transcript, the logs, and the model context — forever. agent-secret fixes the handoff:
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ [ YOU ] [ agent-secret ] [ YOUR AGENT ] │
│ │
│ type secret ──encrypt──▶ stores only ──fetch──▶ fetches + │
│ in browser in browser ciphertext + iv one time decrypts │
│ (never the key) locally │
│ │
│ 🔥 burns on first read │
└──────────────────────────────────────────────────────────────────────────┘
The encryption key is generated in your browser and lives only inside the instruction you hand your agent. It never touches the server. So a full database dump — or a subpoena, or a rogue operator reading the source — recovers nothing but ciphertext. That's the whole product.
✦ the flow
1. You open agent-secret.xndr.io, type the secret + an optional name, hit Encrypt. One click copies a block that's deliberately tiny — one line and one link:
OPENAI_API_KEY — one-time secret (agent-secret). Single GET burns it; then AES-256-GCM
decrypt: response {ct,iv} base64, key = URL #fragment (base64url), ct = ciphertext+16-byte
tag, plaintext = the value.
https://agent-secret.xndr.io/k7f2-9m3q#Xy9…KEY
2. You paste that into your agent's chat.
3. Your agent GETs the link (curl and fetch drop the #fragment, so the server only sees /k7f2-9m3q), decrypts the returned {ct,iv} with the key from the fragment, and writes the value wherever it keeps secrets. The value never went through the model as something you typed, and the link is now dead.
The whole handoff is one link:
agent-secret.xndr.io/<code>#<key>. The key rides in the fragment — which browsers,curl, andfetchnever transmit — so it reaches your agent but never the server.
🔒 how it stays zero-knowledge
╭──────────────────────────────────────────────────────────────────────────╮
│ │
│ ◆ CLIENT-SIDE CRYPTO AES-256-GCM in the browser (WebCrypto). Only │
│ ciphertext + a random nonce are ever POSTed. │
│ │
│ ◆ KEY NEVER SENT the 256-bit key is generated in-page and baked │
│ into the copy block. The server can't derive, │
│ log, or store it — it never arrives. │
│ │
│ ◆ SINGLE-USE the first GET returns the ciphertext and writes │
│ a tombstone in the same step. Read #2 → 410. │
│ │
│ ◆ SHORT TTL 5 min – 24 h, auto-purged from KV on expiry. │
│ │
│ ◆ RATE LIMITED per-IP fixed window blunts code enumeration. │
│ │
│ ◆ NO SERVER SECRETS the Worker holds no keys of its own. Read the │
│ source — nothing there can read a stored secret. │
│ Verifiable, not a promise. │
│ │
╰──────────────────────────────────────────────────────────────────────────╯
Threat model, honestly. The claim code and the decryption key travel together inside the block you paste. Whoever holds that block can decrypt — exactly once — so treat it like the secret until your agent has claimed it. If an interceptor reads it first, your agent's fetch usually fails (410) — tamper tends to be loud. One caveat: single-use is best-effort, not atomic — Workers KV has no compare-and-set, so a claim racing your agent within KV's short propagation window may not be detected (front the claim with a Durable Object if you need strict once-only). What the server cannot do, by construction, is read your secret — at rest or in flight.
Unfurl-safe. Pasting the link into Telegram, Slack, Discord, etc. is fine — their preview crawlers are detected and served a no-op, so they never burn the secret. (They couldn't read it anyway: crawlers don't send the
#fragment.)
🤖 for the agent
No install, no MCP, no SDK. Given the link https://agent-secret.xndr.io/<code>#<key>, an agent needs one HTTP GET and a standard AES-256-GCM decrypt:
GET https://agent-secret.xndr.io/<code> # send WITHOUT the #fragment (curl/fetch already drop it)
→ 200 {"ct":"<base64>","iv":"<base64>"} (and the secret is now burned)
→ 410 already_claimed | expired
→ 404 not found
decrypt: AES-256-GCM
key = base64url-decode(<the #fragment>) # 32 bytes
nonce = base64-decode(iv) # 12 bytes
tag = last 16 bytes of base64-decode(ct)
data = base64-decode(ct) minus the tag
plain = the secret value (UTF-8)
Many libraries (WebCrypto, Python
cryptography) takectwith the tag appended — passbase64-decode(ct)whole and skip the manual split. OpenSSL/Node-style APIs want the tag separated, as shown.
🛰 api
| Method | Path | Purpose |
|---|---|---|
GET |
/ |
The share form (all crypto runs here). |
POST |
/ |
Create. Body { ct, iv, ttl? } (base64 ciphertext + nonce). → { code, expiresAt, ttl } |
GET |
/:code |
Claim + burn. → { ct, iv } once, then 410. (Preview crawlers get a no-op.) |
GET |
/:code/meta |
Lifecycle only — { exists, claimed?, expiresAt? }. Never ciphertext. |
DELETE |
/:code |
Destroy immediately. |
🚀 self-host
It's a single Cloudflare Worker + one KV namespace. No secrets to configure — the server is stateless about keys by design.
$ git clone https://github.com/mrcsXndr/agent-secret && cd agent-secret
$ npm install
# In wrangler.toml: set your own account_id, and replace (or remove) the
# [[routes]] block with your domain — the shipped values are XNDR's.
$ npx wrangler kv namespace create SECRETS # paste the id into wrangler.toml
$ npx wrangler deploy
$ npm run dev # local: http://localhost:8787
$ npm test # vitest — incl. full E2E round-trip
RATE_LIMIT_PER_MIN (default 30) is the only knob, in wrangler.toml.
🧱 stack
Cloudflare Workers · Hono · Workers KV · WebCrypto (AES-256-GCM) · TypeScript · Vitest — no runtime dependencies beyond Hono.
Installing Agent Secret
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/mrcsXndr/agent-secretFAQ
Is Agent Secret MCP free?
Yes, Agent Secret MCP is free — one-click install via Unyly at no cost.
Does Agent Secret need an API key?
No, Agent Secret runs without API keys or environment variables.
Is Agent Secret hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Agent Secret in Claude Desktop, Claude Code or Cursor?
Open Agent Secret on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Gmail
Read, send and search emails from Claude
by GoogleSlack
Send, search and summarize Slack messages
by SlackRunbear
No-code MCP client for team chat platforms, such as Slack, Microsoft Teams, and Discord.
Discord Server
A community discord server dedicated to MCP by [Frank Fiegel](https://github.com/punkpeye)
Compare Agent Secret with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All communication MCPs
