README
¶
Host MCP Gateway
Host MCP Gateway is a small Go daemon that runs local MCP servers on the host and exposes them through authenticated HTTP endpoints. It is intended for MCP servers that need host-only capabilities, such as macOS frameworks, while the MCP client runs somewhere else.
Features
- Runs configured MCP server processes over stdio.
- Routes JSON-RPC requests to a target MCP server by
server_id. - Supports wrapper requests through
POST /rpc. - Supports direct raw JSON-RPC requests through
/{server_id}/rpc. - Exposes health and server-status endpoints.
- Enforces bearer-token authentication on every endpoint.
- Restricts clients by explicit IP address or CIDR allowlist.
- Restarts crashed MCP server processes according to per-server policy.
- Emits structured JSON logs and OTLP traces and metrics.
Requirements
- Go 1.22 or newer.
- One or more MCP server commands installed on the host.
- macOS when running MCP servers that depend on macOS APIs.
Set OTEL_EXPORTER_OTLP_ENDPOINT only when you want OTLP metrics and traces exported. If the variable is unset, the gateway still runs and uses no-op observability providers.
Install
Build a local binary:
go build -o host-mcp-gateway ./...
Install into your Go binary directory:
go install ./...
For a published module, the install command should use the repository module path:
go install github.com/replace-me/host-mcp-gateway@latest
The current go.mod uses the same placeholder path. Replace github.com/replace-me/host-mcp-gateway with the final repository path before publishing a release.
Configuration
By default, the gateway reads:
~/.config/host-mcp-gateway/config.json
Create a config from the sample:
mkdir -p ~/.config/host-mcp-gateway
cp config/host-mcp-gateway.sample.json ~/.config/host-mcp-gateway/config.json
Generate a bearer token for auth_token:
openssl rand -hex 32
The config file is JSON:
{
"bind_host": "127.0.0.1",
"bind_port": 7411,
"request_timeout_ms": 30000,
"restart_backoff_ms": 2000,
"auth_token": "replace-me-generate-a-token",
"allowed_clients": [
"127.0.0.1/32",
"::1/128"
],
"servers": [
{
"server_id": "host-service",
"command": "/usr/local/bin/replace-me-mcp-server",
"args": [],
"working_dir": "",
"env": {},
"autostart": true,
"restart_policy": "on-failure",
"startup_timeout_ms": 30000
}
]
}
Config fields:
| Field | Required | Default | Description |
|---|---|---|---|
bind_host |
No | 127.0.0.1 |
Interface for the HTTP server. |
bind_port |
No | 7411 |
Port for the HTTP server. |
request_timeout_ms |
No | 30000 |
Timeout for MCP request/response calls. |
restart_backoff_ms |
No | 2000 |
Delay before restarting a crashed MCP process. |
auth_token |
Yes | None | Bearer token required by all endpoints. |
allowed_clients |
Yes | None | IP addresses, CIDRs, or localhost. |
servers |
Yes | None | MCP server process definitions. |
Server fields:
| Field | Required | Default | Description |
|---|---|---|---|
server_id |
Yes | None | Unique routing key for the MCP server. |
command |
Yes | None | Executable path or command name. |
args |
No | [] |
Command arguments. |
working_dir |
No | "" |
Working directory for the child process. |
env |
No | {} |
Additional environment variables. |
autostart |
No | false |
Starts the process when the gateway starts. |
restart_policy |
No | on-failure |
One of always, on-failure, or never. |
startup_timeout_ms |
No | 0 |
Reserved by config; process startup is currently marked ready after spawn. |
Run
Run with the default config path:
./host-mcp-gateway
Run with an explicit config:
./host-mcp-gateway -config ~/.config/host-mcp-gateway/config.json
Enable OTLP export:
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 \
./host-mcp-gateway -config ~/.config/host-mcp-gateway/config.json
The gateway is designed to run on the host that owns the MCP server capabilities. Host-only services should be launched where their APIs, permissions, and local resources are actually available.
HTTP API
Every request must include:
Authorization: Bearer <auth_token>
GET /health returns gateway uptime, version, aggregate status, and configured server statuses.
GET /servers returns configured server statuses.
POST /rpc accepts a wrapper request and returns a wrapper response:
{
"server_id": "host-service",
"payload": {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
}
POST /{server_id}/rpc sends a raw MCP JSON-RPC request body to the named server and returns the raw MCP JSON-RPC response body.
GET /{server_id}/rpc opens a server-sent event stream and returns MCP-Session-Id when a session ID exists or is created.
Error responses use this shape:
{
"error": {
"error_code": "server_not_found",
"message": "unknown server_id",
"server_id": "host-service",
"request_id": "1"
}
}
LaunchAgent
A sample macOS LaunchAgent is provided at launchd/host-mcp-gateway.plist.sample.
Copy and edit the sample:
cp launchd/host-mcp-gateway.plist.sample \
~/Library/LaunchAgents/host-mcp-gateway.plist
Replace replace-me paths with your macOS username and confirm the binary path. Add OTEL_EXPORTER_OTLP_ENDPOINT only when you want OTLP export enabled.
Load the LaunchAgent:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/host-mcp-gateway.plist
Unload the LaunchAgent:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/host-mcp-gateway.plist
Development
Run tests:
go test ./...
Run the configured linter when golangci-lint is installed:
golangci-lint run
This repository uses the MIT license. See LICENSE.
Documentation
¶
There is no documentation for this package.