Too much tools in context. Use a gateway
MCP Gateway
MCP Gateway is a server aggregation tool that connects multiple Model Context Protocol (MCP) servers into a single gateway, exposing all tools from connected servers through unified search, describe, and invoke interfaces and it exposes only 5 tools.
The Context Limit Problem
When connecting an client (Claude Code, Opencode, etc.) to multiple MCP servers, each server lists all its tools. With 10+ MCPs each exposing 10-50 tools, you can easily exceed 500+ tool descriptions in the system prompt:
10 servers × 20 tools each = 200+ tool descriptions
Each tool: 200-500 chars → 40KB-100KB of description just for tool schemas!
This creates two problems:
- Context overflow: Many LLMs hit their context limit before any conversation happens
- Cognitive overload: LLMs struggle to choose the right tool from hundreds of options
The Gateway Solution
MCP Gateway solves this by providing tool search instead of dumping all tool schemas:
┌─────────────┐ gateway.search ┌─────────────────┐ kubernetes::pods_list ┌──────────────────┐
│ AI Client │ ───────────────────► │ MCP Gateway │ ─────────────────────────► │ Kubernetes MCP │
│ │ │ │ │ │
│ │ ◄────────────────────│ │ ◄───────────────────────── │ │
└─────────────┘ pods_list schema └─────────────────┘ pods output └──────────────────┘
How It Works
MCP Gateway operates as both an MCP client (connecting to upstream servers) and an MCP server (exposing tools to downstream clients):
┌──────────────┐ MCP ┌─────────────────┐ MCP ┌──────────────────┐
│ AI Client │ ◄──────────── │ MCP Gateway │ ◄──────────── │ Upstream Server │
│ (Claude, etc)│ │ (this gateway) │ │ (playwright, │
└──────────────┘ └─────────────────┘ │ kubernetes...) │
└──────────────────┘
- Gateway starts and reads configuration
- For each configured upstream server, Gateway connects via stdio (local) or HTTP/WebSocket (remote)
- Gateway fetches the tool catalog from each server
- All tools are indexed in a unified catalog with search capabilities
- AI clients connect to Gateway and use
gateway.searchto find relevant tools - Only the tools the client actually needs are invoked
You will notice around ~40% reduction of initial token used.
Installation
Claude Code
Add to your Claude MCP configuration:
{
"mcpServers": {
"gateway": {
"command": "bunx",
"args": ["github:eznix86/mcp-gateway"]
}
}
}
OpenCode
Add to your OpenCode MCP configuration:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"mcp-gateway": {
"type": "local",
"command": ["bunx", "github:eznix86/mcp-gateway"]
},
}
}
You may append your global AGENTS.md (~/.config/opencode/AGENTS.md) with this template.
You may now just simple enumerate the MCP available.
Configuration
MCP Gateway reads configuration from a JSON file. By default, it looks for:
- Path provided as first command-line argument
MCP_GATEWAY_CONFIGenvironment variable~/.config/mcp-gateway/config.json
Configuration Format
{
"local-server": {
"type": "local",
"command": ["bun", "run", "/path/to/server.ts"],
},
"remote-server": {
"type": "remote",
"url": "https://mcp.example.com",
"enabled": true
},
"websocket-server": {
"type": "remote",
"url": "wss://mcp.example.com/ws",
"enabled": true
}
}
Each entry specifies:
type:"local"or"remote"command(local only): Array with command and arguments to spawn the upstream serverurl(remote only): Full URL of the remote MCP servertransport(optional, remote only): Override transport detection ("streamable_http"or"websocket"). Usually auto-detected from URL protocol.enabled: Set to false to skip connecting to this server
Docker
Run MCP Gateway in Docker with HTTP transport:
# Build the image
docker build -t mcp-gateway .
# Run with config mounted
docker run -p 3000:3000 \
-v ./examples/config.json:/home/gateway/.config/mcp-gateway/config.json:ro \
mcp-gateway
Endpoints:
| Endpoint | Description |
|----------|-------------|
| GET / | Gateway info and endpoints |
| GET /health | Health check |
| /mcp | MCP protocol endpoint |
Example:
curl http://localhost:3000/
# {"name":"MCP Gateway",...,"endpoints":{"mcp":"/mcp","health":"/health"}}
curl http://localhost:3000/health
# {"status":"ok"}
Remote Server Configuration
Remote servers are auto-detected based on the URL protocol:
http://orhttps://→ Streamable HTTP (recommended)ws://orwss://→ WebSocket
{
"gh-grep": {
"type": "remote",
"url": "https://mcp.grep.app"
},
"custom-websocket": {
"type": "remote",
"url": "wss://my-server.com/mcp"
}
}
Available Tools
gateway.search
Search for tools across all connected servers.
{
query: "kubernetes pods",
limit: 10, // optional, max 50
filters: {
server: "kubernetes", // optional, filter by server name
}
}
Returns matching tools with relevance scores. Tools matching in name are boosted.
gateway.describe
Get detailed information about a specific tool.
{
id: "kubernetes::pods_list" // format: serverKey::toolName
}
Returns the full tool schema including inputSchema.
gateway.invoke
Execute a tool synchronously and get immediate results.
{
id: "kubernetes::pods_list",
args: { namespace: "default" },
timeoutMs: 30000 // optional, default 30 seconds
}
gateway.invoke_async
Start an asynchronous tool execution. Returns a job ID for polling.
{
id: "some-server::long-running-tool",
args: { ... },
priority: 10, // optional, higher values run first
timeoutMs: 60000
}
gateway.invoke_status
Check the status of an async job.
{
jobId: "job_123456789_abc123"
}
Tool ID Format
All gateway tools use the format serverKey::toolName to identify tools:
kubernetes::pods_list
playwright::browser_navigate
github::create_issue
The serverKey is the key name in your configuration file.
Architecture
Components
- MCPGateway class: Main orchestrator
- Upstream connection manager: Manages connections to MCP servers (stdio for local, HTTP/WebSocket for remote)
- Tool catalog: In-memory index of all available tools with metadata
- Job queue: Handles async tool invocations with priority ordering and concurrency limits (max 3 concurrent by default)
- Search engine: MiniSearch with BM25 scoring and fuzzy matching
Search Algorithm
The search uses MiniSearch with BM25 ranking:
- BM25 scoring: Relevance algorithm
- Field boosting: Name matches (3x), title matches (2x), description/server matches (1x)
- Fuzzy matching: Handles typos with 0.2 threshold (e.g., "kubenetes" → finds "kubernetes")
- Prefix search: Partial word matching (e.g., "pod" matches "pods_list")
Contributing
git clone https://github.com/eznix86/mcp-gateway.git
cd mcp-gateway
bun install
# Run locally (stdio transport)
bun run index.ts
# Run with Docker (HTTP transport on port 3000)
bun run docker:build && bun run docker:run
License
MIT License. See the LICENSE.