TAI BUI
Back to curriculum
LearnPython

MCP Gateways and Registries — Enterprise Control Planes

A gateway is where an enterprise decides which MCP servers its developers can reach. It centralizes auth, RBAC, audit, rate limiting, caching, and tool-poisoning detection, then exposes the merged tool surface as a single MCP endpoint. The Official MCP Registry (Anthropic, GitHub, PulseMCP, and Microsoft, namespace-verified) is the canonical upstream. This lesson shows where a gateway fits, walks a minimal implementation, and surveys the 2026 vendor landscape.

TIME: ~45 minutesPREREQUISITES: Phase 13 · 15 (tool poisoning), Phase 13 · 16 (OAuth 2.1)

Learning Objectives

  • Explain where an MCP gateway sits (between MCP clients and multiple backend MCP servers).
  • Implement the five gateway responsibilities: auth, RBAC, audit, rate limit, policy.
  • Enforce a pinned-tool-hash manifest at the gateway layer.
  • Differentiate the Official MCP Registry from metaregistries (Glama, MCPMarket, MCP.so, Smithery, LobeHub).

The Problem

Picture a Fortune 500 with 30 approved MCP servers, 5000 developers, compliance and audit requirements, and a security team that wants one place to set policy. Letting each developer install whatever server they like in their IDE doesn't survive the first compliance review.

The gateway pattern fixes this:

  1. The gateway runs as a single Streamable HTTP endpoint that developers connect to.
  2. It holds the credentials for each backend MCP server.
  3. Every developer request is authenticated and scoped through the gateway's own OAuth.
  4. The gateway routes the call to the backend server and applies policy on the way.
  5. Every call is logged for audit.

Cloudflare MCP Portals, Kong AI Gateway, IBM ContextForge, MintMCP, TrueFoundry, and Envoy AI Gateway all shipped gateways or gateway features in 2025-2026.

The Official MCP Registry launched alongside them as the canonical upstream: curated, namespace-verified, reverse-DNS-named servers that a gateway can pull from. Metaregistries (Glama, MCPMarket, MCP.so, Smithery, LobeHub) aggregate servers across several sources.

Warm-up0/3
1. An MCP server you approved last month quietly changes a tool description to carry hidden instructions. What is this attack called?Warm-up
Two cards side by side. Left, the description text of a tool as approved last month. Right, the text the same server serves today, now ending with a SYSTEM tag containing the word exfiltrate.
Description strings are the ones main.py uses for its notes search tool and for its demo change.
2. Under OAuth 2.1, which mechanism lets a public client prove it started the authorization flow it is finishing?Warm-up
Sequence diagram between an app labelled public client and an authorization server. Four arrows: an authorization request, a redirect back with a code, a code exchange request marked with a question mark for something sent along with the code, and an access token.
Typed schematic of an OAuth 2.1 authorization-code flow.
3. A web API recognizes who you are but refuses the request because your account lacks permission. Which HTTP status code fits best?Warm-up
A request card with a GET line and a bearer header, a card saying the caller's identity is known but the permission for this request is missing, and a dashed box asking for the HTTP status code.
Typed, illustrative request. The path and header are placeholders.
Check: The Problem0/2
1. What is an MCP gateway?Define
Two IDE boxes for alice and bob on the left, a box labelled gateway in the middle, and two backend boxes for notes and github on the right, joined by arrows.
Typed layout of the clients and backends in the lesson's main.py demo.
2. Why does letting each developer install any MCP server in their IDE fail a compliance review?Explain
Three developer IDE boxes, each with a different list of locally installed servers, with arrows to a compliance review box. A dashed box asks why the review fails.
Illustrative developer and server assignments.

The Concept

Five gateway responsibilities

  1. Auth. OAuth 2.1 to identify the developer; maps to user roles.
  2. RBAC. Per-user policy: which servers, which tools, which scopes.
  3. Audit. Every call logged with who, what, when, result.
  4. Rate limit. Per-user / per-tool / per-server caps to prevent abuse.
  5. Policy. Reject poisoned descriptions, enforce Rule of Two, redact PII.

Gateway as a single endpoint

To developers, the gateway looks like one MCP server. Internally it routes to N backends. Session ids (Phase 13 · 09) are rewritten at the boundary.

Credential vaulting

Developers never see backend tokens. The gateway holds them (or proxies to an identity provider that does). A developer with notes:read on the gateway may transitively access the notes MCP server with the gateway's own backend credentials, but only under a policy that binds the transitive access.

Tool-hash pinning at the gateway

The gateway holds a manifest of approved tool descriptions (SHA256 hashes). At discovery time, it fetches each backend's tools/list, compares hashes to the manifest, and removes any tool whose description has mutated. This is the rug-pull defense from Phase 13 · 15 applied centrally.

