loading…
Search for a command to run...
loading…
Universal MCP gateway with single-port multiplexing and Meta-MCP. 4 meta-tools replace 100+ registrations, saving 95% context window. Hot-reloadable capabilitie
Universal MCP gateway with single-port multiplexing and Meta-MCP. 4 meta-tools replace 100+ registrations, saving 95% context window. Hot-reloadable capabilities, OpenAPI auto-import, 42 starter capabilities (25 zero-config).
CI Crates.io Downloads Rust License unsafe forbidden dependency status Capabilities MCP Protocol OWASP Agentic AI Glama Quality Score Install in VS Code Install in Cursor
Give your AI access to every tool it needs -- without burning your context window or building MCP servers.

MCP Gateway sits between your AI client and your tools. Instead of loading hundreds of tool definitions into every request, the AI gets a compact Meta-MCP surface -- 14 tools minimum, 16 in the README benchmark scenario, 17 when webhook status is surfaced -- and discovers the right backend tool on demand.
Public quantitative claims in this README are sourced from docs/BENCHMARKS.md and the machine-readable benchmarks/public_claims.json, with CI checks to catch drift.
MCP Gateway is a tool and capability gateway. It routes MCP tool/resource/prompt traffic to backend MCP servers and capability-backed REST APIs, and it can proxy MCP server-to-client requests like sampling/createMessage, elicitation/create, and roots/list back to the connected client over the existing gateway session.
MCP Gateway is not a general OpenAI/Anthropic chat completions or embeddings gateway. When a backend asks for sampling/createMessage, the connected client still performs the model call. The OpenAI-compatible prompt-cache helpers in the gateway exist only so gateway_invoke can preserve prompt_cache_key behavior for backends or capabilities that happen to call LLM APIs internally.
The context window is the bottleneck. Every MCP tool you connect costs ~150 tokens of context overhead. Connect 20 servers with 100+ tools and you've burned 15,000 tokens before the conversation starts -- on tool definitions the AI probably won't use this turn.
Worse: context limits force you to choose which tools to connect. You leave tools out because they don't fit -- and your AI makes worse decisions because it can't reach the right data.
MCP Gateway removes that tradeoff entirely.
| Without Gateway | With Gateway | |
|---|---|---|
| Tools in context | Every definition, every request | 16 Meta-MCP tools in the README benchmark (~1600 tokens) |
| Token overhead | ~15,000 tokens (100 tools) | ~1600 tokens -- 89% savings |
| Cost at scale | ~$0.22/request (Opus input) | ~$0.024/request -- $201 saved per 1K |
| Practical tool limit | 20-50 tools (context pressure) | Unlimited -- discovered on demand |
| Connect a new REST API | Build an MCP server (days) | Drop a YAML file or import an OpenAPI spec (minutes) |
| Changing MCP config | Restart AI session, lose context | Restart gateway (~8ms), session stays alive |
| When one tool breaks | Cascading failures | Circuit breakers isolate it |
The base discovery quartet (gateway_list_servers, gateway_list_tools, gateway_search_tools, gateway_invoke) stays constant. The README benchmark scenario also surfaces stats, cost report, playbooks, profile controls, disabled-capability visibility, and reload for a 15-tool surface. Surfacing webhook status adds the 16th tool.
| Alternative | What it does | Why MCP Gateway is different |
|---|---|---|
| Direct MCP connections | Each server connected individually | Every tool definition loaded every request. 100 tools = 15K tokens burned. Gateway: a small fixed 13-16 tool surface instead of every backend tool. |
| Claude's ToolSearch | Built-in deferred tool loading | Only works with tools already configured. Gateway adds unlimited backends + REST APIs without MCP servers. |
| Archestra | Cloud-hosted MCP registry | Requires cloud account, sends data to third party. Gateway is local-only, zero external dependencies. |
| Kong / Portkey | General API gateways | Not MCP-aware. No meta-tool discovery, no tool search, no capability YAML system. |
| Building fewer MCP servers | Reduce tool count manually | You lose capabilities. Gateway lets you keep everything and pay the token cost of the compact Meta-MCP surface. |
Connecting N MCP servers to an agent means accepting N attack surfaces. Tool poisoning, rug pulls, and exfiltration via hidden instructions in tool descriptions are demonstrated attacks, not hypotheticals. Invariant Labs' writeup (MCP Security Notification: Tool Poisoning Attacks) and Simon Willison's summary (MCP has prompt injection security problems) lay out the threat model.
mcp-gateway puts every backend tool description behind one audit surface and defends it structurally:
<IMPORTANT> blocks, ~/.ssh/~/.aws/id_rsa/.env//etc/passwd, sidenote exfiltration language, curl .* https?://, base64 in exfil context. MEDIUM patterns warn: 40+ consecutive spaces, zero-width / bidi-override Unicode, oversized descriptions. Implementation: src/validator/rules/tool_poisoning.rs (19 tests).mcp-gateway cap pin <file> writes a sha256: line over the file's canonical hash (grep -v '^sha256:' capability.yaml | sha256sum is reproducible from any shell). The loader refuses any mismatched file on load and on every watcher event.RUG-PULL DETECTED. The capability stays quarantined until an operator re-pins. Implementation: src/capability/hash.rs and detect_rug_pulls in src/capability/backend.rs.Full walkthrough, PoC snippets, and roadmap: docs/blog/security-aware-mcp-gateway.md.
mcp-gateway cap import <spec-url-or-file> turns an OpenAPI 3 spec into one validated capability YAML per operation. The full Swagger Petstore spec becomes 19 validated capability YAMLs end-to-end:mcp-gateway cap import https://petstore3.swagger.io/api/v3/openapi.json --output capabilities/ --prefix petstore
22 tests across src/capability/openapi.rs and tests/openapi_import_tests.rs.Tell your AI assistant (recommended):
Read https://github.com/MikkoParkkola/mcp-gateway and install mcp-gateway to consolidate all my MCP servers behind one gateway
Your agent will install the binary, run the setup wizard, import your existing MCP servers, and wire itself up. Works in Claude Code, Cursor, Windsurf, Codex, and any AI with terminal access.
Or four commands:
brew install MikkoParkkola/tap/mcp-gateway # 1. install
mcp-gateway setup wizard --configure-client # 2. import existing servers + wire up clients
mcp-gateway serve # 3. run
mcp-gateway doctor # 4. verify everything is healthy
That's it. Your AI clients now talk to the gateway and the gateway routes to every backend you already had configured — at a flat ~15 tools instead of ~150. Start with gateway_search_tools from your AI client to find any backend tool, then invoke it with gateway_invoke.
Nothing to import yet?
mcp-gateway init --with-exampleswrites a workinggateway.yamlwith public capabilities so you can confirm the gateway is alive before adding your own servers.
| Method | Command |
|---|---|
| Homebrew (macOS/Linux, recommended) | brew install MikkoParkkola/tap/mcp-gateway |
| Cargo | cargo install mcp-gateway |
| cargo-binstall | cargo binstall mcp-gateway |
| Docker | docker run -v $(pwd)/gateway.yaml:/config.yaml ghcr.io/mikkoparkkola/mcp-gateway:latest --config /config.yaml |
# macOS Apple Silicon
curl -L https://github.com/MikkoParkkola/mcp-gateway/releases/latest/download/mcp-gateway-darwin-arm64 -o mcp-gateway && chmod +x mcp-gateway
# macOS Intel
curl -L https://github.com/MikkoParkkola/mcp-gateway/releases/latest/download/mcp-gateway-darwin-x86_64 -o mcp-gateway && chmod +x mcp-gateway
# Linux x86_64
curl -L https://github.com/MikkoParkkola/mcp-gateway/releases/latest/download/mcp-gateway-linux-x86_64 -o mcp-gateway && chmod +x mcp-gateway
mcp-gateway setup wizard --configure-client
Scans Claude Desktop, Claude Code, Cursor, Zed, Continue.dev, Codex, and running MCP processes; lets you pick which servers to import into gateway.yaml; and writes the gateway entry back into each detected client config so they route through the gateway instead. Add --yes to skip the prompts and import everything.
48 popular MCP servers are pre-registered with the right command, args, and env-var template. mcp-gateway add is claude mcp add / codex mcp add compatible:
mcp-gateway add tavily # known server, fills env vars
mcp-gateway add my-server -- npx -y @some/mcp-server --flag # arbitrary stdio command
mcp-gateway add --url https://mcp.sentry.dev/mcp sentry # HTTP server
mcp-gateway add -e API_KEY=xxx my-server -- npx my-mcp-server
mcp-gateway list shows what's configured. mcp-gateway remove <name> removes one.
gateway.yamlFor the full schema reference, see docs/QUICKSTART.md#configuration. Minimal example:
server:
port: 39400
meta_mcp:
enabled: true
backends:
tavily:
command: "npx -y @anthropic/mcp-server-tavily"
description: "Web search"
env:
TAVILY_API_KEY: "${TAVILY_API_KEY}"
sentry:
http_url: "https://mcp.sentry.dev/mcp"
description: "Sentry issues"
mcp-gateway serve # start the gateway
mcp-gateway doctor # diagnose config, port, env vars, backend health
mcp-gateway doctor --fix # auto-fix issues where possible
The web dashboard is at http://localhost:39400/ui once serve is running.
setup export writes the gateway entry into client config files for you. It auto-detects the right path per client:
mcp-gateway setup export --target all # all detected clients
mcp-gateway setup export --target claude-code # one client
mcp-gateway setup export --target all --dry-run # preview without writing
mcp-gateway setup export --target all --watch # regenerate on gateway.yaml changes
| Client | Config path |
|---|---|
claude-code |
~/.claude.json |
claude-desktop |
platform-specific |
cursor |
.cursor/mcp.json (workspace) |
vs-code-copilot |
.vscode/mcp.json (workspace) |
windsurf |
~/.codeium/windsurf/mcp_config.json |
cline |
.cline/mcp_servers.json (workspace) |
zed |
~/.config/zed/settings.json |
Modes: --mode proxy (HTTP), --mode stdio (subprocess), --mode auto (probe health endpoint, fall back).
{
"mcpServers": {
"gateway": {
"type": "http",
"url": "http://localhost:39400/mcp"
}
}
}
The gateway exposes 14 Meta-MCP tools minimum, 16 in the README benchmark scenario, and 17 when webhook status is surfaced. The base discovery quartet stays fixed; the rest are operator helpers for stats, cost, playbooks, profile control, disabled-capability visibility, reload, and webhook status.
Token math (Claude Opus @ $15/M input tokens, reproducible via python benchmarks/token_savings.py --scenario readme):
Turn any REST API into a tool by dropping a YAML file (~30 seconds) or importing an OpenAPI spec:
mcp-gateway cap import stripe-openapi.yaml --output capabilities/ --prefix stripe
The gateway ships with 110+ built-in capabilities -- weather, Wikipedia, GitHub, stock quotes, package tracking, and more. Capability YAMLs hot-reload automatically after file changes, no restart needed.
mcp-gateway now ships HeyGen video-generation capabilities in capabilities/media/:
video_agent_createvideo_createvideo_getvideo_downloadvoice_listavatar_listSetup:
export HEYGEN_API_KEY=your-api-key
Make sure your config loads the built-in capability directory:
capabilities:
enabled: true
directories:
- ./capabilities
The request schemas ship hand-written for the initial connector, but HeyGen's CLI can act as the schema source of truth for future regeneration:
heygen video-agent create --request-schema
heygen video create --request-schema
Map that JSON into each capability's schema.input block when refreshing the connector.
Example end-to-end workflow:
# 1. Create the video with the Video Agent
CREATE=$(curl -s http://127.0.0.1:39401/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/call",
"params":{
"name":"gateway_invoke",
"arguments":{
"backend":"capabilities",
"tool":"video_agent_create",
"args":{"prompt":"A presenter explaining our product launch in 30 seconds"}
}
}
}')
VIDEO_ID=$(printf '%s' "$CREATE" | jq -r '.result.content[0].text | fromjson | (.data.video_id // .video_id)')
# 2. Poll until completed and fetch the downloadable URL
VIDEO_URL=$(while true; do
BODY=$(curl -s http://127.0.0.1:39401/mcp \
-H 'Content-Type: application/json' \
-d "{
\"jsonrpc\":\"2.0\",
\"id\":1,
\"method\":\"tools/call\",
\"params\":{
\"name\":\"gateway_invoke\",
\"arguments\":{
\"backend\":\"capabilities\",
\"tool\":\"video_get\",
\"args\":{\"video_id\":\"$VIDEO_ID\"}
}
}
}")
STATUS=$(printf '%s' "$BODY" | jq -r '.result.content[0].text | fromjson | (.data.status // .status)')
if [ "$STATUS" = "completed" ]; then
printf '%s' "$BODY" | jq -r '.result.content[0].text | fromjson | (.data.video_url // .video_url)'
break
fi
sleep 5
done)
# 3. Download and save a local MP4
curl -s http://127.0.0.1:39401/mcp \
-H 'Content-Type: application/json' \
-d "{
\"jsonrpc\":\"2.0\",
\"id\":1,
\"method\":\"tools/call\",
\"params\":{
\"name\":\"gateway_invoke\",
\"arguments\":{
\"backend\":\"capabilities\",
\"tool\":\"video_download\",
\"args\":{\"video_url\":\"$VIDEO_URL\"}
}
}
}" \
| jq -r '.result.content[0].text | fromjson | .data' \
| base64 --decode > heygen-explainer.mp4
Your AI connects once to localhost:39400. Behind it, capability YAMLs plus reloadable gateway config sections (including backend add/remove/update and routing/profile changes) can reload live via file watching, gateway_reload_config, or POST /ui/api/reload. Listener address changes report restart_required; env_files list changes stay startup-only and take effect after restart. Your AI session stays connected.
Circuit breakers, retry with backoff, rate limiting, health checks, graceful shutdown, and concurrency limits. One flaky server won't take down your toolchain.
┌───────────────────────────────────────────────────────────────┐
│ MCP Gateway (:39400) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Meta-MCP: 13-16 Tools + Surfaced Tools │ │
│ │ • gateway_list_servers • gateway_search_tools │ │
│ │ • gateway_list_tools • gateway_invoke │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Failsafes: Circuit Breaker │ Retry │ Rate Limit │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Tavily │ │ Context7 │ │ Pieces │ │
│ │ (stdio) │ │ (http) │ │ (sse) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────────────┘
Embedded web UI at /ui -- live status, searchable tools, server health, config viewer. Operator dashboard at /dashboard. Cost tracking at /ui#costs. All served from the same binary and port, no frontend build step.
| Feature | Description | Docs |
|---|---|---|
| Authentication | Bearer tokens, API keys, explicit admin keys, per-client rate limits | examples/per-client-tool-scopes.yaml |
| Per-Client Tool Scopes | Allowlist/denylist tools per API key with glob patterns | examples/per-client-tool-scopes.yaml |
| Security Firewall | Credential redaction, prompt injection detection, shell/SQL/path traversal scanning | CHANGELOG |
| Cost Governance | Per-tool, per-key, daily budgets with alert thresholds (log/notify/block) | CHANGELOG |
| Session Sandboxing | Per-session call limits, duration caps, backend restrictions | CHANGELOG |
| mTLS | Certificate-based auth for tool execution | CHANGELOG |
| Feature | Description |
|---|---|
| Capability System | REST API to MCP tool via YAML. Hot-reloaded. 110+ built-in. OpenAPI import supported. |
| Transform Chains | Namespace, filter, rename, and response transforms. Example. |
| Webhooks | GitHub/Linear/Stripe push events as MCP notifications. Docs. |
| Auto-Discovery | Discover MCP servers from existing client configs and running processes. |
| Surfaced Tools | Pin high-value tools directly in tools/list for one-hop invocation. |
| Semantic Search | TF-IDF ranked search across all tool names and descriptions. |
| Tool Profiles | Usage analytics per tool: latency, errors, trends. Persisted to disk. |
| Config Export | Export sanitized config as YAML/JSON. mcp-gateway config export |
gateway_reload_config and /ui/api/reload return restart_required for listener changes (for example server.host / server.port); env_files list edits remain startup-onlygateway.yaml in cwd, ~/.config/mcp-gateway/, /etc/mcp-gateway/readOnlyHint, destructiveHint, openWorldHintmcp-gateway completions bash|zsh|fishtools/list (SEP-1821), tools/resolve (SEP-1862), dynamic promotionAny MCP-compliant server works. All three transport types supported:
| Transport | Examples |
|---|---|
| stdio | @anthropic/mcp-server-tavily, @modelcontextprotocol/server-filesystem, @modelcontextprotocol/server-github |
| HTTP | Any Streamable HTTP server |
| SSE | Pieces, LangChain, GitMCP (free remote docs+code search for any GitHub repo) |
Remote MCP servers plug in by URL — no extra code. See examples/gateway-full.yaml for a commented GitMCP backend entry and docs/REMOTE_BACKENDS.md for a step-by-step walkthrough.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check with backend status |
/mcp |
POST | Meta-MCP mode (dynamic discovery) |
/mcp/{backend} |
POST | Direct backend access |
/ui |
GET | Web dashboard |
/dashboard |
GET | Operator dashboard |
/metrics |
GET | Prometheus metrics (with --features metrics) |
| Metric | Value | Notes |
|---|---|---|
| Startup time | ~8ms | Measured with hyperfine (benchmarks) |
| Binary size | ~12-13 MB | Release build with LTO, stripped |
| Hot-path microbenchmarks | Included | Criterion suite covers registry, parsing, cache-key, firewall, and semantic search hot paths |
| End-to-end latency | Backend-dependent | Measure with your real MCP servers and REST APIs rather than relying on a synthetic single number |
MCP Gateway can ingest Agent Skills / Claude Code
SKILL.md files and expose them as discoverable skills alongside capability
YAML. This lets the gateway consume any SKILL.md — whether authored locally,
shipped from agentskills.io, or pulled from a GitHub release — and surface
it through the same meta-tool surface used for capabilities.
# Import a local skill directory (auto-discovers SKILL.md + resources/)
mcp-gateway skills import ~/.claude/skills/gws-gmail-send
# Import a single SKILL.md file
mcp-gateway skills import ./path/to/SKILL.md
# Import from an agentskills.io URL
mcp-gateway skills import https://agentskills.io/skills/my-skill/SKILL.md
# List imported skills
mcp-gateway skills list
# Search by name, description, trigger, or keyword
mcp-gateway skills search "gmail"
# Show the full body (including any embedded code blocks)
mcp-gateway skills show gws-gmail-send
# Remove a skill
mcp-gateway skills remove gws-gmail-send
What gets parsed
name, description, version, effort,
allowed-tools, triggers, keywords)bash/python/json code blocks extracted as
structured SkillCodeBlock entriesSKILL.advanced.md, reference.md,
README.md, and any resources/*.md files in the skill directorySecurity model (read-only)
Imported skills are stored as data, not executed. Embedded bash or
python blocks are parsed and surfaced to users/agents via skills show,
but MCP Gateway will never run them automatically. A future release may
add opt-in execution gated on per-skill user consent. If you need to run
a skill's commands today, copy them from skills show and run them in
your own shell.
Registry location: ~/.mcp-gateway/skills.json (override with
MCP_GATEWAY_SKILLS_REGISTRY or --registry).
Reference: Anthropic SKILL.md spec · agentskills.io
| Document | Contents |
|---|---|
| Quick Start | Zero to running in 2 minutes |
| Configuration Reference | All config options |
| OAuth Configuration | OAuth 2.0 setup with Slack and Figma examples |
| Deployment Guide | Docker, systemd, TLS/mTLS, scaling |
| OpenAPI Import | Generate capabilities from OpenAPI specs |
| Webhooks | Event integration setup |
| Community Registry | Share and install capabilities |
| Benchmarks | Performance measurements |
| Changelog | Release history |
| OWASP Agentic AI Compliance | Risk coverage matrix |
Backend won't connect? Test the command directly (npx -y @anthropic/mcp-server-tavily), then check gateway logs with --log-level debug.
Circuit breaker open? Check curl localhost:39400/health | jq '.backends'. Adjust thresholds in failsafe.circuit_breaker.
Tools not appearing? Verify the backend is running (gateway_list_servers). Tool lists are cached for 5 minutes.
git checkout -b feature/your-feature)cargo test) and lint (cargo fmt && cargo clippy -- -D warnings)main with a clear description and CHANGELOG entrySee CONTRIBUTING.md for full details. Look for good first issue or help wanted to get started.
mcp-gateway is part of a suite of MCP tools:
| Tool | Description |
|---|---|
| mcp-gateway | Universal MCP gateway — compact 13-16 tool surface replaces 100+ registrations |
| trvl | AI travel agent — 36 MCP tools for flights, hotels, ground transport |
| nab | Web content extraction — fetch any URL with cookies + anti-bot bypass |
| axterminator | macOS GUI automation — 34 MCP tools via Accessibility API |
mcp-gateway is dual-licensed as of v2.11.0:
| Scope | License | File |
|---|---|---|
| Core gateway, capabilities, transport, CLI, and everything not listed below | MIT | LICENSE |
| Designated Enterprise Edition modules (see below) | PolyForm Noncommercial 1.0.0 | LICENSE-EE.md |
EE-designated paths (every file carries // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0):
src/security/firewall/ — egress filteringsrc/security/agent_identity.rs — identity-based access control (OWASP ASI03)src/security/data_flow.rs — data flow tracking (EU AI Act Art. 12)src/security/message_signing.rs — HMAC inter-agent signing (OWASP ASI07)src/security/policy.rs — advanced policy enforcementsrc/security/response_inspect.rs, response_scanner.rs — outbound credential / exfil detectionsrc/security/scope_collision.rs — scope conflict detectionsrc/security/tool_integrity.rs — tool poisoning detection (OWASP ASI04)src/cost_accounting/ — cost governancesrc/key_server/ — OIDC-backed scoped key issuanceWhat this means in practice:
[email protected].Created by Mikko Parkkola. Implements Model Context Protocol version 2025-11-25.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"mikkoparkkola-mcp-gateway": {
"command": "npx",
"args": []
}
}
}