Run a Model Context Protocol (MCP) Gateway on Unraid to let AI agents — Claude Desktop, VS Code, Cursor — securely access Docker-hosted MCP tools across your LAN. Built from docker/mcp-gateway.
| Test | Result |
|---|---|
/health endpoint |
HTTP 200 |
MCP initialize |
Gateway v2.0.1 — tools, prompts, resources confirmed |
tools/list |
8 built-in tools (code-mode, mcp-add, mcp-find, etc.) |
| Auth token auth | Bearer token required and enforced |
| Streaming transport | SSE + HTTP POST — session-based bidirectional messaging |
Gateway startup log
- Reading profile configuration...
- Default profile not found, using empty configuration
- Loading 1 catalog(s) for dynamic tools
- Processing catalog 'mcp/docker-mcp-catalog:latest' with 313 servers
- Total servers loaded from all catalogs: 313
- No server is enabled
- Listing MCP tools...
> 0 tools listed in 21.429µs
- Adding internal tools (dynamic-tools feature enabled)
> mcp-find: tool for finding MCP servers in the catalog
> mcp-add: tool for adding MCP servers to the registry
> mcp-remove: tool for removing MCP servers from the registry
> code-mode: write code that calls other MCPs directly
> mcp-exec: execute tools that exist in the current session
> mcp-config-set: tool for setting configuration values for MCP servers
> mcp-create-profile: tool for creating or updating profiles with current gateway state
> mcp-activate-profile: tool for activating saved profiles
> mcp-discover: prompt for learning about dynamic server management
- Watching for configuration updates...
> Initialized in 270.152586ms
> Start streaming server on port 8811
> Gateway URL: http://localhost:8811/mcp
> Use Bearer token from MCP_GATEWAY_AUTH_TOKEN environment variable
Catalog mcp/docker-mcp-catalog:latest pulled
- Client initialized test-client@1.0.0
- Client initialized Zed@0.1.0 (4 connections)
- Unraid users who want AI agent capabilities on their home server
- Self-hosters looking for a local, private MCP gateway instead of cloud-based AI tool access
- Developers running Claude Desktop, VS Code, or Cursor who need Docker-hosted MCP tools on their LAN
- Docker users deploying MCP servers in isolated containers managed by a lightweight gateway
AI Client ──→ MCP Gateway (Unraid container, port 8811) ──→ MCP Servers (isolated containers)
- Quick Start
- Features
- Installation
- Configuration
- Adding Custom MCP Servers
- Connecting AI Clients
- Architecture
- Security
- Build from Source
- FAQ and Troubleshooting
- License
# 1. Clone and configure
git clone https://github.com/wildfirebill-unraid/mcp-gateway-unraid.git
cd mcp-gateway-unraid
cp .env.example .env
# 2. Set your MCP_GATEWAY_AUTH_TOKEN in .env
echo "MCP_GATEWAY_AUTH_TOKEN=mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" >> .env
# 3. Start the gateway
docker compose up -d
# 4. Verify
curl http://localhost:8811/health
# 5. Connect your AI agent
curl -H "Authorization: Bearer mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" http://localhost:8811/mcpYour AI clients connect to
http://<unraid-ip>:8811/mcpwith theAuthorization: Bearer <token>header.
- 🔒 LAN-only by default — all traffic stays on your local network
- 🔐 Bearer authentication — every MCP request requires a token (
MCP_GATEWAY_AUTH_TOKEN) - 📦 Isolated containers — each MCP server runs in its own Docker container with resource limits
- 🔌 Multiple transport modes —
streaming(recommended for LAN),sse, orstdio - 🛡️ Secrets isolation — API keys stored in a mounted
.envfile, never in environment variables - 🧩 Dynamic catalog — auto-pulls the Docker MCP catalog on start for discoverable tools
- 🖥️ Unraid ready — download the XML template for one-click install (Community Apps listing coming soon)
- 🏗️ Builds from source — no dependency on Docker Hub availability
Community Apps listing coming soon. For now, install via the XML template in this repo.
Step 1 — Copy the template to your Unraid server:
# From any machine on your LAN, copy the XML to Unraid's user templates folder:
scp unraid/mcp-gateway-unraid.xml root@<unraid-ip>:/boot/config/plugins/dockerMan/templates-user/
# Or download it directly on Unraid via the web terminal:
cd /boot/config/plugins/dockerMan/templates-user/
wget https://raw.githubusercontent.com/wildfirebill-unraid/mcp-gateway-unraid/main/unraid/mcp-gateway-unraid.xmlStep 2 — Install from the Unraid web UI:
- Go to Docker → Add Container
- Click Template → select mcp-gateway-unraid from the dropdown
- Set your Auth Token (
MCP_GATEWAY_AUTH_TOKEN— required) - Click Apply
The template is now listed alongside your other containers — no need to re-add it after reboots.
git clone https://github.com/wildfirebill-unraid/mcp-gateway-unraid.git
cd mcp-gateway-unraid
cp .env.example .env
# Edit .env to set MCP_GATEWAY_AUTH_TOKEN and GATEWAY_SERVERS
docker compose up -ddocker run -d \
--name unraid-mcp-gateway \
--restart unless-stopped \
-e DOCKER_MCP_IN_CONTAINER=1 \
-e MCP_GATEWAY_AUTH_TOKEN=mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 \
-e GATEWAY_SERVERS=fetch,duckduckgo \
-p 8811:8811 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /mnt/user/appdata/mcp-gateway/secrets:/secrets:ro \
ghcr.io/wildfirebill-unraid/mcp-gateway-unraid:latestThe image is hosted on GitHub Container Registry (ghcr.io) — no Docker Hub account needed.
| Variable | Default | Description |
|---|---|---|
MCP_GATEWAY_AUTH_TOKEN |
(auto-generated) | Bearer token for endpoint authentication. Required for persistent client access. |
GATEWAY_TRANSPORT |
streaming |
Transport protocol: stdio, sse, or streaming |
GATEWAY_PORT |
8811 |
Port the gateway listens on |
GATEWAY_SERVERS |
fetch,duckduckgo |
Comma-separated list of MCP servers to enable |
GATEWAY_MEMORY |
2Gb |
Memory limit per MCP server container |
GATEWAY_CPUS |
1 |
CPU cores per MCP server container |
GATEWAY_LOG_CALLS |
true |
Log MCP tool calls to stdout |
GATEWAY_VERIFY_SIGNATURES |
false |
Verify Docker MCP image signatures |
DOCKER_MCP_IN_CONTAINER |
1 |
Must be set to 1 for Unraid / non-Docker-Desktop environments |
The gateway enforces Bearer token authentication on all endpoints except /health.
- Set
MCP_GATEWAY_AUTH_TOKENas an environment variable on the container - If unset, a random 50-character token is generated on every container start (token changes on restart)
- Clients send the token in the
Authorizationheader:
Authorization: Bearer mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0To persist the same token across restarts, set MCP_GATEWAY_AUTH_TOKEN
in your Unraid template or .env file.
The gateway uses the Docker MCP Catalog which includes:
| Server | Description | Image |
|---|---|---|
fetch |
HTTP requests to fetch URLs | docker/mcp-fetch |
duckduckgo |
Web search | docker/mcp-duckduckgo |
filesystem |
Read/write access to mounted paths | docker/mcp-filesystem |
github-official |
GitHub API (issues, PRs, repos) | docker/mcp-github |
slack |
Slack workspace access | docker/mcp-slack |
postgres |
PostgreSQL database queries | docker/mcp-postgres |
notion |
Notion workspace tools | docker/mcp-notion |
Set via GATEWAY_SERVERS=fetch,duckduckgo,filesystem,github-official.
Beyond the default fetch and duckduckgo servers, you can add any MCP
server to the gateway. There are two categories:
- Catalog servers — published in the
Docker MCP Catalog (just add the name
to
GATEWAY_SERVERS) - Custom servers — any other MCP server (use one of the three options below)
This walks through adding the filesystem MCP server so your AI agent
can read/write files on a Unraid share.
- Go to Docker → click the MCP Gateway container → Edit
- Find the MCP Servers (
GATEWAY_SERVERS) variable - Change it from
fetch,duckduckgotofetch,duckduckgo,filesystem - Click Apply — the gateway restarts and spawns a filesystem container
- Your AI client can now use
read_file,write_file,list_directorytools
All catalog servers work the same way: just add the server name to
GATEWAY_SERVERS. See the table below for available servers.
For servers not in the Docker MCP Catalog, use one of the three approaches below.
Unraid appdata convention: Place custom YAML files in
/mnt/user/appdata/mcp-gateway/so they persist across container updates.
Create a full catalog file that mixes Docker catalog servers with your own, then mount it into the container.
1. Create catalog.yaml on your Unraid server:
mkdir -p /mnt/user/appdata/mcp-gateway
nano /mnt/user/appdata/mcp-gateway/catalog.yamlFor a container-based server (Docker image the gateway spawns):
version: 3
name: docker-mcp
displayName: Docker MCP Catalog
servers:
my-custom-server:
description: "My custom MCP tool"
title: "Custom Server"
type: "server"
image: "my-org/custom-mcp-server:v1"
env:
- name: "API_KEY"
value: "{{my-custom-server.api_key}}"
command:
- "--transport=stdio"
config:
- name: "my-custom-server"
description: "Server configuration"
type: "object"
properties:
api_key:
type: "string"
description: "API key for the server"
required: ["api_key"]For an HTTP-based server (already running elsewhere on your network):
my-http-server:
type: http
url: "http://host.docker.internal:3000/mcp"2a. Docker Compose — mount the catalog:
services:
gateway:
image: ghcr.io/wildfirebill-unraid/mcp-gateway-unraid:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./catalog.yaml:/mcp/catalog.yaml:ro
command:
- --catalog=/mcp/catalog.yaml
- --servers=fetch,duckduckgo,my-custom-server
- --transport=streaming
- --port=88112b. Unraid web UI — mount the catalog:
In the gateway container's edit view, add:
| Field | Value |
|---|---|
| Extra Parameters | --catalog=/mcp/catalog.yaml --servers=fetch,duckduckgo,my-custom-server |
| Path / Volume | Container Path: /mcp/catalog.yaml ← Host Path: /mnt/user/appdata/mcp-gateway/catalog.yaml (read-only) |
The gateway spawns my-custom-server as a sibling container just like
catalog servers — same resource limits, secrets injection, and lifecycle
management.
Define a single server in a YAML file and reference it directly with --server file://.
1. Create my-server.yaml on your Unraid server:
mkdir -p /mnt/user/appdata/mcp-gateway
nano /mnt/user/appdata/mcp-gateway/my-server.yamlregistry:
my-dev-server:
description: "Development server"
title: "Dev Server"
type: "server"
image: "myorg/dev-server:latest"
tools:
- name: "dev_tool"
env:
- name: "MY_KEY"
value: "{{my-dev-server.my_key}}"
config:
- name: "my-dev-server"
description: "Config"
type: "object"
properties:
my_key:
type: "string"
required: ["my_key"]2a. Docker Compose — mount and reference:
services:
gateway:
image: ghcr.io/wildfirebill-unraid/mcp-gateway-unraid:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./my-server.yaml:/servers/my-server.yaml:ro
command:
- --server=file:///servers/my-server.yaml
- --servers=fetch,duckduckgo,my-dev-server
- --transport=streaming
- --port=88112b. Unraid web UI — mount and reference:
In the gateway container's edit view, add:
| Field | Value |
|---|---|
| Extra Parameters | --server=file:///servers/my-server.yaml --servers=fetch,duckduckgo,my-dev-server |
| Path / Volume | Container Path: /servers/my-server.yaml ← Host Path: /mnt/user/appdata/mcp-gateway/my-server.yaml (read-only) |
The --server file:// flag can be repeated and mixed with catalog servers.
Run your MCP server as its own container alongside the gateway (separate container in Unraid's Docker tab). Connect clients directly to it, bypassing the gateway.
In Unraid web UI — add a new container:
- Go to Docker → Add Container
- Set Repository to
my-org/custom-mcp-server:v1 - Set a fixed Container Port mapping (e.g.
3000:3000) - Add
API_KEY=sk-custom-server-key-abc123in Environment Variables - Click Apply
Connect your AI client to the companion directly:
{
"mcpServers": {
"Local_Server": {
"url": "http://192.168.1.100:3000/mcp"
}
}
}Trade-offs:
| Approach | Lifecycle managed by gateway | Secrets injection | Resource limits | Best for |
|---|---|---|---|---|
| Custom catalog | ✅ | ✅ | ✅ | Servers you want fully managed |
file:// definition |
✅ | ✅ | ✅ | Adding one-off servers to an existing setup |
| Companion container | ❌ | ❌ (manual) | ❌ (manual) | Quick testing, HTTP-only servers, or when you can't containerize |
All clients connect to http://<unraid-ip>:8811/mcp with the
Authorization: Bearer <token> header.
Option A — URL connection (streaming):
In claude_desktop_config.json:
{
"mcpServers": {
"Unraid_Gateway": {
"url": "http://192.168.1.100:8811/mcp",
"headers": {
"Authorization": "Bearer mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
}
}
}
}Option B — Local Docker Desktop (for testing):
{
"mcpServers": {
"MCP_DOCKER": {
"command": "docker",
"args": ["mcp", "gateway", "run", "--transport", "streaming", "--port", "8811"]
}
}
}In .vscode/mcp.json:
{
"servers": {
"Unraid_Gateway": {
"url": "http://192.168.1.100:8811/mcp",
"headers": {
"Authorization": "Bearer mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
},
"type": "sse"
}
}
}Settings → MCP → Add new MCP server:
- Name: Unraid Gateway
- Type:
url - URL:
http://192.168.1.100:8811/mcp - Headers:
{"Authorization": "Bearer mcp_gateway_token_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"}
┌──────────────────────────────────────────────────────────────────┐
│ Unraid Server │
│ │
│ ┌─────────────────────┐ ┌────────────────────────────────┐ │
│ │ AI Client │ │ MCP Gateway Container │ │
│ │ (Claude / VS Code │─────▶│ ghcr.io/.../mcp-gateway-unraid│ │
│ │ / Cursor) │ │ Port 8811 │ │
│ └─────────────────────┘ │ Auth: Bearer token │ │
│ │ Entrypoint: env-var to CLI │ │
│ └──────────┬─────────────────────┘ │
│ │ │
│ ┌──────────▼─────────────────────┐ │
│ │ MCP Server Containers │ │
│ │ (fetch, duckduckgo, │ │
│ │ filesystem, github, etc.) │ │
│ │ Each gets: CPU/MEM limits, │ │
│ │ isolated networking │ │
│ └────────────────────────────────┘ │
│ │
│ /var/run/docker.sock ◄── gateway creates sibling containers │
│ ./secrets/.env ◄── API keys mounted read-only │
└──────────────────────────────────────────────────────────────────┘
- 🔐 Bearer auth — all MCP endpoints require a valid token
- 🏠 LAN-only — gateway listens on your LAN, not exposed to the internet
- 📦 Container isolation — each MCP server runs in its own container with resource limits
- 🔑 Secrets isolation — credentials in a mounted
.envfile, never in process environment - 🖼️ Image signatures — optional image signature verification
- 🚫 No root — MCP servers run with limited privileges
- 🔄 Auto-generated tokens — if
MCP_GATEWAY_AUTH_TOKENis unset, a new random token is generated on each start
The Dockerfile builds the gateway from the official docker/mcp-gateway repository:
docker build -t mcp-gateway-unraid:local .This produces the same multi-stage build used in CI/CD and published to ghcr.io.
Contributions are welcome! Here's how to help:
- Report issues — open a GitHub issue for bugs or feature requests
- Submit PRs — fork the repo, make changes, and open a pull request
- Improve docs — README updates, better examples, and troubleshooting tips are always appreciated
See the open issues for current tasks.
Your MCP_GATEWAY_AUTH_TOKEN is missing or doesn't match the client's
Authorization header. Set a fixed token in the Unraid template and
pass it as Authorization: Bearer <token> in every client request.
This environment variable is missing. Set DOCKER_MCP_IN_CONTAINER=1 on
the container to tell the gateway it's running inside a Docker container
on a Linux host (Unraid) rather than Docker Desktop.
The Docker socket is not mounted. Mount /var/run/docker.sock so the
gateway can create sibling MCP server containers.
Port 8811 is likely blocked by the Unraid firewall. Navigate to Settings → Firewall in Unraid and allow inbound TCP traffic on port 8811.
Check that ./secrets/.env exists, is readable, and follows the correct
format (KEY=VALUE on each line). The file must be mounted into the
container at /secrets/.env.
The container started before your network interface was ready. Restart the container — the catalog pull is retried on each start.
No MCP_GATEWAY_AUTH_TOKEN was set, so the gateway generated a random
one. Set a fixed token in the Unraid template or .env file to keep it
stable.
See the Adding Custom MCP Servers section
above for three approaches: custom catalog.yaml, file:// definitions,
or companion containers.
Yes — that's the point. Set DOCKER_MCP_IN_CONTAINER=1 for Unraid and
other non-Docker-Desktop Docker hosts.
No. It listens on the Unraid LAN interface (port 8811) by default. Do not port-forward this port unless you have additional security measures in place.
- docker/mcp-gateway — the official upstream gateway this image builds from
- Docker MCP Toolkit & Catalog — official Docker MCP catalog documentation
- Model Context Protocol — the open standard this gateway implements
- Claude Desktop — AI desktop client with MCP support
- VS Code MCP — using MCP servers in VS Code Copilot
- Unraid Community Apps — one-click install templates for Unraid
MIT — see LICENSE.