Policy-as-code

Advanced gateways express policy in OPA/Rego, Kyverno, or Styra. Rules like "user alice may call github.open_pr only on repos in org acme" are encoded declaratively. Simple gateways use hand-coded Python. Both work.

Session-aware routing

When a user's session includes a mix of servers, the gateway multiplexes: the developer's single MCP session holds N backend sessions, one per server. Notifications from any backend route through the gateway to the developer's session.

Namespace merging

Gateways merge tool namespaces from all backends, typically with prefix-on-collision. github.open_pr, notes.search. This makes routing unambiguous.

Registries

  • Official MCP Registry (registry.modelcontextprotocol.io). Launched under Anthropic, GitHub, PulseMCP, Microsoft stewardship. Namespace-verified (reverse-DNS: io.github.user/server). Pre-filtered for basic quality.
  • Glama. Search-centric metaregistry aggregating many sources.
  • MCPMarket. Commercial-leaning directory with vendor listings.
  • MCP.so. Community directory; open submissions.
  • Smithery. Package-manager-style installation flow.
  • LobeHub. UI-integrated registry in their LobeChat app.

Enterprise gateways pull from the Official Registry by default, allow admin-curated additions from metaregistries, and reject anything unpinned.

Reverse-DNS naming

Official Registry mandates reverse-DNS names for public servers: io.github.alice/notes. Namespaces prevent squatting and make trust delegation clearer.

Vendor survey, April 2026

VendorStrength
Cloudflare MCP PortalsEdge-hosted; OAuth integrated; free tier
Kong AI GatewayK8s-native; fine-grained policy; logs to OpenTelemetry
IBM ContextForgeEnterprise IAM; compliance; audit export
TrueFoundryDevOps-leaning; metrics-first
MintMCPDeveloper-platform oriented
Envoy AI GatewayOpen-source; customizable filters

Phase 17 (production infrastructure) goes deeper on gateway operations.

