agent-secret

agent-secret

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.

Category
访问服务器

README

agent-secret

One-time secret share, built for AI agents.

You need to get an API key into your AI agent's environment. Pasting it into the chat means it lives in the transcript, the logs, and the model context — forever. agent-secret fixes the handoff:

  • You get a short claim code like k7f2-9m3q. The code is a pointer, not the secret — safe to paste into any chat.
  • Your agent exchanges the code for the secret programmatically (via an MCP tool) and writes it straight to .env. The value never appears in the conversation.
  • The secret is single-use (burns on claim) and expires fast (10 min by default).

The claim code is safe to share. The secret is not. That asymmetry is the whole product.

30-second happy path

1. Human — store the secret, get a code:

$ npx agent-secret put OPENAI_API_KEY=sk-abc123...

  Claim code:  k7f2-9m3q
  Expires:     2026-07-06T17:27:57Z (10m)
  Single-use:  burns on first claim

  Paste this into your agent chat (the code is safe to share — it is not the secret):

    Claim secret k7f2-9m3q with agent-secret and save it to .env as OPENAI_API_KEY

2. Human — paste that one line into the agent chat.

3. Agent — calls the claim_secret MCP tool with save_to: ".env". The MCP server writes OPENAI_API_KEY=sk-abc123... into .env and tells the agent only:

Claimed k7f2-9m3q: wrote OPENAI_API_KEY to /project/.env. The secret is burned
server-side and its value was not shown.

Done. The secret went human → encrypted store → agent's env file. The chat only ever saw k7f2-9m3q.

Why not just paste it in chat?

Paste the key in chat Paste a claim code
Lands in the transcript / logs forever just a dead pointer
Enters the model context yes code only
Reusable if leaked yes, until you rotate no — single-use + TTL
Revocable no yes (burn, or wait out the TTL)

A leaked claim code is worthless after the agent claims it (or after ~10 minutes). A leaked API key is an incident.

Setup

1. Deploy the Worker (self-host, ~2 minutes)

The backend is a single Cloudflare Worker + KV namespace. Free tier is fine.

git clone <this repo> && cd agent-secret && npm install
npx wrangler kv namespace create SECRETS   # paste the returned id into wrangler.toml
node -e "console.log(crypto.randomBytes(32).toString('base64'))"
npx wrangler secret put MASTER_KEY         # paste the generated key when prompted
npx wrangler deploy

Your endpoint is https://agent-secret.<your-subdomain>.workers.dev. It also serves a tiny web form at / for putting secrets from a browser.

Local dev: copy .dev.vars.example to .dev.vars, fill in a key, then npm run dev.

2. Point the human tools at it

export AGENT_SECRET_URL=https://agent-secret.<you>.workers.dev
npx agent-secret put MY_KEY=value        # or:  npx agent-secret put MY_KEY - < key.txt

Tip: the put NAME - < file / pipe form keeps the value out of your shell history.

3. Add the MCP server to your agent

Not on npm yet. Until agent-secret is published, run the MCP server from your built checkout: npm run build once, then point the command at dist/mcp/server.js (absolute path). The npm/npx forms below light up the moment it's published.

From your checkout (works today):

{
  "mcpServers": {
    "agent-secret": {
      "command": "node",
      "args": ["/absolute/path/to/agent-secret/dist/mcp/server.js"],
      "env": { "AGENT_SECRET_URL": "https://agent-secret.<you>.workers.dev" }
    }
  }
}

Once published to npm — Claude Code:

claude mcp add agent-secret \
  -e AGENT_SECRET_URL=https://agent-secret.<you>.workers.dev \
  -- npx -y --package agent-secret agent-secret-mcp

Claude Desktop / any MCP client (mcpServers config):

{
  "mcpServers": {
    "agent-secret": {
      "command": "npx",
      "args": ["-y", "--package", "agent-secret", "agent-secret-mcp"],
      "env": { "AGENT_SECRET_URL": "https://agent-secret.<you>.workers.dev" }
    }
  }
}

