mcp-gw
Integrates with Home Assistant's MCP server to provide tools for controlling Home Assistant entities such as turning devices on/off, setting volumes, and more.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-gwlist all registered backends"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-gw
An aggregating MCP (Model Context Protocol) gateway that runs as a Docker container. Claude Code connects to one endpoint and gets tools from all registered backend MCP servers combined.
Architecture
Claude Code
│ HTTP MCP (localhost:3000/mcp)
▼
┌─────────────────────────────┐
│ mcp-gateway │ ← Alpine Docker container
│ ┌─────────┐ ┌──────────┐ │
│ │ MCP srv │ │Dashboard │ │
│ └────┬────┘ └──────────┘ │
│ │ mcp-gw-net │
└───────┼─────────────────────┘
│
├── backend-a:8080 ← Docker container on mcp-gw-net
├── backend-b:8080 ← Docker container on mcp-gw-net
└── 10.10.7.22:8123 ← External host (e.g. Home Assistant)Tools from all backends are aggregated and namespaced as backend__tool_name so Claude Code sees them in a single tool list.
Related MCP server: Multi MCP
Quick Start
git clone https://github.com/gpimthong/mcp-gw
cd mcp-gw
docker compose up -dThe gateway starts on port 3000.
Dashboard: http://localhost:3000
MCP endpoint: http://localhost:3000/mcp
Health: http://localhost:3000/api/health
Connect Claude Code
Add to ~/.mcp.json:
{
"mcpServers": {
"gateway": {
"type": "http",
"url": "http://localhost:3000/mcp"
}
}
}Restart Claude Code to pick up the change.
Homelab Deployment
First-time setup on a new machine
config/backends.json is gitignored (to prevent credentials from leaking). You must create it manually on every fresh clone:
mkdir -p config
cat > config/backends.json << 'EOF'
{
"backends": []
}
EOFThen start the gateway and register your backends via the dashboard or API.
Persistent config across restarts
The config/ directory is bind-mounted into the container (see docker-compose.yml). Any backends you register via the dashboard or API are written to config/backends.json on the host and survive container restarts automatically.
Network topology
The gateway runs on a dedicated bridge network mcp-gw-net (172.22.0.0/16). Backend containers must be on this network. External hosts (like Home Assistant on your LAN) are reachable directly by IP — no network joining needed for those.
Adding Backend MCP Servers
Docker container backends
The container must be on the mcp-gw-net network:
# Attach an existing container
docker network connect mcp-gw-net <container-name>
# Or start a new backend directly on the network
docker run -d --name my-mcp --network mcp-gw-net my-mcp-imageThen register it:
curl -X POST http://localhost:3000/api/backends \
-H 'Content-Type: application/json' \
-d '{"name":"my-mcp","url":"http://my-mcp:8080/mcp","transport":"http","enabled":true}'External host backends
Backends that run outside Docker (on a LAN IP, VM, or another machine) are registered by IP. No network setup needed — the gateway container reaches them over the host network.
curl -X POST http://localhost:3000/api/backends \
-H 'Content-Type: application/json' \
-d '{"name":"my-service","url":"http://192.168.1.50:8080/mcp","transport":"http","enabled":true}'Authenticated backends (Bearer token / custom headers)
Pass a headers object to send arbitrary HTTP headers on every request to a backend. This is how you authenticate against services like Home Assistant:
curl -X POST http://localhost:3000/api/backends \
-H 'Content-Type: application/json' \
-d '{
"name": "my-service",
"url": "http://192.168.1.50:8080/mcp",
"transport": "sse",
"enabled": true,
"headers": {
"Authorization": "Bearer <your-token-here>"
}
}'The headers field is optional. Without it, requests are sent unauthenticated.
Home Assistant Setup
Home Assistant's built-in MCP server is exposed at /mcp_server/sse and uses SSE transport. It requires a long-lived access token.
Get a long-lived access token
Open Home Assistant → Profile (bottom-left avatar)
Scroll to Long-Lived Access Tokens → Create Token
Give it a name (e.g.
mcp-gateway) and copy the token
Register Home Assistant as a backend
curl -X POST http://localhost:3000/api/backends \
-H 'Content-Type: application/json' \
-d '{
"name": "homeassistant",
"url": "http://<HA_IP>:8123/mcp_server/sse",
"transport": "sse",
"enabled": true,
"headers": {
"Authorization": "Bearer <your-long-lived-token>"
}
}'Replace <HA_IP> with your Home Assistant host IP (e.g. 10.10.7.22) and <your-long-lived-token> with the token from the previous step.
Resulting tools in Claude Code
Once connected, Home Assistant tools appear namespaced as homeassistant__<tool>, for example:
homeassistant__HassTurnOnhomeassistant__HassTurnOffhomeassistant__HassSetVolume
Dashboard
The dashboard at http://localhost:3000 shows:
Backend cards — connection status, tool count, latency, last ping
Live request log — real-time stream of every tool call with duration and status
Tool catalog — all tools from all backends, expandable by backend
Use the + Add Backend button to register new backends, or click Remove / Reconnect on each card.
REST API
Method | Path | Description |
|
| Status, version, uptime, tool count |
|
| List all backends with state |
|
| Add / reconnect a backend |
|
| Remove a backend |
|
| Force reconnect |
|
| Last 200 log entries |
|
| SSE live log stream |
Tool Namespacing
Backend memory with tool search_notes → exposed to Claude Code as memory__search_notes.
The double-underscore separator avoids collisions between backends. The gateway parses the prefix at call time to route to the right backend client.
Transport Support
Backend transport | Config value |
MCP Streamable HTTP |
|
MCP SSE (legacy) |
|
Home Assistant uses SSE. Most modern MCP servers use Streamable HTTP.
config/backends.json
This file is gitignored because it typically contains auth tokens. It is created and maintained at runtime by the gateway — every dashboard or API action writes through to this file.
Template for a fresh deployment:
{
"backends": []
}Start from the empty template and re-register your backends after cloning. The config/ directory is bind-mounted so the file persists across docker compose down / up cycles.
Development
Requires Node.js 22+.
npm install
npm run dev # tsx hot-reload
npm run build # compile TypeScript → dist/Config is read from ./config/backends.json in dev mode (set CONFIG_PATH env var to override).
Versioning
Version is set in package.json. The gateway advertises it in the MCP initialize handshake and at /api/health. Git tags follow v<semver> (e.g. v0.1.0).
Project Structure
src/
index.ts — entry point
version.ts — reads version from package.json
types.ts — shared interfaces
logger.ts — circular log buffer + SSE emitter
config.ts — load/save backends.json
backend-registry.ts — MCP client connections + heartbeat
tool-aggregator.ts — namespace + route tool calls
mcp-server.ts — MCP HTTP server (session management)
dashboard.ts — Express app (REST API + SSE)
public/
index.html — dashboard SPA (no build step)
config/
backends.json — persisted backend definitions (gitignored)This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/gpimthong/mcp-gw'
If you have feedback or need assistance with the MCP directory API, please join our Discord server