Cortex Gateway
Cortex Gateway is a federated MCP gateway that provides a single, OAuth-protected entry point to multiple internal backends and native MCP servers, enforcing zero-trust principles for AI agents.
Core capabilities:
whoami— Returns your full OAuth identity (email, sub, scopes, client, jti) and aggregated role/identity information from all federated backends, helping you understand who you are and what you're permitted to do.list_cortex_resources— Discovers all MCP resources exposed by the gateway (e.g., architecture docs, dynamic backend resources via URI templates). Useful for clients that don't natively surface the MCP resources primitive.read_cortex_resource— Reads a specific resource by URI (e.g.,cortex://architecture), returning Markdown or JSON content.report_missing_capability— Files a signal ticket when no available tool fulfills a request, or an existing tool is insufficient. Supports severity levels (blocking,inconvenient,nice_to_have), auto-deduplicates within 24 hours, and returns a ticket ID.list_cortex_tickets— Views your previously filed capability tickets, filterable by status, severity, and backend, so you can track progress and avoid duplicate filings.
Under the hood, the gateway aggregates tools from multiple backends into a unified catalog, dynamically discovers new tools every 60 seconds, enforces per-user OAuth 2.1 scope-based permissions, and maintains a pseudonymized audit trail of all tool calls.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Cortex Gatewayshow me the tools I have access to"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Cortex Gateway
A federated MCP gateway: one spec-compliant, OAuth-protected MCP server in front of N plain-HTTP backends.
Your business apps stay ordinary web services. Each one exposes a single
POST /api/cortex/backend endpoint (a ~120-line contract, no MCP library, no
stdio). The gateway discovers their tools, merges them into one MCP catalog,
enforces OAuth 2.1 + scopes, routes tools/call to the owning backend, and
keeps a pseudonymized audit trail.
Built for one requirement: everyone in a company should be able to hand their own agent the keys — with exactly that person's rights, nothing more, nothing less. And when agents become autonomous assistants, the answer stays the same: the agent borrows the person's identity, the apps keep enforcing that person's rights. The gateway decides nothing, so there is nothing new to trust.
Put another way: zero-trust principles for AI agents — the missing link between your IAM (who your users are, what they may do) and the MCP ecosystem (how agents call tools). Not a full ZTNA product; the identity-and-access layer for agents.
A backend is a dedicated MCP reduced to its essence: a tool catalog plus tool invocation (and optional prompts/resources) over bare HTTP JSON-RPC — the transport and lifecycle machinery (initialize, sessions, SSE, version negotiation) lives once, in the gateway. Because the contract is a semantic subset of MCP, a native MCP server can also be federated through the built-in MCP→backend proxy adapter (docs/mcp-adapter.md).
[MCP agent: Claude Desktop / claude.ai Custom Connector / any MCP client]
│ HTTPS + OAuth 2.1 JWT (Bearer)
▼
[cortex-gateway] ←— thin gateway, no business logic
│ HTTPS + the same JWT propagated (RFC 8707)
▼
[your backends] ←— domain owners, plain HTTP, own their ACLsWhy
Permissions match the underlying app, automatically, at the user level. The gateway never copies or mirrors permissions — it propagates the real user identity (your JWT to first-party backends, the user's own linked token to proxied third-party MCP servers), so each app's native permission model applies per user, with nothing to sync and no service-account flattening. Unlike hosted tool aggregators, the token vault and the audit trail stay on your infrastructure.
One perimeter, not N connectors. Wiring each app as its own MCP connector also keeps native permissions — and leaves you with N consents, N token stores, no shared audit, no cross-app entitlements, and a flooded tool list. The gateway collapses that to one OAuth surface without giving up the per-user model: aggregation without permission loss.
Zero MCP lock-in in your apps. Backends speak a minimal JSON-RPC contract over plain HTTP. Remove the gateway and you can still call them directly (tests, batch jobs, other integrations).
One JWT, N backends. The agent authenticates once; the gateway propagates the token; every backend re-validates it and applies its own permissions. Revocation at the authorization server cuts everything.
Failure isolation. An unreachable backend just disappears from
tools/list; the rest keeps working.Context-aware federation. Backend filtering and a compact "search" mode keep the tool catalog from flooding the agent's context (docs/tool-search-mode.md).
Agent feedback loop. Agents can file
report_missing_capabilitytickets when a tool is missing or insufficient — deduplicated, triaged, optionally pushed to a webhook when blocking.
Related MCP server: Multi-MCP Hub
Use cases
Company-wide agent surface. An organization runs N internal apps (CRM, quality docs, billing, analytics...). Each app adds the ~120-line backend endpoint; the gateway exposes them as ONE MCP connector protected by the company's SSO. Employees plug a single URL into Claude Desktop / claude.ai and get exactly the tools their token scopes allow, with a central audit trail. This is the setup the gateway was born in.
Product builder. You ship several products and want agents (yours or your customers') to operate them. Instead of maintaining one MCP server per product, every product implements the backend contract and the gateway is your single, versioned, OAuth-protected agent API. Adding a product to the agent surface is one env var.
Thematic hub / curated registry. Run a gateway as a topic endpoint —
e.g. "all open-data tools for domain X" — that federates several providers
behind one URL with one token. The scope model gives you per-provider
opt-in, get_help/get_snapshot give agents self-describing discovery, and
the audit trail tells you what is actually used. Providers either speak the
(deliberately tiny) backend contract natively, or — for off-the-shelf MCP
servers — get fronted by the built-in MCP→backend proxy adapter
(docs/mcp-adapter.md).
Free / paid tool tiers. Scopes are entitlements. Let your authorization
server grant mcp:yourapp:basic to free users and mcp:yourapp:pro to
paying ones (your billing webhook updates the grant): the gateway then shows
and allows each caller exactly the tools of their plan — no paywall logic in
the gateway or the backends, tools just declare their scope. Revocation and
downgrades propagate through the normal OAuth chain.
Federating native MCP servers (adapter, beta)
The built-in MCP→backend proxy adapter lets a bundle mix contract backends and off-the-shelf native MCP servers (Canva, Figma, ...): the adapter is an MCP client downstream (initialize, sessions, SSE framing) and a plain backend upstream, so the gateway core does not change. Per-user downstream OAuth is handled by a token vault (AES-256-GCM at rest) and a linking flow (RFC 9728 discovery, Dynamic Client Registration, PKCE): each user consents once per provider, then agents are identified on the whole bundle with a single Cortex token. See docs/mcp-adapter.md for a worked "design bundle" example (Canva + Figma + your own backend).
Roadmap
Machine identity for discovery — replace the static technical token with a
client_credentialsflow once your AS supports it.Shared event bus / rate-limit store — for multi-instance deployments.
Features
MCP spec 2025-06-18 (Streamable HTTP transport: POST JSON-RPC, GET SSE for
listChangednotifications, DELETE session termination)Primitives: tools, resources (incl. URI templates), prompts
OAuth 2.1 resource server: JWKS verification, audience per resource (RFC 8707), protected-resource metadata (RFC 9728), optional RFC 7662 introspection for revocation
Scope-based visibility: agents only see (and can call) the tools their token scopes allow;
scopes_supportedin discovery is derived live from the federated catalogDynamic discovery: backends are polled every 60s; new tools appear without redeploying the gateway, with SSE
tools/list_changedpushBuiltins:
whoami(aggregated identity across backends),find_tools,report_missing_capability,list_cortex_tickets,list_cortex_resources,read_cortex_resource, plus a self-describingcortex://architectureresource generated liveAudit trail: one JSON line per call on stdout (hashed email, hashed params) + optional PostgreSQL persistence with retention cron
Origin allow-list (anti DNS-rebinding), per-token rate limiting, optional pool sandbox
Quickstart (no OAuth server needed)
git clone https://github.com/wellknownmcp/cortex-gateway
cd cortex-gateway
npm install
# 1. Start the demo backend (dependency-free)
node examples/demo-backend/server.mjs &
# 2. Configure the gateway
cat > .env.local <<'EOF'
OAUTH_ISSUER=https://auth.example.com
CORTEX_BACKENDS=demo
CORTEX_BACKEND_DEMO_URL=http://127.0.0.1:4820
CORTEX_TECHNICAL_TOKEN=demo-technical-token
CORTEX_DEV_BYPASS_TOKEN=dev-secret
CORTEX_DEV_BYPASS_SCOPES=mcp:demo:read
EOF
# 3. Run it
npm run dev
# 4. Talk MCP (dev bypass replaces the Bearer JWT locally)
curl -s http://localhost:3213/mcp \
-H 'Content-Type: application/json' \
-H 'X-Dev-Mode: dev-secret' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'
# → whoami, ..., demo_get_help, demo_echo, demo_get_time
curl -s http://localhost:3213/mcp \
-H 'Content-Type: application/json' \
-H 'X-Dev-Mode: dev-secret' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"demo_echo","arguments":{"message":"hello"}}}' | jqIn production you point OAUTH_ISSUER at your OAuth 2.1 authorization
server (any server that issues RS256 JWTs with a JWKS endpoint and supports
the scope claim), and MCP clients connect to https://your-host/mcp with
a Bearer token whose aud is the gateway's canonical URI.
stdio bridge (for stdio-only clients and directory sandboxes)
The gateway is a remote Streamable HTTP server, but some MCP clients — and
the Docker inspection harnesses of directories like Glama — only speak the
stdio transport. scripts/stdio-bridge.mjs bridges the two: it boots the
production build against an ephemeral local OAuth issuer (the real JWT
verification path, no bypass), mints itself a short-lived token, and relays
newline-delimited JSON-RPC between stdin/stdout and POST /mcp.
npm run build
npm run start:stdio # stdio MCP server on stdin/stdoutSelf-granted scopes come from BRIDGE_SCOPES (gateway builtins need none);
the gateway port from BRIDGE_GATEWAY_PORT (default 3213). Design notes and
the gotchas (stdout purity, protocol-version negotiation, session echo):
https://cortex-gateway.dev/guides/expose-http-mcp-server-over-stdio/.
Adding a backend
Implement the contract in your app — one POST endpoint,
list_tools+ your tools (docs/backend-contract.md, reference implementation inexamples/demo-backend/).Declare it:
CORTEX_BACKENDS=demo,docs CORTEX_BACKEND_DOCS_URL=http://127.0.0.1:4001Done. The gateway discovers
docs_*tools within 60s and pushestools/list_changedto connected clients.
Configuration
Everything is env-driven — see .env.example for the full annotated list. The essentials:
Variable | Required | Purpose |
| prod | Canonical MCP resource URI (RFC 9728), default JWT audience |
| yes | Your OAuth 2.1 authorization server |
| yes | Federated backends |
| yes | Static token for catalog discovery (catalog methods only) |
| prod | Web origins allowed (exact or |
| no | PostgreSQL for audit persistence + gateway tickets |
| no | Webhook for blocking missing-capability tickets |
| no |
|
Security model
Agent access is secured by construction, not by gateway policy. The properties below are what to demand from any MCP tooling you wire into an AI app:
OAuth 2.1, not shared API keys — every caller authenticates as themselves; tokens are per-user, scoped and revocable.
No permission flattening — the real user's identity is propagated to each backend, so no over-privileged service account exists and the agent gets exactly the user's own rights.
Least privilege — the tool catalog is scope-filtered per caller; agents only see the tools their token allows.
Verifiable — the whole OAuth discovery chain is walkable without a token, so you (or a third-party scanner) can confirm the posture before connecting.
Under the hood:
The gateway decides nothing about business permissions. OAuth scope is the front door (checked twice: gateway + backend); application roles and ACLs live in each backend.
The static technical token can only reach catalog methods (src/contract/static-token.ts); every data method requires the end user's JWT.
Audit is pseudonymized by design (hashed email, hashed params). Pseudonymized is not anonymous: hashed identifiers remain personal data under GDPR Art. 4(5), so the audit trail stays in your record of processing and needs a retention period.
Sessions are bound to the token's
sub; foreign session ids get 404.
Compliance. These are the controls audits test for on automated access: least-privilege scopes, per-user identity (no over-privileged service account), a per-call attributable audit trail, and central revocation. They map to ISO 27001:2022 Annex A access-control and logging controls (A.5.15, A.5.16, A.5.17, A.5.18, A.8.2, A.8.15, A.8.16) and to SOC 2 CC6/CC7 — both of which apply today. The EU AI Act articles usually cited (Art. 12 record-keeping, Art. 14 human oversight) govern high-risk AI systems only, and after the 2026 Digital Omnibus those obligations were deferred to 2 Dec 2027 (stand-alone Annex III) and 2 Aug 2028 (Annex I embedded); most internal agent deployments are not high-risk, and a gateway is access infrastructure rather than an AI system. Self-hosted means the audit trail and token vault stay in your perimeter — no extra sub-processor under GDPR Art. 28, none in your SOC 2 scope. Cortex supplies the controls, not a certification. Full mapping: https://cortex-gateway.dev/answers/ai-agent-compliance-controls/
Development
npm run typecheck # tsc --noEmit
npm test # vitest
npm run build # prisma generate + next buildThe database is optional in every environment: without CORTEX_DATABASE_URL
the audit stays on stdout and gateway-local tickets are disabled.
License
Maintenance
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wellknownmcp/cortex-gateway'
If you have feedback or need assistance with the MCP directory API, please join our Discord server