The server exposes two tools:

  • claim_secret(code, passphrase?, save_to?, env_name?) — claims and burns. With save_to (e.g. ".env") the MCP server writes NAME=value into that file itself and the value never enters the model context. Without save_to the value is returned inline (with a warning). Always prefer save_to.
  • put_secret(name?, value, ttl_seconds?, passphrase?) — the reverse direction: the agent stores a secret and hands back a chat-safe claim code.

CLI reference

agent-secret put [NAME=]VALUE [--ttl 10m] [--passphrase X]   create, print claim code
agent-secret put NAME - < file                               value from stdin
agent-secret claim CODE [--passphrase X]                     claim (burns); value on stdout
agent-secret meta CODE                                       status — never shows the value
agent-secret burn CODE                                       destroy without claiming

--url overrides AGENT_SECRET_URL. TTL accepts 90s / 10m / 2h / 1d (default 10m, min 60s, hard max 24h). meta is handy for the human: it flips to "Claimed at …" the moment the agent picks the secret up.

API

Route Body Returns
POST /secret {value, name?, ttl?, passphrase?} 201 {code, expiresAt, ttl}
POST /secret/:code/claim {passphrase?} 200 {name?, value} once; 401 wrong/missing passphrase; 404 unknown; 410 claimed/expired
GET /secret/:code/meta — {exists, claimed?, hasPassphrase?, expiresAt?} — never the value
DELETE /secret/:code — 204

Security model

  • Encrypted at rest — AES-256-GCM via Web Crypto before the value touches KV. Key derived per-secret (random salt + IV) from a MASTER_KEY that lives only in Worker secrets, so a KV data leak alone exposes nothing. The stored name is encrypted too.
  • Optional passphrase (you rarely need it) — off by default and safe to ignore. Single-use + a short TTL already make an intercepted code near-worthless, so a passphrase only earns its keep in one case: the claim code leaks and an attacker claims it inside the TTL window before your agent does (e.g. a shared chat log claimed within minutes). When you do use it, it's mixed into the key derivation (PBKDF2-SHA256, 100k iterations) — a wrong passphrase just fails decryption; nothing passphrase-derived is stored, and five wrong attempts destroy the secret. Share it out-of-band, not in the same chat as the code.
  • Single-use + TTL — burns on first claim; expires at TTL (default 10 min, max 24h) regardless.
  • Rate limiting — per-IP, per-minute across all /secret* routes (default 30/min, RATE_LIMIT_PER_MIN var) against code enumeration and passphrase guessing.
  • Codes — 8 chars from a confusable-free alphabet ≈ 2^39 space; combined with rate limits and short TTLs, online guessing is not practical.

Honest limitations (v1)

  • The server sees plaintext at put/claim time. Encryption protects data at rest in KV; it is not end-to-end. Self-host so the operator is you. E2E (client-side encryption, passphrase-only keys) is a natural v2.
  • Strict single-use vs. agent retries. A retry after a successful claim gets 410 already_claimed — the MCP client must use the value from the first response (the tool description says so; the save_to flow makes retries moot since the file is already written). KV is also eventually consistent, so two simultaneous claims racing across edge locations could, in a narrow window, both succeed; a Durable-Object-backed strict burn is the v2 fix if that matters to you.
  • put NAME=VALUE as a CLI arg can land in shell history — use the stdin form (put NAME - < file) or the web form for high-value keys.

Development

npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest — create/claim/burn/expiry/passphrase/meta/rate-limit/crypto
npm run dev         # wrangler dev (needs .dev.vars, see .dev.vars.example)
npm run build       # emit dist/ (CLI + MCP bins)

Layout: single package — src/worker (Hono app + crypto), src/mcp (stdio MCP server), src/cli, src/shared (HTTP client used by both).

Naming

Shipping as agent-secret for now. Candidate brand names if this grows up: Claimcode, Burnbox, Keydrop, Deadrop.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选