拆解 Uber 的 MCP Gateway:800 个服务器、5000 个工具,收进一个控制面

·阅读约11分钟·Evergreen Tools Team

2026 年 10 月 1 日,Uber 工程团队公布了 MCP Gateway 的设计。按博文自述,它已经托管 800 多个 MCP 服务器与 5000 多个工具,是「支撑 Uber 全部 MCP 交互的基础微服务」,充当 AI Agent 与现有后端服务、原生 MCP 服务器之间的编排与路由层。这个故事的价值不在协议本身,而在于一个大型组织如何在 MCP 从「几个团队的实验」变成「几百个团队的基础设施」时,把发现、治理、授权与运维收敛到一个网关里。本文拆解它的控制面、数据面、发现引擎与安全模型,并给出设计清单。

一、先有运维问题,才有协议问题

Uber 的出发点是一个运维问题。按博文,早期与 MCP 的临时集成证明了价值——Agent 能访问实时业务上下文、查询内部服务、代替用户执行有意义的动作。但随着采用加速,问题浮现:各团队独立构建集成,导致工具链碎片化、基础设施重复;MCP 工具难以发现、难以可靠运维,且与特定服务或 Agent 实现紧耦合。在小规模下这些做法能跑,但当数百个团队开始探索 Agent 工作流时,缺少统一架构会让 MCP 的扩展推高运维复杂度、安全风险与开发者摩擦,最终限制它的价值。

# Uber's starting point is an operations problem, not a protocol problem.
# Early MCP integrations were powerful but ad hoc: individual teams built
# their own integrations, so tooling fragmented and infrastructure was
# duplicated. That works until hundreds of teams join in.

EARLY_MCP_PAIN = {
    "tooling": "fragmented across teams",
    "infrastructure": "duplicated",
    "discoverability": "tools were hard to find",
    "coupling": "MCP tied to specific services or agent implementations",
    "root_cause": "growth without a unified architecture",
    "risk": "operational complexity, security risk, developer friction",
}
把 MCP 逻辑集中到一个网关

碎片化不是协议问题,而是运维问题

二、网关的骨架:控制面 + 数据面

解法是把 MCP 逻辑收敛进一个基础微服务,并把它清楚地切成两半。控制面是 MCP Registry:维护数百个 MCP 服务器与数千个 MCP 工具的目录,是发现、归属与启用的单一事实来源。这些工具既有把现有 API 暴露为工具的无代码定义,也有完全按 MCP 规范实现的原生服务器。数据面是 Proxy Gateway,负责在运行时执行 MCP 请求:把协议调用翻译成 HTTP、gRPC 或 TChannel 请求,转发到相应后端服务,再把响应转回 MCP 兼容结果。这样,Agent 面对一致的 MCP 接口,而底层服务完全无需改动。

# The fix is a single microservice with two halves. Uber splits the
# system cleanly into a control plane and a data plane.

MCP_GATEWAY = {
    "MCP Registry": {
        "role": "control plane",
        "holds": ["hundreds of MCP servers", "thousands of MCP tools"],
        "is": "single source of truth for discovery, ownership, enablement",
        "tool_kinds": ["no-code API-as-tool", "fully native MCP servers"],
    },
    "Proxy Gateway": {
        "role": "data plane",
        "job": "execute MCP requests at runtime",
        "does": ["translate MCP calls to HTTP/gRPC/TChannel",
                 "forward to the right back-end",
                 "convert responses back to MCP-compatible results"],
    },
}

# The design goal: agents talk one consistent MCP interface, while the
# underlying services stay exactly as they are.

三、AutoCrawler:让发现自动发生

如果要求每个团队手工编写 MCP 服务器,速度慢且痛苦,所以 Uber 造了 AutoCrawler。按博文,它是一个基于 Cadence 的分布式工作流系统,订阅 Uber 的 IDL 注册表与内部服务信号;定时任务触发 Cadence 工作流扫描新增服务、API 与 schema 变更。对 Protobuf 或 Thrift 定义的服务,它会 upsert 一个虚拟 MCP 服务器、解析 IDL 提取方法名与请求/响应 schema 及文档注释、用 LLM 生成面向 Agent 的工具描述、把 schema 翻译成 MCP 兼容的 JSON-RPC 2.0 schema,并以默认禁用状态注册工具。对原生 MCP 服务器,它监听心跳指标,通过 listTools 拉取显式暴露的工具与 schema,自动创建代理服务器。

# AutoCrawler is the discovery engine that keeps service teams off the
# critical path. It is a Cadence-powered distributed workflow subscribed
# to Uber's IDL registry and internal service signals.

AUTOCRAWLER_STEPS = [
    "Upsert an MCP server for the discovered service/API group",
    "Parse protobuf/Thrift IDLs for methods, schemas and comments",
    "Use an LLM to generate agent-friendly tool descriptions",
    "Translate protobuf/Thrift schemas into MCP JSON-RPC 2.0 schemas",
    "Register tools in the registry DISABLED BY DEFAULT",
]

def discover_native_servers(heartbeat_metrics):
    """Native MCP servers announce themselves; AutoCrawler watches."""
    for server in heartbeat_metrics:
        tools = server.listTools()          # explicit tool + schema export
        yield {"proxy_server": server.name, "tools": tools, "state": "disabled"}
自动发现与默认禁用

发现不等于暴露:暴露权留在拥有团队手里

四、数据面:不重启就能改变行为

数据面负责把「一致性」落到实处。按博文,它持续从控制面消费服务器与工具配置,并按固定节奏刷新内存状态,使工具更新或启用状态变更可以实时生效,无需重启或重新部署。基于这份配置,它动态物化出虚拟 MCP 服务器;每个虚拟服务器只暴露一个 //mcp 端点,作为 Agent 执行的入口,进来的请求通过内置代理服务器解析到对应的 server handler。协议翻译由「既懂工具、又懂下游」的 handler 完成:对 HTTP 后端维护端点配置,对 gRPC/TChannel 维护过程映射,把 JSON 载荷序列化为 Protobuf 或 Thrift 字节并转发,再把响应转回 MCP 兼容 JSON。实际的下游请求通过 Uber 的服务网格 sidecar Muttley 执行,从而自动复用既有的服务间路由能力。

# The data plane is where 'consistency' becomes concrete. It consumes
# server and tool configs from the control plane and refreshes its
# in-memory state on a fixed cadence, so changes take effect without a
# restart or redeploy. Each virtual server exposes ONE endpoint.

DATA_PLANE = {
    "config_source": "control plane (registry)",
    "refresh": "in-memory, fixed cadence, no redeploy",
    "entry_point": "//mcp per virtual server",
    "translation": "server handlers are tool-aware and downstream-aware",
    "id_backends": {
        "http": "endpoint config",
        "grpc_tchannel": "procedure mapping",
    },
    "execution": "delegated to Muttley, Uber's service-mesh sidecar",
}

# Delegating to the mesh means the gateway inherits existing service-to-
# service routing instead of reinventing it.

五、安全:工具级授权与开箱脱敏

安全不是后补的。按博文,MCP Gateway 为所有服务器提供内置的、工具级粒度的授权与脱敏:它使用 Uber 内部的访问控制系统,针对检测到的调用方 actor(人类、服务与 Agent)应用不同的 charter 策略;策略在服务器级别创建,必要时可按工具级别覆盖。同时,网关对工具响应中的任何 PII 或敏感数据做开箱即用的脱敏。把「谁能看到哪些工具」与「谁能调用哪些工具」都放到网关这一层,是它在规模下仍可审计的关键。

# Security is baked in at tool granularity. Uber applies its internal
# access control system with charter policies per caller actor type.

CALLER_ACTORS = ["humans", "services", "agents"]

