Tools MCP and External Integration

Tools MCP and External Integration

MCP Gateway — Patterns

Mcp gateway › Patterns

19 of 65 in this book · 3 min read

Virtual catalogues assembled per consumer

Problem. Aggregating every upstream into one list is the obvious implementation and the one that stops working first: the combined surface outgrows what any model can select from, and every consumer is exposed to systems it has no business reaching.

Approach. Treat the aggregate as an internal index, never as something a consumer sees directly. Each consuming application is bound to a named view: an explicit list of upstreams and specific offerings, with local aliases. Connecting consumers are served their view and nothing else, so the catalogue size is a product of what that consumer needs rather than of how many upstreams the organisation has onboarded.

Trade-off. Views are configuration that someone must curate, and a missing entry presents to the user as a capability that silently does not exist. Onboarding a new upstream now requires a second step before anyone benefits from it, which creates pressure for a permissive default view that undoes the whole pattern.

Decide before dispatch, always

Problem. It is easier to forward a call, observe the result, and then apply policy to what comes back. For anything with an effect this is not enforcement — the record was created, the message was sent, and only the report of it was suppressed.

Approach. Make the policy decision a mandatory step before any upstream connection is touched, with the decision inputs being the authenticated consumer, the resolved upstream and offering, and the argument values. Fail closed when the policy source is unreachable. Record the decision with the same identifier as the call so an allowed call and its outcome can be joined later.

Trade-off. Fail-closed means a policy-store outage is a total outage, which pushes toward caching decisions locally — and a cached allow outlives a revocation. Short cache lifetimes with an out-of-band revocation signal is the usual compromise, and it is a compromise.

Upstream health shapes what is advertised

Problem. When an upstream is down, a gateway can keep advertising its offerings and fail every call against them, or withdraw them and change what the model is being told mid-session. Both are bad, and picking one globally makes it bad in all cases.

Approach. Decide per offering class. Keep read-only offerings advertised during a brief outage so a transient blip surfaces as a retryable error rather than a vanished capability, and withdraw effectful ones promptly so the model stops planning around an action it cannot take. Attach an explicit availability state to each entry rather than inferring it from the list's contents, and emit the change notification the protocol provides rather than letting clients discover the difference through failures.

Trade-off. A flapping upstream produces catalogue churn, which is disruptive in its own right and needs damping. Per-class behaviour is also harder to explain to consumers, who will reasonably ask why one tool disappeared and another did not.

Adapt foreign backends at the edge

Problem. Most of what an organisation wants to make callable is an existing HTTP service, and writing a dedicated server for each one is work nobody schedules. The alternative — letting each application call them directly — puts those calls outside the policy and audit the gateway exists to provide.

Approach. Give the gateway an adapter layer that presents a non-protocol backend as a first-class upstream: a declarative mapping from an offering to a request against the backend, with the same credential brokering, policy evaluation, and result shaping as a native upstream. Consumers see no difference, and coverage of the audit trail stops depending on which integration style a team happened to choose.

Trade-off. Declarative mappings drift from the backend they describe, and they tempt teams into the endpoint-mirroring surface that models handle badly. The adapter also becomes a second place where contracts are defined, competing with wherever those contracts are actually owned.