四个项目都自称 MCP 网关,而把它们区分开的只有一个问题:当调用抵达上游服务器时,上面挂的是谁的身份?MCP 规范裁定了否定面——自 2026-07-28 版本起,服务器绝不可把它从客户端收到的令牌原样透传——却把肯定面的机制,也就是 RFC 8693 令牌交换,留在了路线图上,交给一个仍在筹建中的工作组。于是这四家各答各的,一张四行都写着「OAuth ✅」的功能对照表什么也没告诉你,而其中一家压根没有多用户身份这回事。按这条轴做决定,剩下的就只是部署偏好。
先看全貌
四者都是开源的——这在这个品类里并不常见,也意味着下文每一条断言都是在代码仓里核对过的,而不是在定价页上。不过,它们并不是同一类东西。
| 项目 | 形态 | 抵达上游服务器的身份 | 许可证 |
|---|---|---|---|
| agentgateway | Rust 代理,Linux Foundation 项目 | 交换后的令牌——配置面里就有 RFC 8693 | Apache 2.0 |
| ContextForge(IBM) | Python/FastAPI 的注册表兼代理 | 交换后的令牌,或一条设了闸的请求头透传 | Apache 2.0 |
| Obot | 自托管控制平面,Kubernetes 或 Docker | 用户存好的上游 OAuth 令牌 | MIT,开放核心 |
| Docker MCP Gateway | Docker Desktop MCP Toolkit 背后的 Go CLI 插件 | 没有任何用户专属的东西——因为没有用户 | MIT |
agentgateway 用 Rust 写成,是一个 Linux Foundation 项目,自我定位为下一代智能体代理:JWT、API key 与 OAuth 认证,由 CEL 策略引擎驱动的细粒度 RBAC,限流、TLS 与 OpenTelemetry。ContextForge 出自 IBM,把 MCP 连同 A2A 与 REST/gRPC API 一起联邦到同一个注册表之后,并提供把选定工具子集打包起来的虚拟服务器。Obot 是一个自托管治理平台,网关只是其中一个组件,它的审计方案是四者中最完备的。而 Docker 那个,是大多数工程师本来就已经装好的那个——因为它随 Docker Desktop 一起来。
规范裁定了什么,又把什么留给了你
当前协议版本是 2026-07-28,其授权部分的安全考量页写得异常直白。这里有两条义务要紧,均引自规范原文:
MCP 服务器必须(MUST)只接受明确签发给自己的令牌,并且必须拒绝那些没有把自己包含在 audience 声明里的令牌,或以其他方式确认自己就是该令牌的预期接收方。
如果 MCP 服务器要向上游 API 发起请求,它可以充当这些 API 的 OAuth 客户端。用在上游 API 的访问令牌是另一枚令牌,由上游授权服务器签发。MCP 服务器绝不可(MUST NOT)把它从 MCP 客户端收到的令牌透传出去。
注意主语:这些是加在 MCP 服务器身上的义务。网关对其上游的一切而言就是一个 MCP 服务器,所以它继承了这些义务;但规范从未把网关当作一个品类来处理——这恰恰解释了为什么四个网关可以用四种不同方式做到合规。规范自己的最佳实践页点名了这个反模式及其后果:转发未经修改的令牌会造成「混淆代理」问题,而下游服务器的日志「可能显示这些请求来自另一个来源、带着另一个身份」。这不只是绕过授权,更是审计被污染。
接下来是那个缺口。规范要求使用 RFC 8707 资源指示符——客户端必须发送 resource 参数,好让令牌绑定到它所面向的那台服务器。规范并没有要求 RFC 8693。在该仓库里,令牌交换出现在正文之外的地方仅有一处:开发路线图,被列为一个仍在筹建的「智能体身份」工作组的未来工作,与工作负载身份联邦和 ID-JAG 授权并列。也就是说,那个把「别透传令牌」变成「那该怎么做」的机制,尚未成为协议的一部分。下文每一个网关都得在没有它的情况下自行决定,而这才是四种答案分道扬镳的诚实原因。
四种答案
agentgateway 与 ContextForge 会交换令牌。两者都把 RFC 8693 写在代码里,而不是写在宣传语里。agentgateway 的配置 protobuf 定义了一个令牌交换类型,带 subject_token_type、actor_token 与 actor_token_type 字段;它还实现了跨应用访问,也就是 MCP 路线图所指向的 ID-JAG 形态。ContextForge 在其 tool 与 gateway 服务里实现了交换,以配置为 grant_type == "token-exchange" 的网关为触发条件,并且在没有已认证用户时直接拒绝调用——报错是「User authentication required for token-exchange gateway」,这是正确的失败方式,也是这条路径确有其事、而非纸上谈兵的一个好迹象。
ContextForge 同时也提供了那个被禁止的模式——有意为之,且设了闸。它的请求头透传功能会把入站的 X-Upstream-Authorization 改名为 Authorization 再转发出去。这就是透传,而文档在页首就明说了:该功能默认关闭,必须用 ENABLE_HEADER_PASSTHROUGH=true 显式开启,且 Authorization 被刻意排除在默认头列表之外,并附有关于令牌泄漏风险的说明。这是一件站得住脚的工程决定——现实中确实存在只支持这一种方式的 MCP 服务器——它同时也是整篇对比中最锋利的那个例证:你的部署合不合规,是由一个环境变量决定的,而不是由你买了哪个产品决定的。
Obot 代管的是一枚按用户存储的令牌,而且它显然正处在迁移途中。其 v0.25.0 文档描述了一个执行 RFC 8693 交换的 MCP Server Shim,交换用的凭据留在 shim 里、绝不暴露给 MCP 服务器。而当前 main 分支已经删掉了 shim 和那段表述:网关现在是「在目标服务器需要时取出该用户存好的上游 OAuth 令牌,并把请求代理过去」。两者都站得住——按用户存储的令牌断然不是透传,因为它本就是上游签发给该用户、用于该上游的——但它们的安全属性并不相同,而一枚每次请求现换的令牌,要比一枚静态存放的刷新令牌更窄。如果你在评估 Obot,请锁定版本,因为在已发布文档与当前分支之间,答案变了。
Docker 没有答案,因为它没有用户。入站认证是一枚静态 bearer 令牌,从 MCP_GATEWAY_AUTH_TOKEN 读取或在启动时生成,以常量时间比较;网关包里任何地方都没有「调用方用户」这个概念,而 --allow-unauthenticated 是一个会打印警告的显式退出开关。出站方向,它自己充当 OAuth 客户端,走动态客户端注册与 PKCE,并且确实发送 RFC 8707 的 resource 参数——所以在受众绑定上它是对的——但它拿到的身份属于这台工作站,不属于某个人。这不是缺陷。这是一个工作站工具对自身范围的诚实交代;唯一的失败模式是:团队先装了它,之后才发现它没法长成那个面向集群的网关。
Docker 打的是另一项运动,而且它在赢
把 Docker 的网关放到它真正参赛的那条轴上评判,它在这里的方案遥遥领先——因为四者中只有它真的在运行 MCP 服务器,而不只是把请求路由过去。对 Docker Hub 的 mcp/ 命名空间中的镜像,签名校验默认开启,这些镜像随后必须按摘要引用,并在拉取或运行之前完成校验——该命名空间之外的第三方镜像不在覆盖范围内,这一点值得知道而不是想当然。容器以 Docker 隔离、no-new-privileges 以及配置好的 CPU 与内存上限启动。远程 URL 默认必须是公网 HTTPS,且回环、私有、链路本地与元数据服务地址段一律拒绝——这是大多数代理丢给网络去管的 SSRF 防护。宿主机挂载默认只读,且必须落在允许清单内的根目录之下。密钥拦截默认开启,同时扫描工具调用参数与文本响应。
与之相对,那几个企业级代理大多什么也不运行。Obot 是例外,而这个对比很能说明问题:每台 MCP 服务器都跑在自己的 Kubernetes pod 里,按服务器的域名允许清单也存在,但要通过一个外部控制器来强制,而它今天唯一支持的提供方是 Aviatrix——内置的 NetworkPolicy 被明确写为「不感知域名」。所以对一家公司而言,诚实的架构是两层都要,而不是选出一个赢家:身份、策略与审计放在集群网关,隔离与供应链放在真正跑服务器进程的那一层。任何一方都不会把另一半卖给你,而这两者之间的接缝,正是你的出站管控必须落脚的地方。
审计是身份的下游,所以它才是那个诚实的分胜负点
审计日志只能记下网关本来就掌握的身份。这让日志成为一项派生属性、而非一条独立的轴,也让任何背着合规义务的人能很快把候选名单收窄。
Obot 的最完备:记录 MCP 请求与响应,连同发起请求的用户,可按日期、用户、服务器、操作与状态筛选,默认 90 天后删除并提供导出路径。其中最值得照抄的一块——无论你最后部署什么——是它的访问模型:请求与响应体只有拥有 Auditor 角色的用户才能查看,其余所有角色(包括 Owner 与 Admin)都只能看到元数据。这是一个大多数自建实现根本想不到要做的职责分离设计,而它正是「一份审计日志」与「一份访问面比原数据还宽的数据副本」之间的区别。
Docker 的方案,同样是对其范围而言自洽、对合规而言无用:调用日志默认开启,但文档明确写着日志只记录工具名与参数的形状元数据,且原始参数的键与值不得写入日志。对一台参数就是你自己密钥的工作站来说,这非常好。但它不是一份「谁做了什么」的记录。
这个规律超出这四家也成立。如果一个网关说不出某次工具调用是替哪个人发起的,那么日志量再大也产不出审计轨迹——这与环境权限问题从另一个方向给出的论证是同一个,也是受托访问与同意记录会不断出现在智能体监管里的原因。
什么时候选哪个
| 情形 | 选 | 理由 |
|---|---|---|
| 一名开发者、本地服务器,想要隔离与供应链安全 | Docker MCP Gateway | 最好的容器隔离、按摘要签名的镜像、SSRF 与密钥防护——而且没有一个你日后要拆掉的身份模型,因为它本来就没有 |
| 集群部署、已有身份提供方、需要每次请求都收窄权限 | agentgateway | 配置面里就有 RFC 8693 交换与跨应用访问、基于 CEL 的 RBAC;若你的采购流程在意这一点,它还有 Linux Foundation 的治理背书 |
| 要把 MCP 与 A2A 及既有 REST API 一起联邦 | ContextForge | 四者中唯一把非 MCP 后端当作一等公民对待的;虚拟服务器无需部署任何东西就能做工具级收窄——只要别开请求头透传 |
| 有合规义务、自托管 Kubernetes、审计就是交付物 | Obot | 按用户的审计加上以 Auditor 角色把关的载荷可见性、按服务器的 pod 与出站允许清单——请锁定版本,并确认那个版本给的是哪种身份模型 |
| 你还没决定你的智能体究竟以谁的身份行动 | 暂时哪个都别选 | 上面每一个选项都编码了对那个问题的一个答案。先把它定下来;网关是执行点,不是决策 |
不该拿来定夺的:star 数——它反映的是品类关注度而不是契合度——以及 README 上写没写「企业级就绪」。该拿来定夺的:把你在考虑的那一个,对着一台需要 OAuth 的服务器跑一遍,然后去读上游服务器的访问日志。如果本该出现某个人的地方出现的是你网关的服务身份,那你就在它变成一次事故之前先找到了答案。
常见问题
按用户存储的 OAuth 令牌,和令牌透传是一回事吗?
不是,而这个区别正是全部要点。透传转发的是客户端呈递给网关的那枚令牌,它是按网关的受众签发的,因此到达上游时就是一个混淆代理。而按用户存储的令牌,是上游授权服务器经由该用户给出的同意、签发给该用户、用于该上游的。它是合规的。它同时也比交换得来的令牌更宽,因为它带着刷新令牌静态存放,而不是每次请求现铸。
MCP 规范要求 RFC 8693 吗?
不要求。它要求客户端使用 RFC 8707 资源指示符,并禁止服务器透传收到的令牌。RFC 8693 令牌交换出现在路线图里,是「智能体身份」工作组的未来工作,与工作负载身份联邦及 ID-JAG 并列。谁要是告诉你某个网关「因为做了 RFC 8693 所以合规」,他描述的是对一件规范尚未要求之事的一个好实现。
能直接把 Docker 的网关用在生产里吗?
对于凭据本就属于机器的单租户负载——构建代理、定时任务、某个团队共用的自动化——可以,而且你会得到这里其他几家都比不上的隔离。但凡是代表具名个人行动的场景,就不行:没有可归属的用户概念,你就无法界定一次攻陷的范围、无法撤销某一个人的访问,也拿不出审计轨迹。
如果某台 MCP 服务器压根不支持 OAuth,会坏在哪?
你最终会在某处留下一枚共享凭据,问题只在于留在哪。好的版本是网关持有它,由网关侧按用户的策略决定谁可以调用哪个工具,于是用户身份的丢失止步于一条你掌控的边界,并且被记录下来。坏的版本是全局打开请求头透传,那会在丢掉身份的同时污染上游的审计轨迹。这两者在功能对照表上长得一模一样。
如果我的智能体直接调 MCP 服务器,还需要网关吗?
在第二个团队、第二套环境或第一位审计师出现之前,不需要。当你需要一个统一的执行点来管「谁可以调哪个工具」、需要一个统一的地方做令牌交换而不是共享凭据、需要一份能说出人名的日志时,网关才挣到它的位置——这与 AI 网关的收敛论证是同一个,只是把模型调用换成了工具调用。在那之前,它只是你为了运维而运维的基础设施。
延伸阅读
本站相关:
- MCP 的 OAuth 2.1 认证——这些网关所实现的授权模型。
- 生产中的 MCP 运维——集群规模下运行服务器究竟涉及什么。
- MCP 安全反模式——混淆代理及其近邻。
- MCP 注册表与分发——网关背后那些服务器从哪来。
- 智能体身份——决定智能体以谁的身份行动,而网关只负责执行。
- 受托访问与同意记录——监管正在收敛到的那份记录。
项目来源:
- modelcontextprotocol/modelcontextprotocol——规范,2026-07-28 版本。
- agentgateway/agentgateway
- IBM/mcp-context-forge——ContextForge。
- obot-platform/obot
- docker/mcp-gateway