Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••••••••••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

Running Docker MCP Gateway on Linux (Without Docker Desktop)

Docker's MCP Toolkit is a great way to expose Model Context Protocol servers to AI clients like Claude, n8n, or Cursor. Out of the box it's designed for Docker…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!

Docker's MCP Toolkit is a great way to expose Model Context Protocol servers to

AI clients like Claude, n8n, or Cursor. Out of the box it's designed for Docker

Desktop on macOS and Windows — but what if you want to run it on a headless Linux

server? A Raspberry Pi, a VPS, a home lab box?



This guide walks through setting it up from scratch on Linux (Debian/Ubuntu, arm64

or amd64), including secrets management, custom MCP server images, and a systemd

service that starts automatically on boot.




This guide is based on getting it actually working on a Raspberry Pi 5 running

Debian 13. Several things that look like they should work on Linux don't — I'll

call those out explicitly so you don't waste time on the same dead ends.








What We're Building



A self-hosted MCP gateway that:




  • Runs any MCP server as a Docker container

  • Exposes them all behind a single HTTP endpoint with Bearer token auth

  • Starts automatically on boot via systemd



AI Client  →  http://your-server:8811/sse  →  docker-mcp gateway  →  MCP containers









Prerequisites




  • Linux host with Docker installed (Docker Engine, not Docker Desktop)

  • Your user in the docker group (sudo usermod -aG docker $USER)

  • SSH access if setting up remotely







Step 1 — Install the docker-mcp Binary



The docker mcp command is a Docker CLI plugin. On Linux you install it directly

from the GitHub releases — no Docker Desktop needed.




# Create the CLI plugins directory
sudo mkdir -p /usr/local/lib/docker/cli-plugins

# Download the binary for your architecture
# arm64 (Raspberry Pi 4/5, Apple Silicon VMs):
sudo curl -fsSL \
https://github.com/docker/mcp-gateway/releases/download/v0.41.0/docker-mcp-linux-arm64.tar.gz \
| sudo tar -xz -C /usr/local/lib/docker/cli-plugins/

# amd64 (regular x86 server):
sudo curl -fsSL \
https://github.com/docker/mcp-gateway/releases/download/v0.41.0/docker-mcp-linux-amd64.tar.gz \
| sudo tar -xz -C /usr/local/lib/docker/cli-plugins/

sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-mcp

# Verify
docker mcp --version






Check the releases page for the

latest version.







Step 2 — The docker-pass Workaround



This is the first Linux-specific gotcha. docker mcp CLI commands (like

docker mcp server ls) expect a Docker CLI plugin named docker-pass. This binary

ships with Docker Desktop on macOS but not on Linux, causing this error:




docker pass has not been installed






The fix: a small wrapper script that satisfies the Docker CLI plugin protocol and

delegates to docker-credential-pass.



First, install docker-credential-pass:




# arm64:
sudo curl -fsSL \
https://github.com/docker/docker-credential-helpers/releases/download/v0.9.5/docker-credential-pass-v0.9.5.linux-arm64 \
-o /usr/local/bin/docker-credential-pass

# amd64:
sudo curl -fsSL \
https://github.com/docker/docker-credential-helpers/releases/download/v0.9.5/docker-credential-pass-v0.9.5.linux-amd64 \
-o /usr/local/bin/docker-credential-pass

sudo chmod +x /usr/local/bin/docker-credential-pass






Then create the wrapper plugin:




sudo tee /usr/local/lib/docker/cli-plugins/docker-pass > /dev/null << 'EOF'
#!/bin/bash
if [[ "
$1" == "docker-cli-plugin-metadata" ]]; then
echo '{"SchemaVersion":"0.1.0","Vendor":"Docker","Version":"v1.0.0","ShortDescription":"Docker Pass secrets helper"}'
exit 0
fi
exec docker-credential-pass "
$@"
EOF

sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-pass






Verify Docker recognizes it:




docker info --format '{{.ClientInfo.Plugins}}' | tr ',' '\n' | grep pass
# Should show: ...pass /usr/local/lib/docker/cli-plugins/docker-pass...







Note: This wrapper is only needed for docker mcp CLI commands. The gateway

itself uses a different mechanism for secrets — covered in Step 5.










Step 3 — Pull or Load Your MCP Images



Any Docker image that implements the MCP stdio protocol can be used as an MCP server.






Option A: Images from the official Docker MCP catalog






docker pull mcp/playwright:latest









Option B: Custom/private images



Transfer from another machine:




# On the source machine:
docker save mcp/my-server:latest | ssh your-linux-host "docker load"












Step 4 — Configure the Gateway



Create the config directory:




mkdir -p ~/.docker/mcp/catalogs









registry.yaml — which servers to enable






cat > ~/.docker/mcp/registry.yaml << 'EOF'
registry:
playwright:
ref: ""
my-server:
ref: ""
EOF









catalog.json — where to find catalog definitions



The gateway needs to know where your catalog files live. By default it only reads

the official Docker MCP catalog. Register additional catalogs here:




cat > ~/.docker/mcp/catalog.json << 'EOF'
{
"catalogs": {
"docker-mcp": {
"displayName": "Docker MCP Catalog",
"url": "https://desktop.docker.com/mcp/catalog/v2/catalog.yaml"
},
"my-catalog": {
"displayName": "My Custom Servers",
"url": "/home/youruser/.docker/mcp/catalogs/my-catalog.yaml"
}
}
}
EOF









A catalog YAML for a custom server



The catalog defines how a server runs and which env vars it needs. List all

env vars under secrets: — including non-sensitive ones like usernames.




Linux gotcha: The config: field in catalog YAMLs is not used for env var

injection on Linux. Everything must be in secrets: to be passed to containers.







registry:
my-server:
title: My MCP Server
description: Does something useful
image: mcp/my-server:latest
type: server
tools: []
secrets:
- name: my-server.api_key
env: API_KEY
description: API key for the service
- name: my-server.username
env: USERNAME
description: Your username
name: my-catalog
displayName: My Catalog












Step 5 — Secrets



This is the second major Linux gotcha. docker mcp uses a secrets engine

(se:// URIs) that is Docker Desktop-only and doesn't work on Linux. The

docker mcp secret set command will fail with docker pass has not been installed

even after you install the wrapper from Step 2.



The solution is the --secrets flag, which points the gateway at a plain env file:




# Create the secrets file
cat > ~/.docker/mcp/secrets.env << 'EOF'
my-server.api_key=your-api-key-here
my-server.username=your-username
EOF

# Restrict permissions — only your user can read it
chmod 600 ~/.docker/mcp/secrets.env






The key names map to the name field in the catalog's secrets: list.



Is this secure? The file is chmod 600 — readable only by your user, same

as ~/.ssh/id_rsa. Anyone who can read it already has root or is you. If you want

GPG encryption at rest, you can store sensitive values in pass and populate the

file from it — but for an unattended service the threat model is the same either way.



Are secrets isolated between MCP servers? Yes, completely. The secrets file is

never passed to or mounted into any container. The gateway reads it internally and

uses it purely as a lookup table. When spawning each container it passes only the

specific -e VAR=value flags declared in that server's catalog secrets: list.

You can verify this with --dry-run --verbose — the docker run command for each

server is logged in full, and you'll see that playwright gets zero secret env vars,

while lanis-mcp only gets LANIS_*. There is no way for one MCP server to access

another's credentials.







Step 6 — Test the Gateway



Do a dry run first:




docker mcp gateway run \
--dry-run \
--verbose \
--secrets ~/.docker/mcp/secrets.env \
2>&1






You should see all your configured servers listed and their tools counted, with no

Warning: Secret '...' not found lines. If warnings appear, check that the key

names in secrets.env exactly match the name fields in your catalog YAML.



If everything looks good, start it live:




docker mcp gateway run \
--transport sse \
--port 8811 \
--secrets ~/.docker/mcp/secrets.env












Step 7 — systemd Service



Create the service file:




sudo tee /etc/systemd/system/mcp-gateway.service > /dev/null << EOF
[Unit]
Description=Docker MCP Gateway
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=simple
User=
$(whoami)
Environment=HOME=
$HOME
ExecStart=/usr/local/lib/docker/cli-plugins/docker-mcp gateway run
\\
--transport sse
\\
--port 8811
\\
--secrets
$HOME/.docker/mcp/secrets.env
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF






Set a stable Bearer token that survives restarts:




sudo mkdir -p /etc/systemd/system/mcp-gateway.service.d

TOKEN=$(openssl rand -hex 32)
echo "Save this token: $TOKEN"

sudo tee /etc/systemd/system/mcp-gateway.service.d/token.conf > /dev/null << EOF
[Service]
Environment=MCP_GATEWAY_AUTH_TOKEN=
$TOKEN
EOF






Without this, the gateway generates a new random token on every start — which means reconfiguring every client after each restart.



Enable and start:




sudo systemctl daemon-reload
sudo systemctl enable mcp-gateway.service
sudo systemctl start mcp-gateway.service






Check it's running:




sudo systemctl status mcp-gateway.service
journalctl -u mcp-gateway.service -f












Connecting a Client



The gateway runs on port 8811 with SSE transport:




URL:   http://your-server:8811/sse
Auth: Authorization: Bearer <your-token>









Claude Desktop



Add to ~/Library/Application Support/Claude/claude_desktop_config.json

(macOS) or the equivalent on your OS:




{
"mcpServers": {
"my-gateway": {
"command": "npx",
"args": [
"mcp-remote",
"http://your-server:8811/sse",
"--header",
"Authorization: Bearer <your-token>",
"--allow-http",
"--transport",
"sse-only"
]
}
}
}






Two flags are required here that aren't obvious:





  • --allow-http — mcp-remote blocks non-HTTPS URLs by default


  • --transport sse-only — the default http-first strategy sends a POST that
    the gateway rejects with sessionid must be provided









Troubleshooting






docker pass has not been installed



The docker-pass CLI plugin wrapper is missing or not executable. Re-check Step 2.






Warning: Secret '...' not found



The key name in secrets.env doesn't match the name field in the catalog YAML,

or you forgot to pass --secrets to the gateway. Check with:




docker mcp gateway run --dry-run --verbose --secrets ~/.docker/mcp/secrets.env 2>&1 | grep Warning









Server shows 0 tools in dry-run but works live



Some servers need the actual secrets present to respond to tool listing. This is

normal — the gateway still starts them correctly at runtime.






cannot use --port with --transport=stdio



You must specify --transport sse when using --port. The default transport is

stdio (for direct client connections), not HTTP.






sessionid must be provided in mcp-remote



Add --transport sse-only to the mcp-remote args. The default transport strategy

tries Streamable HTTP first, which the gateway doesn't support.









Keeping Things Updated






Upgrade docker-mcp






VERSION=v0.41.0  # replace with latest
ARCH=arm64 # or amd64

sudo curl -fsSL \
https://github.com/docker/mcp-gateway/releases/download/$VERSION/docker-mcp-linux-$ARCH.tar.gz \
| sudo tar -xz -C /usr/local/lib/docker/cli-plugins/

sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-mcp
sudo systemctl restart mcp-gateway.service









Update a custom MCP image






docker save mcp/my-server:latest | ssh your-linux-host "docker load"
ssh your-linux-host "sudo systemctl restart mcp-gateway.service"












Summary



The key differences from macOS Docker Desktop:











































Concern macOS (Docker Desktop) Linux (headless)

docker-mcp binary
Bundled with Docker Desktop Downloaded from GitHub releases

docker-pass plugin
Proprietary binary Wrapper script → docker-credential-pass
Secrets injection
docker mcp secret set + keychain

--secrets <env-file> (chmod 600)
Auto-start Docker Desktop systemd service
Transport stdio or SSE SSE with --transport sse
mcp-remote Default settings work Needs --allow-http --transport sse-only


Everything else — catalog YAMLs, registry.yaml, the docker mcp CLI — works

identically between macOS and Linux once the above pieces are in place.

🔍 CTI & Forensik

Cyber Threat Intelligence & Forensik

ATT&CK-Navigator · IoC-Radar · Exploit-Belege
CTI Threat Relationship Graph
Akteure · Techniken · Beziehungen
4 Knoten · 3 Relationen
CVE / Incident Threat Actor Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Running Docker MCP Gateway on Linux (Without Docker Desktop)

Thematisch verwandte Begriffe: Running, Docker, Gateway, Linux · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag