如何安全地把 MCP 用在 Hermes Agent 里
嗨,我是 Lena。本周我本来没打算写 MCP。我只是想给自己一直在跑的一个 Hermes Agent 实例接上第二个工具服务器。结果在改配置、看工具列表刷新到一半时,我停住了。
这个 agent 现在能访问四个十分钟前还没有的服务器。我其实还没认真想过,每一个服务器到底被允许读取什么。于是我回去看文档,又回去看配置。这次开场我就先停在这里——因为这个小小的停顿,基本就是这篇文章想讲的全部。
这不是一篇 MCP 入门。如果你看到这里,大概已经知道这个协议是什么了。我想写下来的,是我这段时间学到的:怎么在把 MCP 用到 Hermes Agent 时,不要悄悄给 agent 交出去比自己原本打算更多的权限。
MCP 实际给 Hermes Agent 增加了什么
不写 Hermes 原生工具,也能接入外部工具
Hermes 自带一组固定的内置能力。MCP 是一种扩展这组能力的方式,而且不需要你重新写一个原生工具。 你把 Hermes 指向一个 server——本地的也好,远程的也好——那个 server 的工具列表就会和内置工具一起出现。从 agent 的视角看,几乎没什么区别。
但这个“几乎”很重要。内置工具活在 Hermes 自己的权限模型里。MCP tools 则隔着一层协议边界。它们在你的机器或网络里实际做什么,完全取决于你信任的那个 server。
为什么 MCP 是适配层,不是魔法功能
我一直提醒自己这一点。MCP 不会让一个工具自动变得更安全,也不会让它更聪明。它标准化的是:一个工具如何被描述给 agent,以及调用和响应如何通过 JSON-RPC 2.0 来回传递。就这些。
所以当 Hermes 里的某个 MCP tool 出问题时,bug 几乎从来不在 MCP 本身。问题通常在你连接的 server、它正在使用的凭证,或者那个“agent 会自己判断该调用什么”的假设里。这件事我学了两遍才真的记住。
什么时候该用 MCP,什么时候不该用
适合、不适合,以及暴露过大的工具面
在 Hermes 配置里,MCP 真正值得出现的场景通常是这些:
- 围绕外部系统的读取型工作——拉取 issues、查询日志、获取文档、浏览 agent 原生够不到的文件。
- 你已经信任的内部 API,再用一个自己控制的小 MCP server 包起来。
- 一次性集成,也就是写 Hermes 原生工具有点过度设计的那种。
而这些场景,我会多想一想:
- 任何会破坏生产系统的操作。 删除、force-push、schema 变更——只要工具描述听起来足够自信,agent 真的会去调用。
- 一次暴露几十个工具的 server。 Anthropic 工程团队提到过,大多数 MCP clients 会把所有工具定义预先加载进模型上下文,这意味着连接的 server 越多,token 越多,暴露面越大,也越容易出现工具描述悄悄塑造行为的地方。研究人员也单独记录过,工具描述本身会被喂给 LLM,而且可以携带隐藏指令——这就是现在被广泛称为 tool poisoning 的问题。窗口越大,风也越容易进来。
- 随便找来的社区 server,尤其是那些一上来就要宽泛凭证的。MongoDB 团队在文档里说得很直接:Streamable HTTP servers 默认应该绑定在 localhost (127.0.0.1),因为绑定到 0.0.0.0 会把它们暴露给整个本地网络。很多“开箱即用”的教程会跳过这一段。
如果一个 workflow 很少用、很敏感,或者生命周期很短,MCP 大概率不是它最合适的形状。 写成脚本,然后显式调用,会更清楚。
在 Hermes 里安全配置 MCP
stdio 与远程 server
两种 transport。它们不能互相替代。
Stdio 会把 MCP server 作为你机器上的子进程运行。Hermes 通过 stdin/stdout 跟它通信。它简单、低延迟,适合本地文件系统、开发者工具这类场景。代价是:你正在自己的机器上执行一个 binary,而且 OAuth/token 那套机制在这里基本用不上。
Remote (Streamable HTTP) 则是 server 跑在别的地方,通过 HTTP 通信。这里授权才真正开始有牙齿。按照官方 MCP specification,MCP servers 在这种模式下现在被归类为 OAuth Resource Servers,也就是说 token 有明确的 scope 和 audience,不再只是一个泛用 API key。我好像开始明白,为什么 2025 年 11 月的 spec 会这么强调这一点——单个静态 API key 在悄悄制造每个问题最糟糕的版本。
我一直回到的粗略规则是:真正必须本地运行的东西用 stdio,任何会和真实网络服务通信的东西用 remote。 在同一个 Hermes config 里混用两者没问题,但我会把它们标清楚,免得自己忘了哪个是哪种。
按 server 过滤、隔离 env、以及 /reload-mcp 工作流
有三个习惯,真的帮我省过时间:
- 按 server 过滤工具面。 如果一个 server 暴露 20 个工具,而 agent 只需要 3 个,就不要加载另外 17 个。Hermes 允许你按 server allowlist 工具名。这不是疑神疑鬼——它会直接缩小前面提到的 prompt-injection 暴露面。
- 隔离环境变量。 不要把完整 shell 环境一股脑丢给每一个你启动的 MCP server。只传这个 server 真正需要的变量,并通过 expansion 引用 secrets(比如
"GITHUB_TOKEN": "$GITHUB_TOKEN"),不要硬编码进去。其他 agent runtime 会在启动 MCP processes 之前,自动把匹配 TOKEN、SECRET、PASSWORD 这类模式的变量打码——Hermes 默认不会替你做这件事,所以你得写得很明确。 - 有意识地使用
/reload-mcp,不要条件反射。 改了 server config 之后,当然要 reload——但继续工作之前,先检查新的工具列表。reload 是你最自然地重新阅读“agent 现在能访问什么”的时刻。我可能想太多了,但 跳过这一步,就是静默权限蔓延发生的方式。
日常真正可用的 MCP 模式
GitHub、database、内部 API、browser stacks
几个我看下来比较站得住的模式:
GitHub 式读取访问。 使用 scoped fine-grained tokens。agent 可以读 issues、PRs 和 code,但不能 push 或 merge。写操作交给人。
Databases。 只连 read replicas。即便如此,我也会把 query timeout 设短,把结果行数上限压低——agent 不小心写出很重的 query 是真实故障模式,不是理论风险。
Internal APIs。 用一个小的内部 MCP server 包起来。不要复用 master service-account token——专门给 agent 发一个范围更窄的 token。研究大规模 MCP 实践的人提到过,现实中的不少 MCP servers 依赖 API keys 或 PATs 这类长期静态 secrets,而这正是最容易泄露的模式。这个数字一直留在我脑子里。
Browser stacks。 这是爆炸半径最大的集成。一个 browser MCP server 可以导航、点击、提交表单。我会默认关掉,只有真正需要时才打开,用完再关掉。
贯穿这一切的线索是:最小权限应该按 server 切分,而不是按 agent 切分。 每一个 MCP server 都是一次单独的信任决策。
Hermes 里常见的 MCP 错误
不安全的默认值、巨大的工具面、过期的配置假设
有些事我自己做错过,也见别人做错过:
- 相信“默认配置”等于“安全配置”。 它通常只意味着“最容易演示”。任何从博客文章里复制来的配置,都值得审一遍,包括这篇——默认值是为了最简单路径写的,不是为了最安全路径写的。
- 先连接,后收窄 scope。 老实说,后面再收窄通常就等于永远不会收窄。添加 server 的时候就把 scopes 设好。
- 以为工具描述就等于工具实际会做的事。 Tool descriptions 是提示词。它们活在 agent 的上下文里,并塑造行为。一个被污染的、或者写得很粗糙的描述,可能把结果推向用户根本看不见的方向。
- 忘了 config drift 真的存在。 上个月安全的 server,这个月可能已经更新了工具列表。Reload, re-read, re-decide.
最后这一点,我还不完全确定该怎么自动化。可能值得以后再回头写。
FAQ
如果 Hermes 已经有能用的工具,我还需要 MCP 吗?
不需要。只有真的有缺口时再加 MCP。新 server 会增加暴露面,不管你用不用它。
Stdio 还是 remote——哪个“更安全”?
这个问题问错了。Stdio 是在本地运行 binary;remote 是跨网络通信。它们面对的威胁不同。应该根据数据和凭证实际住在哪里来选。
我能不能直接信任一个官方 MCP server?
“官方”只说明它是 vendor 写的。不代表你给它的配置就是安全的。scope 和 token 仍然是你的责任。
我应该多久 review 一次 MCP config?
每次添加、移除或更新 server 时都要看一次——哪怕没有变化,我也会每个月快速扫一遍。
我大概还会继续观察它怎么演进。协议还在移动,spec 还在收紧,现在看起来显而易见的模式,六个月后可能会显得很天真。至少现在,对我最有用的不是某段 config snippet——而是当工具列表变长时,先停一下的那个小习惯。这次我就写到这里。




