MCP网关

mcp-gateway 是一个位于 AI 客户端与 MCP 服务器之间的统一网关,提供认证、权限控制、路由与可观测性,适用于集中管理 AI 工具调用和 MCP 服务访问。

  • by HarrisonCN
  • TypeScript
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 HarrisonCN/mcp-gateway

使用说明

mcp-gateway

English · 简体中文

17.0.1 is the current release — released by owner decision; external security review and dedicated-hardware soak not yet performed. 15.0.0 and 16.0.0 never shipped as stable releases, so 17.0.0 is the first stable major after 14.9 and carries every breaking change of 15.0, 16.0 and 17.0 (Node.js ≥ 24, config schema v13 only, plugin API v6 only, no inline module plugins). Test it in staging first; see release gates. Upgrading from 14.9: migrating to v15 · v16 · v17. Staying on 14.9: npm i @winstonsayno/mcp-gateway@v14-lts, image :14.

One authenticated, observable endpoint in front of all your MCP servers.

mcp-gateway sits between AI clients (Claude Code, Cursor, your own agents, LLM apps, web and mobile front-ends) and the Model Context Protocol servers they use. Clients connect once — over MCP Streamable HTTP at /mcp or a REST API under /api/v1 — and the gateway authenticates the caller, checks what it may do, routes the call to the right upstream and records what happened. Keys, scopes, rate limits, policy, logs and metrics live in one place instead of in every client.

Current release: 17.0.1 (npm latest). Live dashboard demo with simulated traffic, no backend: https://harrisoncn.github.io/mcp-gateway/

Contents

Architecture

flowchart LR
  subgraph Clients
    A["MCP clients<br/>Claude Code · Cursor · agents"]
    B["LLM apps<br/>OpenAI · Grok · DeepSeek · Claude"]
    C["Web / mobile apps<br/>JS · Kotlin · Swift · Python · Go"]
  end

  subgraph GW["mcp-gateway"]
    direction TB
    AU["Authentication<br/>API keys · JWT · OAuth 2.1"]
    PO["Authorization & policy<br/>scopes · tenants · tool policy · rate limits"]
    RT["Routing<br/>splits · load balancing · failover"]
    SM["Security modules<br/>DLP · sanitize · approvals · …"]
    CA["Cache<br/>tool cache · semantic cache"]
    FA["Final authorization<br/>against the routed target"]
    AD[("Audit log · metrics · traces")]
    AU --> PO --> RT --> CA --> SM --> FA
    FA -.-> AD
  end

  A -- "/mcp (Streamable HTTP)" --> AU
  B -- "/api/v1 (REST)" --> AU
  C -- "/api/v1 or /mcp" --> AU

  FA -- stdio --> U1["Local MCP servers"]
  FA -- "Streamable HTTP · SSE" --> U2["Remote MCP servers"]
  FA -- WebSocket --> U3["WebSocket MCP servers"]

Each call is authenticated, authorized against the caller's scope, routed (a routing split is decided and authorized before any cache lookup), passed through the configured security modules and then authorized once more against the final target right before it is sent upstream. Feature modules are loaded on demand: a module is only imported when its section is present in the config.

Key features

Core gateway

  • MCP endpoint at /mcp (Streamable HTTP, protocol revisions 2025-11-25 back to 2024-11-05) that aggregates tools, resources and prompts from every upstream, with progress, cancellation, logging, completions and subscriptions.
  • Upstream transports: stdio, streamable-http, legacy sse and websocket, with per-server headers and env.
  • REST API under /api/v1: tool discovery and calls, resources, prompts, request history, live stats (SSE). GET /api/v1/tools?format=openai|openai-responses|anthropic returns function-calling schemas for LLM APIs.
  • Reconnect with backoff and jitter, MCP ping health checks, per-server concurrency limits, timeouts and tool allow / deny filters.
  • Hot reload of servers, keys, limits and CORS when the config file changes (start --no-watch to disable).

Access control

  • API keys (constant-time compare, sha256: digests, expiry / disable), JWT (HMAC, PEM or JWKS; issuer / audience / exp checks) and OAuth 2.1 resource server per the MCP authorization spec. Misconfiguration fails closed.
  • Per-key scopes (server and tool globs, own rate limit) for keys and JWT claims, enforced on REST and /mcp; tenants with roles; sliding-window rate limits; brute-force lockout.
  • Network guards: IP allowlist, Host / Origin checks against DNS rebinding, body and argument size limits, security headers with a hash-based CSP. stdio servers run with an environment allowlist and optional uid / gid, cwd and sandbox wrapper (stdio isolation).

