English | 简体中文
This project provides a lightweight Model Context Protocol (MCP) gateway for token-efficient, on-demand discovery and one unified entry point for multiple downstream services.
Instead of exposing every downstream MCP tool up front, the gateway keeps a small fixed tool surface and lets the client discover services, list tools for a specific service, fetch one tool schema when needed, and then forward the actual tool call.
This gateway is designed for a practical problem that appears quickly once you use multiple MCP services across multiple agents.
If every agent connects directly to every MCP service, two problems show up:
- The tool surface becomes too large.
- The MCP configuration becomes too repetitive.
Many MCP services expose dozens or even hundreds of tools.
If an agent connects directly to several MCP services, the client often needs to expose or describe a very large tool inventory up front. That increases:
- prompt size
- tool discovery cost
- repeated schema/context overhead across sessions
This gateway avoids that by exposing a small fixed discovery interface instead of flattening every downstream tool into the initial tool list.
The normal flow becomes:
- list available services
- inspect tools for one selected service
- fetch schema for one selected tool
- call that tool
That means the model only sees the minimum amount of MCP metadata needed for the current task.
Without a gateway, each agent usually needs its own MCP client configuration for multiple downstream services.
That quickly becomes hard to maintain:
- every agent config needs to be updated when services change
- command paths and environment variables are repeated
- secrets and local machine details are spread across multiple client configs
- different agents may drift out of sync over time
With this gateway, the downstream MCP pool is defined once in one config file, and every agent only needs to connect to the gateway itself.
That gives you a cleaner architecture:
- one MCP entry point for many services
- one place to add, remove, or update downstream MCP definitions
- one place to control what is exposed to agents
- less duplicated local configuration
- easier reuse across Codex, Claude Code, Gemini CLI, or other MCP-capable clients
In short, this gateway is useful when you want to treat multiple MCP services as a managed service pool rather than reconfiguring the same MCP stack separately for every agent.
- Keep the public tool surface small and stable.
- Discover services first, then tools for one service, then schema for one tool.
- Avoid sending hundreds of downstream tools to the model at session start.
- Expose a fixed gateway contract instead of dynamically flattening downstream tools.
- Return compact discovery payloads for service and tool enumeration.
- Forward downstream tool results directly to the caller for minimal wrapping.
- Load a static service pool from JSON.
- Reload config automatically when the file changes.
- Stop removed, disabled, or replaced downstream processes during hot reload.
- Restart failed downstream processes up to 3 times before marking them unavailable.
- Preserve the last valid config snapshot when a reload fails.
npm install -g @jadchene/mcp-gateway-serviceStart the gateway:
mcp-gateway-serviceWith an explicit config path:
mcp-gateway-service --config ./config.jsonCreate a local config.json from config.example.json, then start the gateway:
npm install
npm run devBy default the gateway loads ./config.json.
Use --config <path> to override it for the current process. If --config is omitted, the gateway falls back to MCP_GATEWAY_CONFIG, then ./config.json.
Override it with:
$env:MCP_GATEWAY_CONFIG="config/gateway/config.json"
npm run devmcp-gateway-service --versionShort form:
mcp-gateway-service -vThe gateway currently supports stdio downstream transports only.
A service is loaded only when enable is missing or set to true. If enable is set to false, the gateway skips that service entirely. During hot reload, disabling or removing a service also stops its existing downstream process if one is running.
logging.enableis optional and defaults tofalse.logging.pathis required only whenlogging.enableistrue.- When enabled, the gateway writes newline-delimited JSON logs to the configured file and never writes operational logs to MCP
stdoutorstderr. - Relative
logging.pathvalues are resolved from the config file directory. - Logging config supports hot reload, so changing
logging.enableorlogging.pathin the config file takes effect without restarting the gateway. enableis optional. When omitted, the gateway treats the service as enabled.cwdis optional. When omitted, the gateway uses its current working directory.envis optional.framingis optional. When omitted, the gateway trieslinefirst and thencontent-length.
{
"logging": {
"enable": false,
"path": "./logs/mcp-gateway.log"
},
"services": [
{
"serviceId": "demo-echo",
"enable": true,
"name": "Demo Echo Service",
"description": "Sample echo MCP service.",
"transport": {
"type": "stdio",
"command": "node",
"args": [
"--experimental-strip-types",
"examples/echo-service.ts"
]
}
}
]
}The gateway exposes a fixed set of discovery and routing tools:
gateway.listServicesgateway.getServicegateway.listToolsgateway.getToolSchemagateway.manageServicegateway.callTool
gateway.listServicesreturns onlyserviceId,description, andavailable.gateway.listToolsreturns onlynameanddescription.gateway.getToolSchemareturns onlyinputSchemaandoutputSchema.gateway.manageServicereturns onlyserviceId,action,enabled, andavailable.gateway.callToolforwards the downstream MCP tool result directly without extra gateway metadata wrapping.
- The default token-efficient workflow still uses four tools:
gateway.listServices,gateway.listTools,gateway.getToolSchema, andgateway.callTool. gateway.getServiceis primarily for diagnostics, such as checking recent service errors, connection state, protocol version, or downstream server info.gateway.manageServiceis an operational tool for explicit service control, not part of the normal discovery flow.
Use gateway.manageService when you explicitly need to reconnect a service or persistently change its enabled state.
Input:
serviceId: logical service identifieraction: one ofreconnect,enable, ordisable
Action behavior:
reconnect: immediately tries to start and reinitialize the specified downstream MCP again. Use this when a service previously failed because its dependency was not ready, such as an IDE that was not open yet.enable: writesenable: trueto the config file for that service and triggers a reload.disable: writesenable: falseto the config file for that service and triggers a reload.
Important notes:
enableanddisableare persisted to the JSON config file. They are not session-only toggles.reconnectdoes not modify the config file. It only retries the current service lifecycle.
For the best token efficiency, the MCP client should cache discovery results instead of repeatedly querying the gateway:
- Call
gateway.listServicesonce at session start. - Call
gateway.listTools(serviceId)only when a service is actually needed. - Call
gateway.getToolSchema(serviceId, toolName)only before the first use of that tool. - Call
gateway.callTool(...)for execution. - Use
gateway.getServiceonly when diagnostics are explicitly needed. - Use
gateway.manageServiceonly when a service must be reconnected or explicitly enabled/disabled. - Refresh discovery data only when a call fails, the config changes, or the client explicitly wants a refresh.
This repository includes a public skill for agent frameworks that support skill loading:
- Skill path:
skills/mcp-gateway/SKILL.md
The skill focuses on:
- token-efficient discovery flow
- avoiding unnecessary schema/tool enumeration
- calling downstream tools through the minimal gateway contract
The examples below intentionally use relative config paths so they stay portable.
~/.codex/config.toml
[mcp_servers.gateway]
command = "mcp-gateway-service"
args = ["--config", "./config.json"]~/.gemini/settings.json
{
"mcpServers": {
"gateway": {
"type": "stdio",
"command": "mcp-gateway-service",
"args": [
"--config",
"./config.json"
]
}
}
}~/.claude.json
{
"mcpServers": {
"gateway": {
"type": "stdio",
"command": "mcp-gateway-service",
"args": [
"--config",
"./config.json"
]
}
}
}- Repository-managed
config.jsonandconfig.example.jsonare examples only. - Copy
config.example.jsonto your own localconfig.jsonbefore running the gateway. - Keep real local configs and logs outside the repository.
- File logging is disabled by default so MCP startup stays quiet unless you explicitly enable it.
- Downstream output schema is returned only when the downstream service exposes it.
- Windows command resolution supports PowerShell shims such as
.ps1-backed command aliases. - On Windows, the gateway prefers
pwshfor.ps1shim resolution and execution, and automatically falls back topowershell.exewhenpwshis unavailable.
Released under the MIT License.