
如果你使用 DeepSeek、元宝 AI、Copilot、ChatGPT 等 AI 工具,协助配置轩辕镜像、编写 docker pull 命令、修改 Docker Compose 镜像地址、配置镜像加速、排查镜像拉取失败、分析报错日志等问题,请先让 AI 阅读并遵守轩辕镜像的规则文档。
只需在 AI 对话中先发送下面这段话即可:
请先阅读并遵守:https://xuanyuan.cloud/agents.md
未读文档前不要生成 pull 命令或排错方案。查看 agents.md 用法指南与完整示范。国内用户首推 元宝 AI、DeepSeek 的深度思考模式,不推荐豆包 AI;Cursor 等编辑器可在对话 @ 该链接,或加入 User Rules。 若 AI 无法访问外链,可 打开说明文档 复制全文粘贴。文档会随站点更新,复制内容可能过期,建议定期检查。
GitHub: https://github.com/hwdsl2/docker-mcp-gateway
Part of the https://github.com/hwdsl2/self-hosted-ai-stack — deploy a complete self-hosted AI stack with a single command.
Docker image to run a self-hosted https://modelcontextprotocol.io/ (Model Context Protocol) gateway, providing authenticated access to multiple MCP tool servers over HTTP from a single endpoint. Powered by https://github.com/samanhappy/mcphub with Caddy auth proxy. Designed to be simple and secure by default.
Features:
/mcp or individual servers at /mcp/<name>/ for monitoring MCP server statusmcp.env file; no JSON editing/health health check)linux/amd64, linux/arm64📘 New book: The Self-Hosted AI Builder’s Guide. A practical guide to building, securing, and operating your own private AI stack.
Also available:
MCP servers have no built-in authentication. Exposing them publicly without auth is the same class of problem as the ~175,000 unauthenticated Ollama servers found publicly exposed (source). This image enforces Bearer token authentication on all API requests via a built-in Caddy auth proxy, so unauthorized access is blocked even if the port is accidentally exposed.
Step 1. Start the MCP Gateway:
bashdocker run \ --name mcp \ --restart=always \ -v mcp-data:/var/lib/mcp \ -p 3000:3000/tcp \ -d hwdsl2/mcp-gateway
On first start, an API key is auto-generated and displayed in the container logs. All API requests require this key.
Note: For internet-facing deployments, using a reverse proxy to add HTTPS is strongly recommended. In that case, also replace -p 3000:3000/tcp with -p 127.0.0.1:3000:3000/tcp in the docker run command above, to prevent direct access to the unencrypted port.
Step 2. Get the API key:
bash# View the key in the container logs docker logs mcp # Or retrieve it for use in scripts MCP_KEY=$(docker exec mcp mcp_manage --getkey)
The API key is displayed in a box labeled MCP Gateway API key. To display it again at any time:
bashdocker exec mcp mcp_manage --showkey
Step 3. Test with the API:
bashMCP_KEY=$(docker exec mcp mcp_manage --getkey) # Test the MCP endpoint (fetch server is enabled by default) curl http://localhost:3000/mcp \ -H "Authorization: Bearer $MCP_KEY" # Check gateway health (no auth required) curl http://localhost:3000/health
Note: The docker exec management commands (mcp_manage) do not require the API key.
To learn more about how to use this image, read the sections below.
Get the trusted build from the https://hub.docker.com/r/hwdsl2/mcp-gateway/:
bashdocker pull hwdsl2/mcp-gateway
Alternatively, you may download from https://quay.io/repository/hwdsl2/mcp-gateway:
bashdocker pull quay.io/hwdsl2/mcp-gateway docker image tag quay.io/hwdsl2/mcp-gateway hwdsl2/mcp-gateway
Supported platforms: linux/amd64 and linux/arm64.
All variables are optional. If not set, secure defaults are used automatically.
This Docker image uses the following variables, that can be declared in an env file (see https://github.com/hwdsl2/docker-mcp-gateway/blob/main/mcp.env.example):
| Variable | Description | Default |
|---|---|---|
MCP_API_KEY | API key for authenticating requests (auto-generated if not set) | Auto-generated |
MCP_PORT | TCP port for the gateway (1–65535) | 3000 |
MCP_HOST | Hostname or IP shown in startup info and --showkey output | Auto-detected |
MCP_SERVERS | Comma-separated list of MCP servers to enable | fetch |
MCP_ADMIN_PASSWORD | Password for the MCPHub dashboard admin account (auto-generated on first start if not set) | Auto-generated |
MCP_DISABLE_USAGE_COUNTS | Set to 1 to disable anonymous aggregate usage counts. | (not set) |
Note: In your env file, you may enclose values in single quotes, e.g. VAR='value'. Do not add spaces around =. If you change MCP_PORT, update the -p flag in the docker run command accordingly.
Example using an env file:
bashcp mcp.env.example mcp.env # Edit mcp.env and set your values, then: docker run \ --name mcp \ --restart=always \ -v mcp-data:/var/lib/mcp \ -v ./mcp.env:/mcp.env:ro \ -p 3000:3000/tcp \ -d hwdsl2/mcp-gateway
Enable servers by listing them in MCP_SERVERS (comma-separated):
| Server | Required config | Description |
|---|---|---|
fetch | — | Fetch URLs and extract content |
filesystem | MCP_FILESYSTEM_DIRS | Read/write files in allowed directories |
github | MCP_GITHUB_TOKEN | GitHub API access (repos, issues, PRs) |
brave-search | MCP_BRAVE_API_KEY | Web search via Brave Search API |
git | MCP_GIT_REPO | Git repository tools (status, diff, commit, log) |
postgres | MCP_POSTGRES_URL | Query PostgreSQL databases |
memory | — | Knowledge graph / persistent memory |
sequential-thinking | — | Structured thinking and reasoning |
Example:
bash# Enable filesystem, fetch, and GitHub servers MCP_SERVERS=filesystem,fetch,github MCP_FILESYSTEM_DIRS=/data/docs,/data/projects MCP_GITHUB_TOKEN=ghp_your_token_here
For the filesystem server, bind-mount host directories into the container:
bashdocker run \ --name mcp \ --restart=always \ -v mcp-data:/var/lib/mcp \ -v ./mcp.env:/mcp.env:ro \ -v /home/user/documents:/data/docs:ro \ -v /home/user/projects:/data/projects \ -p 3000:3000/tcp \ -d hwdsl2/mcp-gateway
For the git server, bind-mount the repository into the container and set MCP_GIT_REPO:
bashMCP_SERVERS=git MCP_GIT_REPO=/repo
bashdocker run \ --name mcp \ --restart=always \ -v mcp-data:/var/lib/mcp \ -v ./mcp.env:/mcp.env:ro \ -v /home/user/myrepo:/repo \ -p 3000:3000/tcp \ -d hwdsl2/mcp-gateway
Use docker exec to manage the gateway with the mcp_manage helper script.
List enabled servers:
bashdocker exec mcp mcp_manage --list
Test a specific server:
bashdocker exec mcp mcp_manage --test fetch docker exec mcp mcp_manage --test github
Show gateway status:
bashdocker exec mcp mcp_manage --status
Show the API key:
bashdocker exec mcp mcp_manage --showkey
Get the API key (machine-readable, for use in scripts):
bashMCP_KEY=$(docker exec mcp mcp_manage --getkey)
Add or remove servers at runtime:
Use the MCPHub dashboard at http://<server>:3000/ to add, configure, or remove MCP servers without restarting the container. Changes are saved to the persistent volume and survive restarts.
Note:
MCP_SERVERSonly applies on the first run whenmcp_settings.jsonis created. After that, the dashboard is the way to manage servers. To re-applyMCP_SERVERSfrom scratch, remove the config file and restart:bashdocker exec mcp rm /var/lib/mcp/mcp_settings.json docker restart mcp
All API requests require a Bearer token. Retrieve the API key first:
bashMCP_KEY=$(docker exec mcp mcp_manage --getkey)
MCP endpoint (all enabled servers):
bashcurl http://localhost:3000/mcp \ -H "Authorization: Bearer $MCP_KEY"
MCP endpoint (specific server):
bashcurl http://localhost:3000/mcp/fetch \ -H "Authorization: Bearer $MCP_KEY"
Dashboard (web UI):
Open http://localhost:3000/ in a browser with Authorization: Bearer <key>, or use a client that supports header injection.
Health check (no auth required):
bashcurl http://localhost:3000/health
Cline (VS Code) — in Cline's MCP settings:
json{ "mcpServers": { "gateway": { "url": "http://localhost:3000/mcp", "transport": "streamable-http", "headers": { "Authorization": "Bearer <api_key>" } } } }
Claude Desktop — in claude_desktop_config.json:
json{ "mcpServers": { "gateway": { "url": "http://localhost:3000/mcp", "transport": "streamable-http", "headers": { "Authorization": "Bearer <api_key>" } } } }
All gateway data is stored in the Docker volume (/var/lib/mcp inside the container):
/var/lib/mcp/ ├── mcp_settings.json # Generated MCPHub configuration ├── .api_key # API key (auto-generated, or synced from MCP_API_KEY) ├── .initialized # First-run marker ├── .port # Saved port (used by mcp_manage) ├── .servers # Enabled servers list (used by mcp_manage) └── .Caddyfile # Generated Caddy config (auth proxy)
mcp_settings.json is generated from MCP_SERVERS on first run only. Subsequent restarts reuse the existing file, preserving any changes made via the dashboard.
Back up the Docker volume to preserve your configuration and API key.
bashcp mcp.env.example mcp.env # Edit mcp.env and set your values, then: docker compose up -d docker logs mcp
Example docker-compose.yml (already included):
yamlservices: mcp: image: hwdsl2/mcp-gateway container_name: mcp restart: always ports: - "3000:3000/tcp" # For a host-based reverse proxy, change to "127.0.0.1:3000:3000/tcp" volumes: - mcp-data:/var/lib/mcp - ./mcp.env:/mcp.env:ro # Mount host directories for the filesystem MCP server (optional): # - /path/to/docs:/data/docs:ro # - /path/to/code:/data/code:ro volumes: mcp-data: name: mcp-data
Note: For internet-facing deployments, using a reverse proxy to add HTTPS is strongly recommended. In that case, also change "3000:3000/tcp" to "127.0.0.1:3000:3000/tcp" in docker-compose.yml, to prevent direct access to the unencrypted port.
For internet-facing deployments, place a reverse proxy in front of MCP Gateway to handle HTTPS termination. The server works without HTTPS on a local or trusted network, but HTTPS is recommended when the API endpoint is exposed to the internet.
Use one of the following addresses to reach the MCP Gateway container from your reverse proxy:
mcp:3000 — if your reverse proxy runs as a container in the same Docker network as MCP Gateway (e.g. defined in the same docker-compose.yml).127.0.0.1:3000 — if your reverse proxy runs on the host and port 3000 is published (the default docker-compose.yml publishes it).Note: The Authorization: Bearer header passes through reverse proxies automatically — no special configuration needed.
Example with https://caddyserver.com/docs/ (https://hub.docker.com/_/caddy) (automatic TLS via Let's Encrypt, reverse proxy in the same Docker network):
Caddyfile:
mcp.example.com { reverse_proxy mcp:3000 }
Example with nginx (reverse proxy on the host):
nginxserver { listen 443 ssl; server_name mcp.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; # required for SSE and WebSocket proxy_read_timeout 300s; proxy_buffering off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
After setting up a reverse proxy, set MCP_HOST=mcp.example.com in your env file so that the correct endpoint URL is shown in the startup logs and mcp_manage --showkey output.
To update the Docker image and container, first download the latest version:
bashdocker pull hwdsl2/mcp-gateway
If the Docker image is already up to date, you should see:
Status: Image is up to date for hwdsl2/mcp-gateway:latest
Otherwise, it will download the latest version. Remove and re-create the container:
bashdocker rm -f mcp # Then re-run the docker run command from Quick start with the same volume.
Your configuration and API key are preserved in the mcp-data volume.
MCP Gateway can be used as the MCP tool gateway in a broader self-hosted AI setup.
For full and lightweight Docker Compose stacks, manual docker run examples, and voice/RAG/MCP pipeline examples with Kokoro, Embeddings, LiteLLM, Ollama, Docling, and MCP Gateway, see https://github.com/hwdsl2/self-hosted-ai-stack.
Connect MCP Gateway to LiteLLM:
yaml# In your LiteLLM config, add the MCP gateway as a tool source: mcp_servers: - url: http://mcp:3000/mcp transport: http headers: Authorization: "Bearer <mcp_api_key>"
See https://github.com/hwdsl2/docker-mcp-gateway#usage-counts.
samanhappy/mcphub (Python 3.13 + Node.js 22)3001 (not published; Caddy proxies from MCP_PORT)/var/lib/mcp (Docker volume)http://localhost:3000 (or your configured port)http://localhost:3000/mcplinux/amd64, linux/arm64Note: The software components inside the pre-built image (such as MCPHub, Caddy, and their dependencies) are under the respective licenses chosen by their respective copyright holders. As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within.
Copyright (C) 2026 Lin Song
This work is licensed under the https://opensource.org/licenses/MIT.
MCPHub is Copyright (C) 2025 samanhappy, and is distributed under the https://github.com/samanhappy/mcphub/blob/main/LICENSE.
Caddy is Copyright (C) 2015 Matthew Holt and The Caddy Authors, and is distributed under the https://github.com/caddyserver/caddy/blob/master/LICENSE.
This project is an independent Docker setup for MCPHub and is not affiliated with, endorsed by, or sponsored by MCPHub.
您可以使用以下命令拉取该镜像。请将 <标签> 替换为具体的标签版本。如需查看所有可用标签版本,请访问 标签列表页面。
来自真实用户的反馈,见证轩辕镜像的优质服务