Compare

MCP gateways compared

Six open-source MCP gateways and MCP Hangar, a policy enforcement plane for MCP that runs on a laptop, a VM or Kubernetes, compared on fifteen rows from caller authentication to tool contract integrity. Every cell links to code or docs at a pinned commit, verified on.

How we compared

  • Each repository was cloned at its default branch and every cell was read at that commit. The commit is listed under the table.
  • Code first: a search, then the whole file, then the path from a request handler or config to the mechanism. Docs are secondary evidence, and required for any feature a vendor sells separately.
  • A mechanism without a path to it from a request is partial, and the note says what is missing. A row that names two things is yes only when both are there.
  • no means the project says so, and links where.no evidence at <sha> means the code at that commit was searched and nothing was found. The two are not the same claim and are never shown as one.
  • MCP Hangar was verified the same way, from its own code at a release tag, not from its README or this site.

Rows 1 to 7 are adapted from the criteria ina vendor's comparison of open-source MCP gateways; no cell is taken from it. Closed-source and hosted products are not compared.

We build MCP Hangar. Every cell links to code or docs at a pinned commit, so you can check us instead of trusting us.

Legend

  • yes in the open-source code
  • partial some of it, or no path to it
  • enterprise enterprise edition, per the vendor
  • no stated by the project
  • no evidence at <sha> searched, not found
  • no, by design a stated non-goal

Comparison table

Fifteen rows, seven projects. Open a value to read its note; the arrows link the evidence.
RowBifrostApache-2.0ContextForgeApache-2.0ObotMITDocker MCP GatewayMITMicrosoft MCP GatewayMITKuadrant MCP GatewayApache-2.0MCP HangarMIT
A. What gateway comparisons usually ask
License and open-core boundary
enterprise

Apache-2.0; guardrails, SSO/SCIM, RBAC, signed audit logs, clustering, token exchange, Edge are enterprise

yes

Apache-2.0; no paid or enterprise-gated security features found in repo or docs

enterprise

MIT; Entra/Okta/OneLogin/JumpCloud/Keycloak/Auth0 SSO need a license key (free registration); >100 users/devices paid

enterprise

MIT; policy evaluation, policy audit and group tool scoping need Docker AI Governance (via sales)

yes

MIT; no paid or enterprise edition found in the repo or its docs

yes

Apache-2.0; no gated security features found in the repo or its docs

yes

MIT (core and operator); HANGAR_LICENSE_KEY is deprecated with no effect; no enterprise directories in either repo

Caller authentication
yes

Virtual-key headers; OAuth 2.1 AS on /mcp (DCR, PKCE S256, RFC 8707, RFC 9728, CIMD); user/SSO mode is enterprise

yes

Gateway JWT, API tokens, SSO (OIDC, Keycloak, Entra, ADFS); OAuth resource server, RFC 9728 PRM, audience check

yes

OAuth 2.1 AS: DCR, PKCE, resource param, RFC 9728 metadata, CIMD, private_key_jwt; API keys; OIDC/OAuth SSO providers

partial

One static Bearer token (MCP_GATEWAY_AUTH_TOKEN or generated) on SSE/streaming; stdio has none; no OAuth/JWT/SSO

yes

Entra ID JWT bearer (resource server); RFC 9728 protected resource metadata; no API keys, no own AS or DCR

partial

Serves RFC 9728 protected resource metadata; JWT/OIDC validation is a Kuadrant AuthPolicy from the guides, not shipped

yes

API keys; JWT via JWKS/OIDC discovery, multi-issuer, aud (RFC 8707); RFC 9728 metadata; resource server, no AS/DCR

Tool scoping
yes

Per-virtual-key tool allow-lists enforced at tools/list and tools/call; Virtual MCPs serve tool subsets at /mcp/<slug>

yes

Virtual servers expose a tool subset, enforced at tools/call; tokens scoped to server_id; team visibility

yes

vMCPs with per-component tool selection; per-user/group profiles grant tool subsets; API keys scoped to MCP server IDs

partial

Gateway-wide tool lists via --tools, tools.yaml, profiles; no per-caller scoping; Desktop policy can deny tools

yes