Check: The Concept0/21
1. Which of these is NOT one of the gateway responsibilities listed under Five gateway responsibilities?Define
An IDE box sends a request through a gateway box to a github backend box. Below, a card shows the tools/call github.open_pr line, next to a dashed box asking what jobs the gateway does.
Typed schematic.
2. What does RBAC decide at an MCP gateway?Define
Code excerpt from main.py showing a dictionary named RBAC keyed by user id. Alice's row lists four server.tool names. Bob's row is hidden.
Excerpt from the lesson's main.py, line breaks changed, with bob's row hidden.
3. What is the gateway's audit log?Define
Table with columns user, call, decision and at. Three rows for alice: notes.search, github.list_issues and github.open_pr, each with decision allow and a timestamp.
Rows captured from AUDIT_LOG in a real run of main.py.
4. What does the gateway's rate limit do?Define
Timeline from 0 to 3 seconds with blue ticks for tools/call requests from one user: two early ones, a dense cluster of twelve just after one second, and two later ones.
Illustrative arrival times.
5. What does credential vaulting mean in the gateway model?Define
A chain of three boxes: alice, a gateway, and a notes backend. A card for the notes backend token points at the backend. A dashed box labelled kept by asks who holds the token.
Typed schematic.
6. How does tool-hash pinning work at the gateway layer?Define
A table of four pinned entries, notes::search, notes::create, github::list_issues and github::open_pr, each with a 12 character hash prefix. Below, a backend tools/list box leads to a dashed box asking what the gateway does, then to a tool list box.
Hash prefixes computed from main.py's descriptions.
7. How does the Policy-as-code subsection describe policy at the gateway layer?Define
A card with the plain-English rule that user alice may call github.open_pr only on repos in org acme, an arrow down to a dashed box asking how the gateway stores the rule.
The rule is the lesson's own example.
8. A developer's session uses tools from several backends at once. What does the gateway do under session-aware routing?Define
A developer session box that uses notes and github, a gateway box, and notes and github backend boxes. A dashed box asks what the gateway keeps for the session.
Typed schematic.
9. Two backends both expose a tool that would collide in one merged gateway namespace. What do gateways typically do?Define
A notes backend and a github backend each offering a tool named search. Arrows lead to a dashed box asking what tool list the developer sees.
Illustrative names.
10. What is the Official MCP Registry?Define
A card naming the Official MCP Registry, its address registry.modelcontextprotocol.io, and the organizations it launched under.
Text from the lesson's Registries section.
11. What naming convention does the Official MCP Registry mandate for public servers?Define
A card for alice's server with publisher alice on GitHub and server name notes, an arrow to a dashed box asking for its name in the registry.
Typed schematic.
12. A developer holds notes:read on the gateway and calls the notes backend through it. What credentials reach the backend?Explain
Alice with scope notes:read, a gateway, and a notes backend joined by arrows. A note says alice sends her gateway token to the gateway, and a dashed box asks what credential goes from the gateway to the backend.
Typed schematic.
13. How do RBAC and rate limiting differ at the gateway?Explain
A chain of four boxes: request, RBAC, rate limit, backend. Under the RBAC and rate limit boxes sits one dashed box asking how the two checks differ.
Typed schematic.
14. Why does the gateway compare hashes of tool descriptions rather than only checking tool names?Explain
A manifest table with two pinned entries and hash prefixes, a box for a live tools/list entry with fields name and description, and a dashed box asking what the gateway compares on.
Hash prefixes computed from main.py's descriptions.
15. How does the Official MCP Registry differ from a metaregistry such as Glama or MCP.so?Explain
Three cards: the Official MCP Registry, Glama and MCP.so, the last two labelled metaregistry. A dashed box asks how the Official Registry differs.
Names from the lesson's Registries section.
16. Why does the Official Registry mandate reverse-DNS names such as io.github.alice/notes?Explain
A card showing the name io.github.alice/notes in large monospace text, with a dashed box asking why the registry requires names of this shape.
Example name from the lesson.
17. The vendor survey lists Envoy AI Gateway as open-source with customizable filters. How does that differ from Cloudflare MCP Portals?Explain
Two cards. Envoy AI Gateway: open-source, customizable filters. Cloudflare MCP Portals with a dashed box asking for its strength.
Envoy row copied from the lesson's vendor survey.
18. A developer holding only notes:read on the gateway manages to delete notes through the backend. Which gateway piece is missing?Analyze
A developer with scope notes:read, a gateway, and a notes backend with a delete_note tool. A note says the note is deleted, and a dashed box asks which gateway piece is missing.
Illustrative tool name.
19. Your security team wants to expose a server listed only on MCP.so. What should an enterprise gateway do?Design
Two cards: the Official MCP Registry where the server is not listed, and MCP.so where it is listed. An arrow leads to a dashed box asking what the enterprise gateway does.
Typed schematic of the stem.
20. Your platform team runs everything on Kubernetes and wants fine-grained policy with logs flowing to OpenTelemetry. Which gateway in the vendor survey fits best?Design
A card listing three needs: runs on Kubernetes, fine-grained policy, logs flowing to OpenTelemetry. An arrow leads to a dashed box asking which gateway from the vendor survey fits.
Needs copied from the stem.
21. Compliance says tool results must never leave the gateway containing SSN-shaped strings. Which responsibility fits, and where does it run?Design
A notes backend, a gateway and a client in a row. A card shows result text from the backend containing the placeholder SSN-shaped string 000-00-0000, and a dashed box asks which gateway responsibility applies.
Placeholder value and typed result text.

Use It

main.py is a minimal gateway in about 200 lines. It authenticates users by a fake Bearer token, holds a per-user RBAC policy, routes calls to two in-process stub backends (notes and github), writes every authenticated tools/call decision (allow, forbidden, rate_limited, hash_mismatch) to an audit log, enforces a rate limit, and rejects any backend tool whose description hash doesn't match a pinned manifest.

What to look at:

  • The RBAC dict, keyed by user id, with the allowed server.tool names.
  • AUDIT_LOG, an append-only list of events.
  • The rate limiter, a token bucket per user (capacity 5, refilling 1 token per second).
  • The pinned manifest, a dict of server::tool -> hash.