Operations

  • Prometheus metrics, OpenTelemetry tracing, optional SQLite audit log, secret redaction in logs, history and API output.
  • Web dashboard at /dashboard: guided setup, live traffic, latency and errors, server health, tool playground, request history.
  • Liveness / readiness probes, signed container image, Helm chart, Kubernetes operator.
  • GitOps (14.7): config directories with environment overlays and secrets by reference, env diffs, release plans with policy simulation, ed25519-signed releases with required approvers, enforcement and drift detection (GitOps guide).
  • Operations console (14.8): cluster status, per-call traces with step timings, policy denial explanations with the config path, incident timeline and a troubleshooting wizard, with operator / viewer roles (operations console).
  • CLI: init, validate, diff / apply, gen-key / hash-key, migrate, bench, conformance, desktop, policy test, plugin, pq, operator.
  • Embeddable as a library: import { Gateway, loadConfig } from '@winstonsayno/mcp-gateway'.

Extended modules — opt in under features:; each has a guide in docs/guides. Among them: Cedar / OPA policies, DLP, prompt-injection sanitising, approval flows, semantic cache, rollouts and blue/green, time-travel replay, real-time budgets, task graphs, OpenAI / A2A bridges, kernel plugin SDK and multi-region. These modules are compact and unit-tested but have seen far less real-world use than the core; test them in your environment before relying on one.

Experimental — confidential computing / TEE attestation, post-quantum TLS, edge autonomy, privacy computing and post-quantum identity. validate, startup and GET /api/v1/security print an EXPERIMENTAL notice when one is enabled; each guide lists what it does not do.

Quick start

Requires Node.js 22 or newer.

npm / npx

npx @winstonsayno/mcp-gateway init      # writes mcp-gateway.yml (loopback, two example stdio servers)
npx @winstonsayno/mcp-gateway gen-key   # prints a key for clients and its sha256 digest for the config
# add the digest to mcp-gateway.yml (see Minimal configuration below), then:
npx @winstonsayno/mcp-gateway validate --strict   # schema check; exits 2 on security warnings
npx @winstonsayno/mcp-gateway start

Or install it globally: npm i -g @winstonsayno/mcp-gateway && mcp-gateway start. The dashboard is at http://localhost:4000/dashboard.

Without auth the gateway refuses to start on a non-loopback address. Configure auth before binding to 0.0.0.0, or — only on a trusted network — pass start --insecure (security.insecure: true).

Docker (GHCR)

Multi-arch images (linux/amd64, linux/arm64) are published as ghcr.io/harrisoncn/mcp-gateway with tags <version>, <major>.<minor>, <major> and latest. They run as the unprivileged node user and read /app/mcp-gateway.yml.

docker run -d -p 4000:4000 \
  -v "$PWD/mcp-gateway.yml:/app/mcp-gateway.yml:ro" \
  -v mcp-gateway-data:/app/data \
  -e MCP_GATEWAY_HOST=0.0.0.0 \
  -e MCP_GATEWAY_API_KEYS=sha256:<digest from gen-key> \
  ghcr.io/harrisoncn/mcp-gateway:17

MCP_GATEWAY_API_KEYS (comma-separated, plain or sha256:<hex>) turns on API-key auth without editing the file, and MCP_GATEWAY_HOST overrides the loopback host written by init so the published port is reachable. stdio servers run inside the container, which ships Node.js / npm; install anything else (Python, uvx, …) in a derived image. A Compose example with Prometheus is in examples/docker.

Every image is signed with cosign (keyless, GitHub OIDC) and carries SLSA provenance and SBOM attestations. Verify before you deploy, and pin the digest it prints:

cosign verify ghcr.io/harrisoncn/mcp-gateway:17.0.1 \
  --certificate-identity-regexp '^https://github.com/HarrisonCN/mcp-gateway/.github/workflows/docker.yml@' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

More in supply chain.

Kubernetes (Helm)

The chart lives in this repository (it is not published to a chart registry) and requires an API key:

git clone https://github.com/HarrisonCN/mcp-gateway.git && cd mcp-gateway
kubectl create secret generic gw-secrets --from-literal=MCP_GATEWAY_API_KEYS=sha256:<digest from gen-key>
helm install gw ./deploy/helm/mcp-gateway --set existingSecret=gw-secrets

Gateway config goes in the chart's config: value. Pods run non-root with a read-only root filesystem; probes use /api/v1/health/live and /api/v1/health/ready; HPA, PDB, ServiceMonitor and the operator (McpGateway CRD) are off by default. See the chart README and the Kubernetes guide.

Minimal configuration

mcp-gateway.yml — an authenticated gateway with one stdio server:

version: 13            # config schema v13 (17.0 refuses v12 files: mcp-gateway config migrate --to v13)
host: 127.0.0.1        # 0.0.0.0 only together with auth
port: 4000