/mcp router: per-tool requiredRoles (Entra roles)/creator/mcp.admin filter list and call; adapters gated per server

partial

tools/list filtered by signed x-mcp-authorized JWT and MCPVirtualServer; tools/call denial is an AuthPolicy CEL sample

yes

allow/deny/approval lists per server, group, member and tenant; RBAC tool:invoke per role; front door lists per tenant

Upstream credentials
yes

Shared headers/OAuth and per-user OAuth/headers in OSS; RFC 8693 token exchange requires an enterprise SCIM IdP

yes

Shared (basic/bearer/headers/client_credentials); per-user OAuth auth-code and Vault creds; RFC 8693 exchange

yes

Per-user upstream OAuth tokens; shared fixed config or user-supplied values per vMCP policy; no RFC 8693 found

partial

Shared per-server secrets and OAuth tokens (DCR) via Desktop or credential helper; no per-user tokens, no RFC 8693

partial

Shared: env vars, one Azure workload identity, Key Vault headers in sample proxy; caller token dropped, id/roles sent

yes

Per-user token via URL elicitation (2025-11-25); client token passthrough, shared discovery creds; RFC 8693 by Authorino

partial

Shared: static api_key, bearer or basic per remote server, env for local servers; no per-user OAuth or RFC 8693 found

Argument and result inspection
partial

OSS Go .so plugin hooks see tool args and results, no validator ships; regex/secrets/LLM/ML guardrails are enterprise

yes

Args and results via tool_pre/post_invoke plugins (regex, lexicon, LLM Guard, Granite); opt-in; schema arg check

yes

Filters on tools/call args and results: regex/secrets rules, LLM judge, third-party ML services, webhooks

yes

Args and text results: regex secret scanner (block-secrets, default on); before/after exec, docker, http interceptors

partial

Args, deterministic: /mcp router checks Mcp-Param-* headers match body per inputSchema; no guardrails or result checks

yes

tools/call args and results checked by external NeMo Guardrails (rule or LLM rails); block or modify; fail-closed

partial

Args, deterministic: L7 secret regexes, size limit, tool/header rules; payload_size validator; no result checks found

Audit of tool calls
partial

Structured MCP tool-call log in OSS; HMAC-signed audit log (enterprise) covers admin events; refusals name permit

partial

Structured logs and tool.invoke spans with caller; plugin decision spans; no hash chain or signatures found

partial

Structured MCP audit log with per-filter status and reason for blocked calls; no hash chain or signatures found

partial

log-calls writes text lines (tool, arg shape, time); structured policy events go to Desktop; no signing or hash chain

partial

ILogger lines for router tool calls and denials (App Insights on gateway service); not signed; no refusal-explain tool

partial

Structured audit=true log line per tools/call (user, tool, server, status); not signed; AuthPolicy denials not logged

partial

Structured event store, SIEM export (CEF, LEEF, syslog, JSONL, OTLP); not signed or hash-chained; why explains refusals

Deployment model
yes

Binary via npx, Docker image, Helm chart (HPA, Postgres, multi-replica); no operator or CRDs; clustering is enterprise

yes

PyPI CLI, container image, docker-compose, Helm chart (2 replicas, HPA, Postgres, Redis); no own operator/CRDs

yes

Docker image, Helm chart, multi-replica on external PostgreSQL; darwin/linux/windows binaries; no K8s operator

partial

Docker CLI plugin binary, gateway Docker image and dind image, compose examples; no Helm, operator or shared-state HA

yes

Docker images (ghcr), K8s manifests, Azure Bicep/ARM (AKS, Cosmos); Redis/Cosmos shared store; no Helm or operator

yes

Docker image, Helm chart, CRDs + controller, OLM via Kuadrant Operator, Redis for multi-replica; standalone binary WIP

yes

pip CLI, Docker image, Helm charts for core (HPA, PDB, PostgreSQL) and operator (4 CRDs); replicas share a lease

B. Tool contract and call path
Tool contract integrity
no evidence
at 21e2263

SHA-256 over discovered tools dedups change callbacks; no approved digest checked at tools/call

no evidence
at 1f8b9bf

No digest or pin over tool definitions; refresh compares fields and overwrites them (see drift)

no evidence
at d8e5db5

