上一篇聊 Agent 记忆系统,中间插回 MCP 这条线,聊一个被严重低估的话题:配置。
部署形态那篇解决了"server 跑在哪",但还有最后一公里:用户怎么把它接起来。命令写什么、环境变量放哪、密钥会不会跟着配置文件一起进 git、团队里二十个人的配置怎么保持一致——这些问题在 demo 里不存在,在真实团队里每一个都咬人。
我自己踩过一圈之后的结论是:MCP 的配置问题本质上是三件事——密钥别泄露、结构要版本化、环境要隔离。这篇文章按这个顺序展开。各客户端(Claude Desktop、Cursor、Code 类工具)的配置文件路径各不相同且经常变,具体路径请以各自文档为准,这里只谈方案本身。
stdio 形态的配置核心就三块:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx"
}
}
}
}command + args 决定怎么拉起进程,env 决定进程的环境变量。HTTP 形态则是一个 url 加认证头。
看起来很简单,第一个坑就藏在这里:每个客户端都维护自己的一份配置。你在 Claude Desktop 里配好了,切到 Cursor 又要配一遍,两个配置文件从此开始各自的漂移——一边升了版本,一边还停在三个月前。配置漂移的直接后果是:同一个"MCP 工具"在不同工具里行为不一致,排查问题时你会把客户端行为差异误判成 server 的 bug。
所以第一条实践:把配置的定义收敛到一处。哪怕客户端不能共享配置文件,也可以共享一份"源"——一个仓库里的 mcp-servers.json 加一个生成各客户端配置的小脚本,改一处、生成多处。生成脚本二十行,从此没有漂移。
上面那份示例配置,在真实项目里是不及格的——GITHUB_TOKEN 明文躺在配置文件里,而配置文件大概率会进 git。MCP 配置进 git 是常态(团队需要共享),所以密钥必须外部化,这不是最佳实践,是及格线。
按投入从低到高,三个层次:
层次一:环境变量引用。 多数客户端支持在 env 值里做变量展开:
{
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}token 放在 shell 的 profile 或系统环境变量里,配置文件里只有一个引用。注意展开语法各客户端支持程度不一,用之前实测一下——$VAR 和 ${VAR}、以及不支持展开时传的是字面量,这三种行为我都见过。
层次二:启动包装脚本。 当客户端不支持变量展开、或者密钥存放在密码管理器(1Password CLI、pass、系统钥匙串)时,把"取密钥 + 拉起 server"封装成一个脚本,配置里的 command 指向脚本:
#!/usr/bin/env bash
# mcp-github.sh —— 从密码管理器取 token 再拉起 server
export GITHUB_TOKEN="$(op read 'op://Vault/github/token')"
exec npx -y @modelcontextprotocol/server-github密钥全程不落盘,配置文件里没有任何敏感信息。代价是多维护一个脚本,对团队场景这个代价几乎总是值得的。
层次三:密钥管理器集成。 远程托管的 server 不存在本地密钥问题,但要面对另一头:所有用户把 token 交给你托管。这时候要按多租户的标准处理——加密存储、按用户隔离、审计访问。这是产品化了的需求,一般团队碰不到,知道有这层就行。
一个容易忽略的细节:历史上泄露过的密钥不会因为改配置而失效。如果某个 token 曾经明文进过 git,哪怕后来删掉了,也要当作已泄露去轮换——git 历史里它永远都在。
配置的版本化原则一句话:结构和版本进 git,密钥走个人环境。
项目级的 MCP 配置(比如仓库根目录的 .mcp.json)应该提交,让每个clone 仓库的人开箱即得;其中的密钥引用全部走第二节的层次一或层次二。个人偏好的、含密钥的配置放客户端的私有配置区,不进 git,.gitignore 兜底。
但把 MCP 配置提交进仓库之前,有一件事必须想清楚:这等于给所有开发者的 Agent 开了新权限。供应链那篇的结论在这里直接适用——
npx -y pkg 拉的是最新版,作者一次 rug-pull 全组中招。至少锁 pkg@x.y.z,更稳的是配 hash 校验;server 有了 dev/staging/prod 之分后,配置层面会出现一个隐蔽的坑:同名工具在不同环境指向不同实现。
场景:你给内部数据库 server 配了三个环境,工具都叫 query_db。Agent 今天连的是 dev,明天配置切到 prod,工具名没变——但语义全变了:dev 里 query_db 删一万行无所谓,prod 里这是事故。模型对工具的认知来自名字和描述,它无法感知背后的环境切换。
两条防御:
query_db_dev / query_db_prod,或者至少在工具描述里写明"这是 staging 环境"。让模型每轮决策时都能看到自己在操作哪个世界;把这篇压成一张检查表:
grep 一遍自己的配置文件;配置这层做好,MCP server 才算真正"可交付"。这之后工程化线还剩最后一块:长会话的上下文管理——记忆系统篇结尾提过,Agent 行为"变形"往往不是模型问题,是早期上下文被截断了。下一篇聊压缩时机、摘要策略,以及什么内容永远不该被压掉。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。