⚡ TLDR
Uber has 800+ MCP servers and 5,000+ tools sitting behind a single gateway, with hundreds of teams building agents on top. Almost none of the work was about models. The questions that actually slowed them down were boring platform questions:
Who owns this tool, and is it safe to expose?
How does an agent find the right one among 5,000?
Who checks authorization when the caller is an agent acting for a human?
How do you give agents access to thousands of existing services without asking every team to write new code?
Their answer is one microservice that sits between every agent and every backend. A registry catalogs the tools, a proxy runs them, and a crawler drafts every tool definition from the Protobuf and Thrift schemas Uber already has. Nothing is exposed until a human owner turns it on.
If you remember one thing: this is the API gateway problem again, with a twist. The client is a model, and a model has a token budget. Hand it 5,000 tool definitions and it has spent most of its context before it starts working.
🧱 The problem turned out to be plumbing
Hundreds of teams at Uber started building agents around the same time. The early ones worked, because an agent that can hit a live service and do something for a user is a lot more useful than one that can only chat.
Then it spread, and you can guess what happened:
Every team built its own integrations, duplicating infrastructure and fragmenting the tooling
Tools were hard to discover and harder to run reliably
Each integration was welded to one service or one agent framework
Security and observability depended on whoever wrote the glue
If you were around for the first few years of microservices you’ve seen this list before. It’s roughly 2014, a month before somebody proposes an API gateway. Agent architectures have the same problem one level down, with the boxes renamed.
🗺️ Two planes
The gateway has two halves:
MCP Registry (control plane). The source of truth for which servers and tools exist, who owns them, and whether they’re enabled
Proxy Gateway (data plane). Takes an MCP call, translates it to HTTP, gRPC, or TChannel, forwards it, and converts the response back into an MCP result
The whole design rests on one bet: the fastest tool you can give an agent is an API you already run. Uber has thousands of services behind HTTP, gRPC, and TChannel. Asking those teams to rewrite anything for agents would have stalled every roadmap in the company, so the gateway adapts to the services and the services stay as they are.
I think that’s right, and I think most teams get it backwards. When MCP shows up, the instinct is to go write MCP servers. You already have the schemas. Wrap them.
🕷️ Discovery is automatic. Exposure is a decision.
Nobody hand-wrote 5,000 tool definitions. A crawler drafts them.
AutoCrawler runs on Cadence. A cron job kicks it off, it scans the IDL registry and some internal service signals for new services, new APIs and schema changes, and for each service or API group it finds it:
Upserts a virtual MCP server for the service
Parses the Protobuf or Thrift files for method names, request and response schemas, and doc comments
Asks an LLM to write agent-friendly tool descriptions from those schemas and comments
Translates the schemas into MCP-compatible JSON-RPC 2.0
Registers the tools in the registry, switched off
Hand-built servers take a second path. Anything written on MCPFx (Uber’s framework for native MCP servers) emits a heartbeat metric. The crawler sees a new heartbeat, calls listTools, and registers a virtual proxy server with whatever came back. Also switched off.
The disabled-by-default part is the decision I’d copy first. A tool stays dark until the owning team has read the generated definition, fixed whatever the LLM got wrong, and enabled it. After that, any edit to a tool description shows up as a config diff the owner has to approve, and they can roll back to the previous version.