No digest over tool definitions found; stored tool description is marked display-only, live description is served

no evidence
at 7e0f342

Image digests and signatures verified for mcp/ images; no digest over tool definitions found

no evidence
at cf9f5e9

No digest over tool definitions; router serves operator-registered definitions from the store as submitted

no evidence
at 98a4ccb

No digest or approved pin of tool definitions; last tools/list kept in memory and replaced on refresh

yes

SHA-256 (JCS) of name, description, inputSchema, outputSchema; opt-in pins checked on every tools/call; block default

Drift detection
no evidence
at 21e2263

Re-lists tools on tools/list_changed and republishes /mcp; no compare-and-refuse/withhold/warn on changed definitions

partial

list_changed and refresh overwrite changed definitions; CEL description policy re-run on fetch can disable a tool

no evidence
at d8e5db5

list_changed refreshes the tool catalog; catalog-entry snapshot digest flags server config updates, not tools

no evidence
at 7e0f342

tools/list_changed triggers a capability refresh; no comparison to known definitions found

no evidence
at cf9f5e9

No definition comparison; adapter tools/list and list_changed pass through; router reads store with 5-minute cache

partial

Re-fetch and list_changed diff description and schemas; change logged at INFO, new definition served, no refuse or hold

yes

list_changed and re-list compare to pins: block withholds and refuses; warn/audit emit event; opt-in new_tools: withhold

Pin bound to upstream identity
no evidence
at 21e2263

No tool-definition pin found, so no upstream identity bound into one

no evidence
at 1f8b9bf

No tool definition pin found; stored tool rows are keyed by gateway_id and upstream tool name

no evidence
at d8e5db5

No tool-definition pin found

no evidence
at 7e0f342

No tool definition pin found

no evidence
at cf9f5e9

No tool-definition pin exists

no evidence
at 98a4ccb

No tool definition pin exists

yes

Pin bound to upstream: remote origin or TLS key, image ref as written, or stdio command hash; pin --write records it

Human approval gate
no evidence
at 21e2263

No gateway hold or timeout; agent mode returns non-auto tool calls to the app; elicitation is forwarded, not approval

no evidence
at 1f8b9bf

No hold-for-approval on tools/call found; MCP elicitation pass-through and SSO signup approval are not this

no evidence
at d8e5db5

No gateway hold of tools/call found; built-in Inspector chat client asks the user before each call (client-side)

no evidence
at 7e0f342

No held tools/call pending human approval; MCP elicitation requests are forwarded to the client

no evidence
at cf9f5e9

No human-in-the-loop hold of tools/call found

no evidence
at 98a4ccb

No hold-for-approval on tools/call; URL elicitation collects per-user tokens and upstream elicitation is relayed

yes

approval_list or L7 requireApproval holds tools/call; refused on timeout; boot refused by default if gate absent

Egress and network enforcement
no evidence
at 21e2263

No NetworkPolicy/egress CRD for MCP servers; SSRF guard on outbound URLs; stdio servers run as host subprocesses

no evidence
at 1f8b9bf

No egress enforcement for MCP servers found; Helm NetworkPolicies are ingress rules for Postgres/Redis/PgBouncer/MinIO

yes

Helm NetworkPolicy blocks private ranges; per-server domain allowlist resource enforced via Aviatrix; default allow

partial

Docker-level: disableNetwork runs --network none; --block-network with allowHosts adds proxy containers; no Kubernetes

partial

Static ingress NetworkPolicies in manifests (gateway pods reach adapter/tool pods); no egress rules, none per server

no evidence
at 98a4ccb

Routes to MCP servers it does not run; generated NetworkPolicies cover controller and broker pods, egress open

yes

MCPEgressPolicy: NetworkPolicy or Cilium backstop, Vanilla denies hostnames; Audit default; namespace deny opt-in

C. Rows Hangar loses
LLM gateway
yes

Multi-provider routing with fallbacks; per-virtual-key budgets, token and request rate limits

partial

OpenAI-compatible proxy to OpenAI/Azure/Anthropic/Bedrock/watsonx/Ollama; per-token request limits; no budgets

yes

LLM proxy on Bifrost with provider routing, fallbacks, per-profile budgets on spend, tokens or requests per user

no evidence
at 7e0f342

No LLM provider routing or budgets; OpenAI API is used for find-tools embeddings

no evidence
at cf9f5e9

No LLM traffic proxy; preview agent runner calls one Azure OpenAI/Foundry deployment as a client

no

VISION non-goal: not replacing Envoy AI Gateway or its AI gateway capabilities; rate limits apply to MCP traffic

no, by design

README non-goal: no model routing, provider failover or token budgets; none found in code at 0c70812

Desktop and device MCP inventory
enterprise

Bifrost Edge endpoint agent inventories MCP servers in desktop AI app configs; needs Enterprise with Edge entitlement

no evidence
at 1f8b9bf

No scanning of desktop MCP client configs or endpoint agent found

yes

Obot Sentry agent (separate MIT repo) uploads scans of MCP servers, skills, clients; inventory views in server

partial

CLI reads local MCP client configs (Claude, Cursor, Codex, others) on one machine; no fleet inventory or endpoint agent

no evidence
at cf9f5e9

No desktop/device MCP config discovery or endpoint agent found

no evidence
at 98a4ccb

No desktop or endpoint MCP config discovery found

partial

mcp-hangar init reads Claude Desktop, Claude Code and Cursor configs on one machine and imports them; no fleet agent

Sandboxed server runtime and catalog UI
partial

Catalog: MCP library with browse/install UI; runtime: stdio servers as host subprocesses, no sandbox

partial

Catalog: entries registered from the admin UI and API; no container or sandbox runtime found

yes

Runtime: Docker containers or K8s pods; catalog with browse UI and API

partial

Runtime: each server in its own Docker container; catalog CLI in OSS, browse UI in Docker Desktop

partial

Runtime: images deployed as K8s StatefulSets; portal registers images by name, no catalog

no evidence
at 98a4ccb

Does not launch MCP servers; discover_tools meta-tool lists registered tools, no install catalog

partial

Runtime: Docker/Podman (read-only, cap-drop) and operator Deployments; catalog: 4-entry CLI list, no UI

Where Hangar is the wrong choice

Hangar decides what happens to a tool call. It does not route model traffic, it reads the MCP client configs on one machine but keeps no inventory across a fleet of them, and its server list is a short CLI list, not a catalog to browse. If one of those is the job, or the platform around it is already chosen, these fit better:

  • LLM routing, provider failover and model budgets: Bifrost, which is an LLM gateway with MCP built in.
  • An inventory of the MCP servers on every developer's machine: Obot, whose Sentry agent reports them to the server.
  • Isolating MCP servers on a developer machine: Docker MCP Gateway, which runs each server in its own container.
  • Federating REST and gRPC services as MCP tools: ContextForge.
  • An Azure and Entra ID estate: Microsoft MCP Gateway.
  • A cluster already run on Envoy, Gateway API or Istio: Kuadrant MCP Gateway, which plugs into the policy you have.

The empty row

Tool contract integrity is a digest over a tool's name, description and schemas, recorded when the tool is approved and checked when it is called. A pinned tool whose definition changes after you said yes to it is refused or withheld, not served. At the commits above, the code of the other 6 projects shows no evidence of one. How digest pinning works and the MCP CVE ledger show why it matters.

What was verified, and when

ProjectRepositoryCommitVerified
Bifrostmaximhq/bifrostverified at 21e2263
ContextForgeIBM/mcp-context-forgeverified at 1f8b9bf
Obotobot-platform/obotverified at d8e5db5
Docker MCP Gatewaydocker/mcp-gatewayverified at 7e0f342
Microsoft MCP Gatewaymicrosoft/mcp-gatewayverified at cf9f5e9
Kuadrant MCP GatewayKuadrant/mcp-gatewayverified at 98a4ccb
MCP Hangarmcp-hangar/mcp-hangarverified at 0c70812 (2.36.6)
mcp-hangar/mcp-hangar-operatorverified at 71afc22 (operator 0.17.39)
mcp-hangar/helm-chartsverified at 8a0ffe7 (charts 0.15.60 / 0.12.55)

Found an error? Open an issue with the cell and a link, and it is re-read at the project's current commit. The same table is inmarkdown.