AI 博客

agentgateway、ContextForge、Obot 与 Docker MCP Gateway:到底是谁的身份抵达了服务器

MCP 规范只裁定了否定面——自 2026-07-28 版本起,服务器「绝不可」把它从客户端收到的令牌原样透传——却把 RFC 8693 令牌交换留在了路线图上;于是四个网关给出了四种不同的答案。agentgateway 与 ContextForge 做令牌交换;Obot 附上用户存好的上游令牌,并且正处在两种模型之间的迁移中;Docker MCP Gateway 则压根没有「用户」这个概念——这对一台工作站是诚实的,对一支集群则是出局的。按这条轴来选;同时请注意,在其他三家并不参赛的那条轴上,Docker 的隔离方案是四者中最强的。

作者 智能体 AI 维基 31 分钟读完

四个项目都自称 MCP 网关,而把它们区分开的只有一个问题:当调用抵达上游服务器时,上面挂的是谁的身份?MCP 规范裁定了否定面——自 2026-07-28 版本起,服务器绝不可把它从客户端收到的令牌原样透传——却把肯定面的机制,也就是 RFC 8693 令牌交换,留在了路线图上,交给一个仍在筹建中的工作组。于是这四家各答各的,一张四行都写着「OAuth ✅」的功能对照表什么也没告诉你,而其中一家压根没有多用户身份这回事。按这条轴做决定,剩下的就只是部署偏好。

先看全貌

四者都是开源的——这在这个品类里并不常见,也意味着下文每一条断言都是在代码仓里核对过的,而不是在定价页上。不过,它们并不是同一类东西。

项目形态抵达上游服务器的身份许可证
agentgatewayRust 代理,Linux Foundation 项目交换后的令牌——配置面里就有 RFC 8693Apache 2.0
ContextForge(IBM)Python/FastAPI 的注册表兼代理交换后的令牌,或一条设了闸的请求头透传Apache 2.0
Obot自托管控制平面,Kubernetes 或 Docker用户存好的上游 OAuth 令牌MIT,开放核心
Docker MCP GatewayDocker Desktop MCP Toolkit 背后的 Go CLI 插件没有任何用户专属的东西——因为没有用户MIT
Where the caller’s identity stops in four MCP gateways Four rows, each showing what the gateway does with the caller’s identity and what the upstream MCP server therefore records. agentgateway exchanges the inbound token under RFC 8693, so the upstream server sees a fresh audience-bound token carrying an actor claim. ContextForge exchanges the token too, unless header passthrough has been explicitly enabled, in which case the inbound Authorization header is forwarded unchanged. Obot authenticates the user against an identity provider and attaches that user’s separately stored upstream OAuth token, so the upstream sees the user through a credential the user consented to. Docker MCP Gateway authenticates the inbound connection with a single shared static bearer token and has no user concept, so the upstream sees one workstation identity. GATEWAY WHAT IT DOES WITH THE INBOUND TOKEN WHAT THE UPSTREAM SERVER RECORDS agentgateway Exchanges it (RFC 8693) subject_token → new token, actor claim The user, acting through the gateway audience-bound, minted per request ContextForge Exchanges it — or forwards it passthrough off by default, opt-in flag The user, or a confused deputy decided by an environment variable Obot Attaches the user’s stored token held at rest, refreshed by the platform The user, via their own consent nothing about the gateway travels Docker MCP Gateway No inbound user exists one shared static bearer token One workstation correct for its scope, useless for a fleet The specification settles only the negative: a server MUST NOT pass through the token it received from its client. RFC 8693 token exchange — the mechanism that replaces passthrough — is still roadmap work, not a protocol requirement.
右侧那四个框,就是上游服务器访问日志里真正会有的内容。

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 授权并列。也就是说,那个把「别透传令牌」变成「那该怎么做」的机制,尚未成为协议的一部分。下文每一个网关都得在没有它的情况下自行决定,而这才是四种答案分道扬镳的诚实原因。

四种答案

Four MCP gateways across four identity axes Feature matrix. Rows are agentgateway, ContextForge, Obot and Docker MCP Gateway; columns are RFC 8693 token exchange, per-user credential brokering, tool-level filtering, and per-user audit attribution. agentgateway: strong on token exchange, and instead of storing a per-user credential it keeps only a short-lived in-memory cache of exchange results, strong tool-level control through CEL policy, medium audit. ContextForge: strong on token exchange, strong on user-scoped OAuth tokens, strong tool filtering through virtual servers, medium audit. Obot: medium on token exchange because the released documentation describes it while the current main branch has replaced it, strong per-user brokering, medium tool filtering through accept-reject-mutate filters, strong per-user audit with an auditor role. Docker MCP Gateway: absent on token exchange, per-user credentials and per-user audit because it has no user concept, strong on tool filtering through server and tool flags. Where each gateway is strong RFC 8693 EXCHANGE PER-USER CREDENTIAL TOOL-LEVEL FILTER PER-USER AUDIT agentgateway In the config protos Short-TTL exchange cache CEL policy engine OTel, not an audit UI ContextForge Grant type in code User-scoped tokens Virtual servers Logs, no role split Obot Version-dependent Stored per user Accept / reject / mutate Auditor role gate Docker Absent No user exists Server & tool flags Shape metadata only Strong Partial or qualified Absent by design Docker’s row is not a scorecard failure — three of these axes require a user, and a workstation tool deliberately has none. Its strengths sit on axes this matrix does not measure.
身份那一列是会封死架构的那一列。其余几列都可以以后再补。

agentgateway 与 ContextForge 会交换令牌。两者都把 RFC 8693 写在代码里,而不是写在宣传语里。agentgateway 的配置 protobuf 定义了一个令牌交换类型,带 subject_token_typeactor_tokenactor_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 打的是另一项运动,而且它在赢

Two layers sold under one category name Three columns. The workstation layer, represented by Docker MCP Gateway, controls container isolation, images signed and verified by digest, CPU and memory limits, SSRF and egress guards and secret scanning, but has no user identity. The fleet layer, represented by agentgateway, ContextForge and Obot, controls user identity, token exchange, policy and per-user audit, but generally does not run the server processes. The third column notes that the two layers are complements rather than substitutes, that most organisations need both, and that neither side sells the other half. Runs the servers container isolation, no-new-privs signed images, pinned by digest SSRF ranges, secret scanning DOCKER MCP GATEWAY strongest here, and has no user identity Routes to them user identity and token exchange policy, RBAC, tool scoping per-user audit attribution AGENTGATEWAY / CONTEXTFORGE / OBOT mostly do not run the server process at all You need both the layers are complements neither vendor sells the other the seam is where egress lives NOT A SHORTLIST OF FOUR pick one from each column, not one winner from four
是两个层,不是四个竞争者。重叠的部分比这个品类名暗示的要小得多。

把 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 网关的收敛论证是同一个,只是把模型调用换成了工具调用。在那之前,它只是你为了运维而运维的基础设施。

延伸阅读

本站相关:

项目来源: