This episode widens the architecture from one server to many: building an MCP gateway that routes requests to many servers with unified auth, plus fleet management with server versioning, rolling deployment, and health/readiness checks that keep services available during releases.

In episode 15 you installed observability on a single server. Now imagine operating ten MCP servers: one for git, one for the database, one for slack, and so on. Each server has its own URL, token, and security configuration. Giving every agent direct access to ten endpoints is an operational nightmare. Episode 16 introduces the layer that tidies this up: an MCP gateway plus fleet management.
This episode's roadmap: the reasons for building a gateway, gateway implementation with routing, unified auth at a single point, then fleet management — server versioning, rolling deployment, and health/readiness checks.
As servers multiply, the problems grow faster than just "many URLs". Every agent that wants to use five tool servers must be configured with five endpoints, five credentials, and five policies. Not to mention rotating credentials, moving servers, or adding instances when load rises — all of that propagates to every client configuration.
A gateway solves this with a single-door pattern: the agent only knows one endpoint, and the gateway knows how to route to the right server behind it. Benefits you'll feel immediately:
In the stateless 2026-07-28 architecture, the gateway is even simpler: because every request carries its own identity and capabilities, the gateway doesn't need to maintain session affinity (episodes 3 and 9) and can route per-request freely.
A gateway is essentially a Streamable HTTP server (episode 13) that receives JSON-RPC requests, decides the destination server, and forwards them. The routing decision is based on the method being called: tools/call carries a tool name, resources/read carries a URI, and prompts/get carries a prompt name — all of that is enough to map to the right server.
A simple routing configuration:
servers:
git:
url: http://git-mcp.internal:8080/mcp
routes:
tools: ["git_status", "git_commit", "git_push"]
db:
url: http://db-mcp.internal:8080/mcp
routes:
resources: ["postgres://*", "mysql://*"]
slack:
url: http://slack-mcp.internal:8080/mcp
routes:
tools: ["slack_send"]
prompts: ["standup_report"]The core implementation in TypeScript isn't far from an ordinary HTTP handler: accept POST, read the method, match it against the route table, then forward the JSON-RPC body to the destination server and send its response back. The key that often gets missed is timeouts and error mapping — if the destination server is slow or errors, the gateway must translate that into a standard JSON-RPC error code, not let a timeout confuse the agent.
With a gateway, authentication stops being each server's business. All incoming requests are verified in one place with one policy: OAuth 2.1 from episode 10 for external clients, API keys or mTLS for internal services. Servers behind the gateway can use different service credentials — or even no authentication at all — because they're never directly exposed to the outside.
What you must protect: never forward client credentials to backend servers raw. The gateway is the trust boundary. The correct pattern:
This way, revoking one client's access happens in one place, and you get a record of who called which tool — valuable assets for audit and abuse detection from episode 14.
Behind the gateway, you operate a fleet of servers. Every MCP server must be treated like a production application: it has a version, a release pipeline, and an upgrade strategy. Two concepts are mandatory:
Versioning also matters because MCP evolves quickly (episode 17 covers compatibility across spec eras). Knowing a server's version and the SDK version it packages lets you plan upgrades before the version is retired.
The most nerve-racking part of fleet operations is replacing versions without downtime. Rolling deployment swaps instances gradually: bring up a new instance with the new version, wait until healthy, then take down the old one. During the process, the gateway only directs traffic to healthy instances.
A Kubernetes deployment with a rolling strategy:
apiVersion: apps/v1
kind: Deployment
metadata:
name: db-mcp
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
spec:
containers:
- name: mcp
image: registry.internal/db-mcp:sha-9f2c71a
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5Note the readiness probe: Kubernetes won't send traffic to a pod before /healthz answers 200. This distinguishes two concepts:
The gateway also checks backend health periodically and marks unhealthy servers as unavailable — cutting them out of routing without waiting for the first request to fail.
Info
Test your readiness probe properly: create an endpoint that actually checks dependencies (database connection, identity provider connection), not just a 200 return. A fake readiness check is the classic cause of flaky errors during rolling deployments — pods look healthy but fail immediately when they receive real traffic.
Episode 16 turned a messy collection of MCP servers into one managed architecture: a gateway as a single entry point with method-based routing and unified auth, followed by fleet management with semantic versioning, rolling deployment, and health/readiness checks that keep traffic flowing only to instances that are truly ready.
Key takeaways:
In the next episode 17 we close the operations phase with a topic often forgotten until it's too late: Versioning & Compatibility (Modern vs Legacy) — version negotiation between two spec eras, dual-era implementation, and deprecation policy with removal clocks. See you there!