def authorize(request):
    """Server-level policy with optional tool-level overrides."""
    policy = charter_policy_for(request.actor)      # by actor type
    decision = policy.check(request.tool)           # tool-level granularity
    if not decision.allowed:
        return {"allow": False, "reason": decision.reason}
    return {"allow": True, "redact_pii": True}       # out-of-the-box redaction
工具级授权与脱敏

谁能看到、谁能调用、响应里有没有 PII

六、可以直接照搬的设计清单

把 Uber 的做法抽成可复用的原则:其一,把 MCP 当作平台能力而非每队自建件,集中到一层网关。其二,控制面与数据面分离,用注册表做发现、归属与启用的单一事实来源。其三,默认禁用、显式启用,任何描述变更都要 diff 与批准,可回滚。其四,用 IDL 与心跳做自动发现,用 LLM 生成描述,把服务团队从关键路径上挪开。其五,工具级授权 + PII 脱敏,且按 actor 类型(人类/服务/Agent)区分策略。其六,配置变更靠内存刷新实时生效。落地前,先用本站的 API 限流计算器与 API 响应时间计算器把限流与延迟预算算清楚,用 OpenAPI 规范校验统一接口契约,再用 API Mock 生成与 API 密钥轮换把「先定义、后暴露、最小权限」落成流程。

📌 常见问题 FAQ

Uber 为什么要自建 MCP Gateway?

按 Uber 工程博文,早期与 MCP 的临时集成证明了价值——Agent 能访问实时业务上下文、查询内部服务并代替用户执行动作。但随着采用加速,问题浮现:各团队独立构建集成,导致工具链碎片化、基础设施重复;MCP 工具难以发现、难以可靠运维,且与特定服务或 Agent 实现紧耦合。在数百个团队开始探索 Agent 工作流后,没有统一架构会让 MCP 的扩展推高运维复杂度、安全风险与开发者摩擦。

MCP Gateway 由哪两部分组成?

按博文,它遵循微服务架构,分为两大部分:控制面是 MCP Registry,维护数百个 MCP 服务器与数千个工具的目录,是发现、归属与启用的单一事实来源;数据面是 Proxy Gateway,在运行时执行 MCP 请求——把 MCP 协议调用翻译成 HTTP、gRPC 或 TChannel 请求,转发到相应后端服务,再把响应转换回 MCP 兼容结果。这样 Agent 面对一致的 MCP 接口,而底层服务无需改动。

AutoCrawler 是什么?它如何自动发现工具?

按博文,AutoCrawler 是一个基于 Cadence 的分布式工作流系统,订阅 Uber 的 IDL 注册表与内部服务信号。定时任务触发 Cadence 工作流扫描新增服务、API 与 schema 变更。对 Protobuf 或 Thrift 定义的服务,它会解析 IDL 提取方法名、请求/响应 schema 与注释,用 LLM 生成面向 Agent 的工具描述,把 schema 翻译成 MCP 兼容的 JSON-RPC 2.0 schema,并以「默认禁用」状态注册工具。对原生 MCP 服务器,它则监听心跳、调用 listTools,自动创建代理服务器。

为什么「默认禁用」是核心设计原则?

按博文,核心设计原则是「发现不等于暴露(discovery doesn't imply exposure)」:每个 MCP 服务器与工具都以禁用状态开始,必须由拥有团队显式审查并启用。服务负责人可以在启用前审查、精修自动生成的工具定义;每次工具描述变更都会触发配置变更 diff,需经服务器负责人批准,可部署也可回滚到先前已知版本。

MCP Gateway 在安全上做了什么?

按博文,MCP Gateway 为所有服务器提供内置的、工具级粒度的授权与脱敏。它使用 Uber 内部的访问控制系统,针对检测到的调用方 actor(人类、服务与 Agent)应用不同的 charter 策略;策略在服务器级别创建,必要时可按工具级别覆盖。此外,网关还会对工具响应中的任何 PII 或敏感数据做开箱即用的脱敏。