|
| 1 | +# mcp-gateway |
| 2 | + |
| 3 | +> Local MCP gateway that fans out to N downstream MCP servers, namespaces their tools, and lazy-loads their schemas — so your coding agent's context isn't eaten by MCP boilerplate. |
| 4 | +
|
| 5 | +[](https://www.npmjs.com/package/@swarmclawai/mcp-gateway) |
| 6 | +[](./LICENSE) |
| 7 | +[](https://github.com/swarmclawai/mcp-gateway/actions/workflows/ci.yml) |
| 8 | + |
| 9 | +## Why this exists |
| 10 | + |
| 11 | +Install more than a handful of MCP servers and something ugly happens: every one of them dumps its full tool schema into your coding agent's context at startup. People routinely report **30,000 – 60,000 tokens** of MCP boilerplate consumed before they've typed a single message. The 1M-context upgrade makes this worse, not better — people just install more servers. |
| 12 | + |
| 13 | +Existing tooling solves the wrong half: |
| 14 | + |
| 15 | +- Registries (wong2/awesome-mcp-servers, mcp.so, smithery, glama) solve **discovery**. |
| 16 | +- Docker's own gateway is great at **multi-tenancy** and **auth**. |
| 17 | +- Nobody owns the **local runtime** problem: "I have 15 MCP servers installed. I want 3 of them exposed by default and the other 12 to only show up when I actually ask for them." |
| 18 | + |
| 19 | +`mcp-gateway` is that tool. You point your upstream client (Claude Code, Cursor, Cline, Aider, Windsurf, etc.) at one MCP endpoint — the gateway. It fans out to all your downstream servers, prefixes their tool names to prevent collisions, and only exposes the tools you've explicitly chosen to pre-load. |
| 20 | + |
| 21 | +## 30-second demo |
| 22 | + |
| 23 | +```bash |
| 24 | +# Generate a starter config |
| 25 | +npx @swarmclawai/mcp-gateway@latest init --write |
| 26 | + |
| 27 | +# Edit mcp-gateway.config.json — set alwaysExpose per server |
| 28 | + |
| 29 | +# See how many tokens each server is spending |
| 30 | +npx @swarmclawai/mcp-gateway token-report |
| 31 | + |
| 32 | +# Point Claude Code at the gateway instead of at each server individually |
| 33 | +claude mcp add gateway -- npx -y @swarmclawai/mcp-gateway@latest start |
| 34 | +``` |
| 35 | + |
| 36 | +## Config |
| 37 | + |
| 38 | +A single `mcp-gateway.config.json` at your project root (or `--config <path>`): |
| 39 | + |
| 40 | +```json |
| 41 | +{ |
| 42 | + "version": 1, |
| 43 | + "namespaceSeparator": "__", |
| 44 | + "servers": [ |
| 45 | + { |
| 46 | + "name": "fs", |
| 47 | + "command": "npx", |
| 48 | + "args": ["-y", "@modelcontextprotocol/server-filesystem", "."], |
| 49 | + "alwaysExpose": true |
| 50 | + }, |
| 51 | + { |
| 52 | + "name": "github", |
| 53 | + "command": "docker", |
| 54 | + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], |
| 55 | + "alwaysExpose": false |
| 56 | + }, |
| 57 | + { |
| 58 | + "name": "sentry", |
| 59 | + "command": "npx", |
| 60 | + "args": ["-y", "@sentry/mcp-server@latest"], |
| 61 | + "alwaysExpose": ["issue_details"] |
| 62 | + } |
| 63 | + ] |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +- `alwaysExpose: true` — every tool from this server is in your agent's context on startup. |
| 68 | +- `alwaysExpose: false` — tools aren't exposed at first; the gateway connects to the server when the agent calls a tool whose name begins with `<prefix>__`. |
| 69 | +- `alwaysExpose: ["tool_a", "tool_b"]` — only the listed tools are pre-exposed. |
| 70 | + |
| 71 | +The gateway prefixes every downstream tool with its server name and the namespace separator (`__` by default) so two servers can both expose a tool called `read_file` without collision — your agent sees `fs__read_file` and `github__read_file`. |
| 72 | + |
| 73 | +## Install |
| 74 | + |
| 75 | +```bash |
| 76 | +pnpm add -g @swarmclawai/mcp-gateway |
| 77 | +# or |
| 78 | +npm i -g @swarmclawai/mcp-gateway |
| 79 | +# or run on demand |
| 80 | +npx @swarmclawai/mcp-gateway@latest --help |
| 81 | +``` |
| 82 | + |
| 83 | +## Commands |
| 84 | + |
| 85 | +| Command | Purpose | |
| 86 | +|---|---| |
| 87 | +| `init` | Create a starter config | |
| 88 | +| `validate` | Validate the config file without connecting to any downstream | |
| 89 | +| `status` | Connect to every enabled downstream and report status + tool counts | |
| 90 | +| `token-report` | Estimate how many tokens each downstream's schemas cost | |
| 91 | +| `add-server <name> <command> [args...]` | Append a server to the config | |
| 92 | +| `start` | Start the gateway (stdio MCP server for an upstream client) | |
| 93 | +| `help-agents` | Print the machine-readable command catalog | |
| 94 | + |
| 95 | +Every command accepts `--json` and returns a one-line JSON envelope. Exit codes: `0` success, `1` user error, `2` internal error. |
| 96 | + |
| 97 | +## How token-report works |
| 98 | + |
| 99 | +The report walks every downstream server, connects to it over stdio, calls `tools/list`, and estimates the token cost of each tool's name + description + input schema. We don't call a real tokenizer — that'd introduce a heavy dep for a directional number. Chars / 3.5 is close enough to tell you which server is blowing up your window. |
| 100 | + |
| 101 | +## Wiring it into your agent |
| 102 | + |
| 103 | +### Claude Code |
| 104 | + |
| 105 | +```bash |
| 106 | +claude mcp add gateway -- npx -y @swarmclawai/mcp-gateway@latest start |
| 107 | +``` |
| 108 | + |
| 109 | +Remove your individual server entries — the gateway replaces them. |
| 110 | + |
| 111 | +### Cursor |
| 112 | + |
| 113 | +In `~/.cursor/mcp.json`: |
| 114 | + |
| 115 | +```json |
| 116 | +{ |
| 117 | + "mcpServers": { |
| 118 | + "gateway": { |
| 119 | + "command": "npx", |
| 120 | + "args": ["-y", "@swarmclawai/mcp-gateway@latest", "start"] |
| 121 | + } |
| 122 | + } |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### Cline, Aider, Windsurf |
| 127 | + |
| 128 | +Same pattern: one `mcp-gateway start` entry in place of N individual server entries. See [`awesome-mcp-for-coding-agents`](https://github.com/swarmclawai/awesome-mcp-for-coding-agents#how-to-install) for the exact config syntax per agent. |
| 129 | + |
| 130 | +## Built for coding agents |
| 131 | + |
| 132 | +Every swarmclawai CLI follows the same agent conventions so Claude Code, Cursor, Cline, Aider, Codex et al can drive them without guessing: |
| 133 | + |
| 134 | +- `--json` everywhere, one-line envelope on stdout |
| 135 | +- Stderr for logs, stdout for data |
| 136 | +- Stable exit codes: `0` / `1` / `2` |
| 137 | +- Non-interactive by default |
| 138 | +- `mcp-gateway help-agents` returns the entire command catalog as JSON |
| 139 | + |
| 140 | +See [`AGENTS.md`](./AGENTS.md) for the full machine-readable reference. |
| 141 | + |
| 142 | +## Roadmap |
| 143 | + |
| 144 | +- Session-scoped explicit exposure: an agent can ask the gateway "expose github__* for the rest of this session" without restarting |
| 145 | +- Schema compression: strip optional descriptions on lazy-exposed tools to shrink `tools/list` replies further |
| 146 | +- Observability endpoint: count tool calls per server to justify what should actually be alwaysExpose |
| 147 | +- Remote (HTTP/SSE) transport for upstream clients, not just stdio |
| 148 | +- Per-tool deny/allow list beyond the name prefix |
| 149 | + |
| 150 | +## Contributing |
| 151 | + |
| 152 | +See [`CONTRIBUTING.md`](./CONTRIBUTING.md). |
| 153 | + |
| 154 | +## License |
| 155 | + |
| 156 | +[MIT](./LICENSE) |
0 commit comments