Self-hosted MCP gateway for a team
Two ways to share#
| Headless gateway (MIT) | Toolport Teams | |
|---|---|---|
| What it is | The same toolport-gateway binary, serving MCP and OpenAPI over HTTP |
Shared server configuration and policies across a team |
| Credentials | Env vars or an encrypted secrets.enc vault on the host |
Each member keeps their own credentials |
| Where | Your Docker host | Hosted and self-hosted options |
Run the headless gateway#
docker pull ghcr.io/btsouth/toolport-gateway:latest
mkdir -p data
cp data/registry.json.example data/registry.json
cp docker-compose.example.yml docker-compose.yml
# create .env with at least TOOLPORT_HTTP_TOKEN=...
docker compose up -dMCP clients connect to http://host:8765/mcp (streamable HTTP). Open WebUI, n8n and LibreChat use http://host:8765 as an OpenAPI tool server.
One token per caller#
List callers in httpClients[] in registry.json so each gets its own token and profile scope, instead of one shared global token. A scoped client only sees tools, and help_<server> browse tools, for servers in its scope.
Discovery can differ per caller too: clientDiscovery[<http-client-id>] set to full for clients with native tool search (Claude Code, Codex) and lazy for the rest.
Before you expose it#
The gateway speaks plain HTTP. Terminate TLS at nginx, Caddy, Traefik or a load balancer, firewall the port, and never send the bearer token over untrusted HTTP. Non-loopback binds refuse to start without a token.
- Token entropy — at least 24 bytes:
openssl rand -hex 24. - Human approval — set
humanApproval: falsein the registry. Without the desktop app's approval broker, gated tools fail closed. - OAuth — browser OAuth still needs the desktop app. Use API keys or pre-vaulted secrets on headless hosts.
- Pin the image — use a digest or version tag, not only
:latest.
The full checklist is in Headless gateway and Docker.