MCP 配置里的明文令牌:如何把它们移出去
各编码代理把 MCP 服务器设置保存在哪里,如何找出写在其中的令牌,zn-gate init --wrap-mcp 如何处理它们(不会删除),以及如何移出这些值并撤销每一步。
MCP 服务器常常需要一个令牌,最快的给法是把它粘贴到代理配置文件里该服务器的 env 或 headers 中。这样令牌就留在你个人文件夹或项目里的一个纯文本文件中。本页列出各代理把该文件放在哪里,说明如何在其中找出令牌,解释 zn-gate init --wrap-mcp 对它们做什么、不做什么,并说明如何移出这些值以及如何撤销每一步。关于密钥与编码代理的整体情况,请见检查清单指南。
各代理把 MCP 服务器保存在哪里
| 代理 | 用户文件 | 项目文件 | init --wrap-mcp 会改写 |
|---|---|---|---|
| Claude Code | ~/.claude.json |
项目根目录的 .mcp.json |
~/.claude.json |
| Claude Desktop | claude_desktop_config.json(macOS ~/Library/Application Support/Claude/,Windows %APPDATA%\Claude\,Linux ~/.config/Claude/) |
无 | 该文件 |
| Cursor | ~/.cursor/mcp.json |
.cursor/mcp.json |
~/.cursor/mcp.json |
| Codex CLI | ~/.codex/config.toml(或 $CODEX_HOME/config.toml) |
.codex/config.toml(仅限受信任的项目) |
用户文件 |
| OpenCode | ~/.config/opencode/opencode.json (或 opencode.jsonc) |
项目中的 opencode.json |
用户文件 |
| Antigravity | ~/.gemini/config/mcp_config.json |
.agents/mcp_config.json |
用户文件(zn-gate 也会查找 ~/.gemini/antigravity/mcp_config.json) |
~/.claude.json 还在 projects 下保存只针对单个项目配置的服务器。init --wrap-mcp 只包装该文件顶层的 mcpServers,所以各项目下的条目不会被包装;audit 会检查它们。
Claude Code、Cursor、Codex CLI 和 OpenCode 的路径来自各代理自己的文档;Claude Desktop 和 Antigravity 的路径依据 zn-gate 的文档和 Antigravity 页面。init --wrap-mcp 不会改动项目文件:项目文件里的令牌原样保留。关于 VS Code、Windsurf、Cline、Zed、JetBrains 和 Continue,请见编辑器。
找出令牌
npx -y zn-gate reach
npx -y zn-gate audit --include-home
reach 需要 zn-gate 1.12.0 或更高版本。两者都是只读的。它们会报告写在代理配置中的密钥值(规则 ZNA011),并且从不打印该值。在项目文件夹中运行 audit 还会检查该项目的文件;--include-home 会加入上表中位于你个人文件夹的文件(Claude Desktop 和 Antigravity 的除外)。两者都使用 zn-gate 自己的检测,因此格式它不认识的令牌可能被漏掉:请你自己也读一遍配置文件。
zn-gate init --wrap-mcp 如何处理令牌
它不会删除令牌。对每个本地(stdio)服务器,它只改启动命令:原命令变成 npx -y zn-gate shield -- 的参数。条目中的其余内容,包括 env,保持原样。shield 随后检查工具描述、调用参数和工具输出,并在你的代理读取之前,从输出中移除它能识别的密钥(详情)。这保护的是代理从服务器收到的内容,而不是这个文件。
关于该命令的其他事实:
- 远程(URL)服务器保持不变,因此
headers条目里的令牌依然在。 - 写入文件之前,它会在原文件旁复制一份,命名为
<文件>.bak.<时间戳>。这份副本是文件原来的样子,包含令牌。 - 带注释的 OpenCode 文件和
args跨多行的 Codex 条目不会被改写;init会把它们报告为 "wrap manually"。
npx -y zn-gate init --dry-run # 预览,不做任何更改
npx -y zn-gate init --shadow # 包装,只记录
npx -y zn-gate init --wrap-mcp # 包装并强制执行
npx -y zn-gate init --revert # 恢复每个文件最近的备份
把值移出去
把令牌放进环境变量,让配置按名称引用它。各代理文档的说法如下:
- Claude Code,在
.mcp.json中:${VAR}(以及${VAR:-default})会在command、args、env、url和headers中展开。对于远程服务器的url和headers,Claude Code 的文档对凭据变量另有限制;在那里依赖这一做法之前请先阅读。 - Cursor,在
mcp.json中:${env:NAME}会在command、args、env、url和headers中解析。 - Codex CLI,在
config.toml中:env_vars把 Codex 环境中的变量转发给 stdio 服务器,bearer_token_env_var指定保存 bearer 令牌的变量名,env_http_headers把请求头名称对应到变量名。文件里只保存名称。 - OpenCode:配置文件中会替换
{env:VARIABLE_NAME},其 MCP 文档在请求头中展示了它。 - Claude Desktop、Antigravity 和其他编辑器:我们没有验证在它们的 MCP 文件中引用环境变量的方法,所以本页不提供。
Cursor 示例,服务器和变量均为虚构(EXAMPLE_API_TOKEN):
{
"mcpServers": {
"example": {
"command": "npx",
"args": ["-y", "example-mcp-server"],
"env": { "EXAMPLE_API_TOKEN": "${env:EXAMPLE_API_TOKEN}" }
}
}
}
该变量必须存在于代理进程的环境中:在你启动代理的地方设置它(你的 shell 配置文件,或操作系统设置变量的方式),重启代理,并检查服务器是否连接成功。请注意,shell 配置文件本身也是代理可以读取的纯文本文件,把令牌放在那里只是把它挪到了另一个文件。更好的做法是使用操作系统的钥匙串或密钥管理工具,在启动代理时提供该变量;至少也要把令牌放在代理打开的任何文件夹之外的文件里。
稳妥的顺序
- 运行
npx -y zn-gate reach,记下哪些文件里有令牌。 - 按上文把每个令牌换成环境变量引用,并重启代理。
- 如果该文件曾被提交、备份、共享或推送,或者代理曾能读取它,或者令牌出现在了某份对话记录中,请轮换所有曾在其中出现过的令牌。你从文件里删掉的值,在你到服务商处吊销之前仍然有效。
- 这之后再运行
npx -y zn-gate init --dry-run,然后--shadow,然后--wrap-mcp。它写下的备份里是不含令牌的文件。 - 如果你是先包装的:令牌移出之后,删除配置文件旁的
.bak.<时间戳>文件,因为它们仍然保存着旧值。 - 再次运行
npx -y zn-gate reach。
zn env shadow 的用途与非用途
zn env shadow .env 会把 .env 文件中的值移入 zn-gate 的本地保险库,并在文件里留下标记(Scrubber)。它读取 KEY=value 形式的行。MCP 配置文件是 JSON 或 TOML,zn-gate 的文档没有描述把 env shadow 用于它们,所以不要对它们使用。
如何撤销每一步
- 包装:
npx -y zn-gate init --revert会把最近的.bak.<时间戳>复制回每个配置文件。你在包装之后对文件所做的任何修改都会丢失;如果备份里有令牌,它们也会回来。完成上面的第 2 步之后,请改为手动撤销:在每个条目中,把原来的命令和参数放回npx -y zn-gate shield --的位置。 - 环境变量引用: 只有迫不得已才把值放回文件,并且绝不要放进你会提交的文件。
env shadow:zn env unshadow 文件 --backup 名称,名称为env shadow打印出的那个。
局限
- 检测只能找出已知格式;没有已知格式的令牌可能被漏掉。
- 包装检查的是服务器返回的内容和代理发给它的内容,并不能阻止其他程序读取配置文件。
- 像
.mcp.json这样的项目文件不在init --wrap-mcp的范围内。 - 你移到环境变量中的令牌,对任何以该环境启动的程序都是可见的。
常见问题
zn-gate init --wrap-mcp 会从我的 MCP 配置中删除令牌吗? 不会。它改的是本地服务器的启动命令,env 和 headers 保持原样。
备份里有我的令牌吗? 有,如果你包装时令牌在文件里。把值移出之后,请删除 .bak.<时间戳> 文件。
我可以对 mcp.json 使用 zn env shadow 吗? 它只记录了用于 .env 文件。
怎么确认没有遗留? 运行 npx -y zn-gate reach 和 npx -y zn-gate audit --include-home,并自己阅读这些文件。
来源
- zn-gate,保护 MCP 服务器与
init --wrap-mcp:/zh/docs/zn-gate/shield/ - zn-gate,
reach和audit检查什么:reach.md、audit.md - Claude Code,MCP:https://code.claude.com/docs/en/mcp
- Cursor,MCP:https://cursor.com/docs/context/mcp
- Codex CLI,MCP:https://learn.chatgpt.com/docs/extend/mcp?surface=cli
- OpenCode,配置与 MCP 服务器:https://opencode.ai/docs/config/、https://opencode.ai/docs/mcp-servers/