auth:
  strategy: api-key
  apiKeys:
    - sha256:<digest printed by gen-key>

security:
  dnsRebindingProtection: true   # Host / Origin checks on /mcp and the API
  authLockout: true              # lock out IPs after repeated failed keys

servers:
  - id: filesystem
    name: Filesystem
    transport: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

Every key, environment override, scope and module section is in the configuration reference; more complete files are in examples/.

Connect clients and LLMs

# REST
curl -H "Authorization: Bearer $KEY" http://localhost:4000/api/v1/tools
curl -X POST http://localhost:4000/api/v1/tools/call \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"tool": "read_text_file", "arguments": {"path": "/tmp/hello.txt"}}'

# Claude Code
claude mcp add --transport http gateway http://localhost:4000/mcp --header "Authorization: Bearer $KEY"
// Cursor: ~/.cursor/mcp.json
{ "mcpServers": { "gateway": { "url": "http://localhost:4000/mcp", "headers": { "Authorization": "Bearer <key>" } } } }

stdio-only clients can bridge with mcp-remote: npx mcp-remote http://localhost:4000/mcp --header "Authorization: Bearer <key>".

Any LLM with function calling. The gateway does not call a model itself. GET /api/v1/tools?format=openai (Chat Completions — OpenAI, DeepSeek and other compatible APIs), format=openai-responses (Responses API — OpenAI, xAI Grok) or format=anthropic (Claude Messages API) returns the tools the caller may use plus a mapping from each LLM tool name to the gateway { server, tool }; execute the model's tool calls with POST /api/v1/tools/call. A complete loop is in examples/llm-tools; the OpenAI-compatible bridge can also run the loop inside the gateway. These are plain HTTP integrations, not partnerships with model vendors.

Web pages and apps. Use REST or the client libraries — JS / TypeScript (@winstonsayno/mcp-gateway-client), Kotlin / Android, Swift, Python, Go. Never ship a long-lived API key in a browser bundle or app binary: put your backend in the middle, or have it mint short-lived scoped JWTs (auth.jwt.requireExp, maxTokenAgeSeconds, mcp_servers / mcp_tools claims) and restrict origins with cors.origins and mcp.allowedOrigins.

Security model

The gateway executes tool calls that can read files, call APIs and spend money: treat it as a privileged service. Operators are root-equivalent (they can change which commands stdio servers run), so give end users scoped keys or tenant roles.

Authorization is re-checked after rerouting. A call can be moved to another server after the first check — by a routing split, rollouts, blue-green, self-healing or a realtime-budgets downgrade. Right before the upstream send, the gateway authorizes the call again against its final target (caller scope, tool exposure, tool policy, data residency and the security guard modules) and then freezes that target. A refused reroute answers -32003 with data.decision: "reroute-denied".

Failed modules have an explicit failure policy. Every feature module declares one:

Policy Modules While the module is configured but failed
closed security and enforcement: dlp, sanitize, agent-identity, policy-engine, approval-flows, confidential, privacy, anomaly, multimodal; quota: console, realtime-budgets the calls it governs are refused with -32026 (data.decision: "module-failed"); the gateway keeps running
open analytics and optimisation, e.g. genai-otel, billing, sla, semantic-cache, rollouts its hooks are skipped
degrade e.g. offline, self-healing, blue-green, edge-autonomy hooks skipped; results carry _meta["mcp-gateway/degraded"]

Fail-closed is scoped: a failed module refuses only the calls in its own configured scope (for example dlp.servers); when that scope cannot be determined it refuses every tool call. Security modules are always closed; modules.failurePolicy may override only console, realtime-budgets and billing. GET /api/v1/admin/kernel shows each module's state and policy.

Hot reload is staged: Prepare → Validate → Commit. New connections, catalog and modules are built aside; servers added by a reload stay hidden (not listed, routed or authorized) until the commit, and removed servers are only disconnected after a successful commit. An invalid config is rejected and the running one keeps serving.

Error codes on /mcp (REST answers 403 with the same code):

Code Meaning
-32003 forbidden: outside the caller's scope, denied by policy, or reroute-denied
-32026 a closed module covering this call has failed (module-failed)

Secure defaults and checks. No auth means loopback only; the Helm chart requires an API key; stdio servers do not inherit MCP_GATEWAY_* variables. mcp-gateway validate --strict fails on security warnings and GET /api/v1/security reports the running posture. CI runs CodeQL, OpenSSF Scorecard, Trivy, npm audit and property tests; there has been no independent third-party audit. Details: threat model, deployment checklist.

