devto 2026-10-04 원문 보기 ↗
A single MCP server in front of one service is a solved problem: generate tools from the OpenAPI spec, run it over stdio or HTTP, done. At company scale the problem changes shape. A midsize platform team has forty services, each with its own spec, its own auth, its own staging and production hosts. Let every team publish an MCP endpoint and you quickly get:
list_users, two create_order, no way to tell them apart.The answer that keeps working as services multiply is an MCP gateway: one endpoint an agent authenticates against, which aggregates many backend APIs into one namespaced, governed tool catalog.
AI clients (Claude Desktop, Cursor, VS Code, CI agents)
│ OAuth 2.1, one consent, one token
▼
┌──────────────── MCP gateway ────────────────┐
│ auth & scopes rate limits audit log │
│ catalog aggregation name normalization │
└───────┬───────────┬───────────┬──────────────┘
▼ ▼ ▼
orders API billing API support API
(OpenAPI) (OpenAPI) (OpenAPI)
│ │ │
▼ ▼ ▼
services + databases (private network)
The gateway is not a new API implementation. It is a composition layer: each backend keeps owning its spec and its service; the gateway compiles those specs into one MCP catalog and proxies calls.
The core design decision is how services appear in tools/list. Flattening produces collisions and ambiguity. Prefixing every tool with a service namespace produces a predictable, greppable catalog:
{
"tools": [
{
"name": "orders__create_order",
"description": "[orders] Create a pending order and reserve inventory for 15 minutes.",
"inputSchema": { "$ref": "#/$defs/orders.CreateOrderRequest" }
},
{
"name": "billing__create_invoice",
"description": "[billing] Issue an invoice for a fulfilled order.",
"inputSchema": { "$ref": "#/$defs/billing.CreateInvoiceRequest" }
}
]
}
Three rules keep the catalog usable:
orders, billing), taken from a registry rather than guessed from repo names.orders.Order, billing.Invoice) so $ref resolution never merges two teams' Error models.The gateway should also deduplicate genuinely shared schemas by reference rather than copying them, so the model sees one Money concept, not twelve.
Clients and models have practical limits on tool count; hundreds of tools degrade selection accuracy even where the client technically accepts them. A gateway earns its keep by managing that budget:
orders:read,billing:read sees only those namespaces; tools/list itself is authorization-aware.The agent authenticates once against the gateway using OAuth 2.1 with PKCE. The gateway then holds service-to-service credentials downstream and maps the caller's identity and scopes onto each request:
agent token (scopes: orders:read, billing:write)
│
▼
gateway authorizes orders__get_order → allowed, signs request as gateway, forwards user identity
gateway authorizes billing__create_invoice → allowed, mints scoped service token
gateway authorizes admin__delete_account → denied at the edge with a structured MCP error
Forward the authenticated user's identity to backends in a signed header or token exchange rather than making every call anonymous; otherwise audit trails end at the gateway. The OAuth mechanics at the edge are the same ones described in MCP authentication explained.
Because every tool call crosses the gateway, concerns that would be duplicated forty times are implemented once:
Retry-After on throttles.orders__create_order and orders__create_order_v2 side by side while backends migrate, following the approach in versioning MCP tools.Do not start by building a platform. The aggregation pattern can be introduced incrementally:
Because the tool catalog is generated from specs, adding a service is a configuration and build step — register the spec, declare the namespace, choose the scopes — rather than an integration project. Treating the MCP server as compiled output is the principle in the MCP server is a build artifact.
Teams adopting this pattern usually discover that the prerequisite is not MCP infrastructure at all; it is having trustworthy, current OpenAPI documents for every service. For services that predate spec-driven development, those can be generated from the running codebase and then maintained as the contract; the code-to-spec workflow is covered in generating OpenAPI from existing code.
A local-first API workspace can generate the individual servers and validate the aggregated catalog before anything is hosted; you can try generating a server from a spec in the online demo, and the client-side configuration for the gateway URL is compared across editors in MCP clients compared.