Check: Use It0/10
1. In main.py, alice calls github.open_pr. RBAC allows it and her bucket has tokens, but the backend's description no longer matches the pinned hash. What happens?Apply
A card with three facts about alice's github.open_pr call: RBAC lists it, her bucket has tokens, and the live description hash differs from the pinned hash. A dashed box asks for the response status and audit decision.
Typed summary of the stem's situation.
2. In main.py, bob calls github.open_pr, which is not in his RBAC set. What happens?Apply
A card with bob's bearer header and a tools/call github.open_pr line, with a dashed box below it asking what happens.
Typed summary of the stem's request.
3. A user's bucket in main.py starts full at capacity 5 and refills 1 token per second. Eight permitted calls arrive within microseconds. About how many are rate limited?Apply
A bucket showing five filled tokens, a note that the refill is one token per second, a row of eight call boxes numbered 1 to 8 arriving within microseconds, and a dashed box asking how many are rate limited.
Typed from the stem and main.py's get_bucket.
4. Alice has spent all 5 tokens at once, then waits 2 seconds. Ignoring other checks, how many calls can she make before being limited again?Apply
Timeline from 0 to 2 seconds. At 0 s alice has spent all 5 tokens of a capacity-5 bucket. At 2 s she calls again, and a dashed box asks how many calls succeed before she is limited.
Typed from the stem.
5. A request reaches gateway_tools_call with the Bearer token bearer_eve, which is not in USERS. What happens?Apply
The USERS table from main.py with keys bearer_alice and bearer_bob, a call to gateway_tools_call with token bearer_eve, and a dashed box asking what happens.
Excerpt from main.py.
6. What does gateway_tools_list return for bob's token before any backend description changes?Apply
Two cards listing the backends' tools: notes with search and create, github with list_issues and open_pr. Below, a call to gateway_tools_list with bob's token and a dashed box asking for the returned names.
Tool names from main.py's backends.
7. After a backend edits a description, alice's tools/list quietly loses notes.search, yet the audit log shows nothing about it. What is the gap?Analyze
Two lists of alice's tool names. Before: notes.search, notes.create, github.list_issues, github.open_pr. After a backend edits a description: notes.create, github.list_issues, github.open_pr. Below, the audit log prints as an empty list.
Real output from main.py after editing the notes search description.
8. pin_manifest hashes whatever the backend reports when the module loads. The backend was already serving a poisoned description at that moment. What follows?Analyze
Three boxes in order: backend serves a poisoned description, module loads and pin_manifest runs, then a tools/call hash check. A card shows the description text at load time with a SYSTEM exfiltrate tag, and a dashed box asks for the hash check outcome.
Description text is the one main.py uses for its demo change.
9. Operators restart the demo gateway often and see users briefly exceed the intended call cap right afterwards. What explains it?Analyze
Bar chart with a dashed line for the intended cap. A bar before a restart marker stays under the line, and a bar right after the restart rises above it.
Illustrative heights; the stem gives no numbers.
10. You are hardening the demo gateway for production. Where should the pinned tool hashes come from?Design
A dashed box asking for the source of hashes, an arrow into a PINNED_HASHES manifest box, and an arrow to a live backend box.
Typed schematic.

Ship It

This lesson produces outputs/skill-gateway-bootstrap.md. Given an enterprise MCP plan (users, backends, compliance), the skill produces a gateway configuration spec.

Author's Note

I'd run main.py first and read the printed output against the code. Alice and bob see different tool lists from the same gateway, bob's call to github.open_pr comes back 403, and a burst of eight calls from alice gets some of them rate limited. The demo ends by mutating a notes tool description on the backend, and the hash check drops it from alice's list and answers 409 on a call.

The part I'd read twice is where the pin comes from. pin_manifest hashes the backend descriptions when the module loads, so the manifest is only as trustworthy as the backend was at that moment. That is a decent stand-in for a reviewed manifest in a demo, but in a real gateway the hashes should come from an approval step, not from whatever the server says at startup.

I'd also be honest about what the sketch leaves out. The policy responsibility in the five-item list is covered only by hash pinning here. There is no PII redaction (exercise 2 adds it), no Rule of Two check, and no session id rewriting, because the backends are in-process stubs. The rate limiter keeps its buckets in memory, so a restart resets everyone to a full bucket, and tools/list drops a mutated tool without writing anything to the audit log, which is a gap I'd close before trusting it.

Exercises

  1. Run main.py. Make a call as an allowed user; then as a disallowed user; then a rate-limit-exceeded burst. Verify all three flows.

  2. Add a policy that redacts PII from results before returning to the client. Use a simple regex pass for SSN-shaped strings; note the gap (emails, phone numbers).

  3. Extend the audit log to emit OpenTelemetry GenAI spans. Phase 13 · 20 covers the exact attributes.

  4. Design an RBAC policy for a 50-developer team with five backends (notes, github, postgres, jira, slack). Who gets read-only on each? Who gets write?

  5. Read the Cloudflare enterprise MCP post top to bottom. Identify one feature Cloudflare ships that this stdlib gateway does not.

Key Terms

TermWhat people sayWhat it actually means
Gateway"MCP proxy"Centralizing server between clients and backends
Credential vaulting"Backend tokens stay server-side"Developers never see upstream tokens
Session-aware routing"Multi-backend session"Gateway multiplexes N backend sessions per developer session
Tool-hash pinning"Approved manifest"SHA256 of every approved tool description; blocks rug-pulls centrally
RBAC"Per-user policy"Role-based access control for tools and servers
Policy-as-code"Declarative rules"OPA/Rego, Kyverno, Styra policies enforced at gateway
Audit log"Who, what, when"Append-only event log for compliance
Rate limit"Per-user token bucket"Per-minute caps to prevent abuse
Official MCP Registry"Canonical upstream"registry.modelcontextprotocol.io, namespace-verified
Reverse-DNS naming"Registry namespace"io.github.user/server convention

Further Reading

Code

Ships With