Advisories. MGW-2026-001 … MGW-2026-013 (reroute re-authorization, fail-closed modules, per-gateway module failures, transactional reload, split-aware cache keys, staged reload, delegated-call identity, issuer-qualified client ids, split-target credentials, final-argument checks, calls in flight across a reload, Redis reply alignment) are fixed in 13.3.0, with backports of the applicable fixes in 12.0.6 and 10.9.7; MGW-2026-013 (glob-matching ReDoS via agent-identity token scopes) is fixed in 13.5.0, 12.0.8 and 10.9.9; MGW-2026-014 (Redis commands before AUTH / SELECT on reconnect) is fixed in 13.7.0, 12.0.10 and 10.9.11 — see SECURITY.md. Report vulnerabilities privately through GitHub private vulnerability reporting (see SECURITY.md), never with details in public issues.

Observability

  • Metrics — GET /api/v1/metrics returns JSON aggregates (requests, errors, latency, per-server state). With monitor.prometheus: true, Prometheus text is served at /metrics and /api/v1/metrics?format=prometheus. Metric names include mcp_gateway_requests_total, mcp_gateway_errors_total, mcp_gateway_request_duration_seconds, mcp_gateway_server_up, mcp_gateway_authz_denials_total, mcp_gateway_reroute_denials_total, mcp_gateway_module_failure_denials_total and mcp_gateway_degraded_calls_total. Metrics are public by default; require auth with auth.protect.metrics.
  • Audit log — audit.enabled: true keeps request metadata (never arguments or results) in SQLite via the built-in node:sqlite; GET /api/v1/requests queries it with filters and paging, and audit.export forwards records to a SIEM. Refused reroutes and calls refused by a failed module are recorded too.
  • Tracing — OpenTelemetry spans per upstream call, exported over OTLP/HTTP without an SDK (observability.tracing), with W3C traceparent propagation.
  • Health — /api/v1/health/live, /api/v1/health/ready, /api/v1/health; live stats at /api/v1/stats and the SSE stream /api/v1/events, which feed the dashboard.

See Observability and Audit log.

Supported versions

Line Latest npm dist-tag Image tag Status
17.x 17.0.1 latest, next :17, :latest Current — new features, bug and security fixes. Released by owner decision; external security review and dedicated-hardware soak not yet performed
15.x / 16.x — — — Prerelease lines only (15.0.0-rc.4, 16.0.0-rc.1); never shipped as stable — their changes are in 17.0.0
14.x 14.9.2 v14-lts :14 Maintained — security and critical bug fixes for existing users; upgrade to 17.x
13.x 13.9.5 v13-lts :13 Maintained — security and critical bug fixes, at least until 15.0.0 ships and no earlier than 2027-04-30; upgrade to 14.x
12.x 12.0.15 v12-0 :12 Superseded — carries the MGW-2026-001, -005, -007, -008, -009, -010, -011, -012, -013, -014, -015, -016, -017, -018 and -019 fixes; upgrade to 13.x
11.x 11.2.0 — :11 Superseded — upgrade to 13.x
10.x (LTS) 10.9.16 v10-lts :10 Bug and security fixes until 2027-10-31, then security fixes only until 2028-10-31
< 10.0 — — — Unsupported — upgrade with mcp-gateway migrate
npm i @winstonsayno/mcp-gateway            # 17.x
npm i @winstonsayno/mcp-gateway@v14-lts    # 14.9.x
npm i @winstonsayno/mcp-gateway@v10-lts    # 10.x LTS

Upgrading: from 10.x run npx @winstonsayno/mcp-gateway@13 migrate --write (config schema v10 → v11, see Migrating to 11.0); from 11.x / 12.x no config migration is needed — read Migrating to 12.0 and Migrating to 13.0.

The project follows Semantic Versioning. Within a major line the /api/v1 REST API, /mcp behaviour, the config schema, CLI commands and flags, root library exports and Prometheus metric names change only in backward-compatible ways — see stability and versioning.

Documentation

Getting started First gateway, step by step
Configuration Every config key, env overrides, scopes, hot reload
API reference REST /api/v1, admin API, /mcp, error codes
Deployment Docker, Kubernetes, reverse proxy, systemd, security checklist
Guides One page per module, plus migration guides
Security · Threat model Advisories, hardening, trust boundaries
Changelog Every release
Dashboard The built-in web UI

Contributing

git clone https://github.com/HarrisonCN/mcp-gateway.git && cd mcp-gateway
npm ci
npm run typecheck && npm test
npm run dev -- start -c examples/basic/mcp-gateway.yml

See CONTRIBUTING.md. When a change is user-facing, update both READMEs (English and 简体中文).

License

MIT © 2026 HarrisonCN