Die Iso­lie­rung eines MCP-Servers mit Docker bedeutet, den Server samt Laufzeit und Ab­hän­gig­kei­ten in einem ab­ge­schot­te­ten Container aus­zu­füh­ren. Dadurch lassen sich die Datei-, Netzwerk- und Sys­tem­zu­grif­fe eines LLM-ge­steu­er­ten Tools gezielt begrenzen, während die übrige Host-Umgebung weit­ge­hend vom aus­ge­führ­ten MCP-Server getrennt bleibt.

Was bedeutet MCP-Server-Iso­lie­rung via Docker?

Das Model Context Protocol (MCP) er­mög­licht es KI-An­wen­dun­gen, externe Werkzeuge und Da­ten­quel­len über stan­dar­di­sier­te Schnitt­stel­len zu verwenden. Ein MCP-Server kann bei­spiels­wei­se Dateien lesen, Da­ten­ban­ken abfragen, APIs aufrufen oder Befehle über speziell dafür ent­wi­ckel­te Tools ausführen.

Bei einem lokalen MCP-Server kommt häufig der stdio-Transport zum Einsatz. Dabei startet der MCP-Client den Server als lokalen Prozess und kom­mu­ni­ziert über dessen Stan­dard­ein­ga­be und Stan­dard­aus­ga­be mit ihm. Wird ein solcher Server direkt über Node.js, Python oder eine andere Runtime auf dem Host gestartet, läuft er grund­sätz­lich im Kontext des lokalen Be­triebs­sys­tems. Welche Dateien, Netz­werk­zie­le oder Um­ge­bungs­va­ria­blen er tat­säch­lich erreichen kann, hängt dann von den Be­rech­ti­gun­gen des Prozesses und seiner eigenen Im­ple­men­tie­rung ab.

Docker fügt zwischen MCP-Server und Host eine zu­sätz­li­che Iso­la­ti­ons­schicht ein. Der Server läuft mit einem eigenen Da­tei­sys­tem, eigenen Prozess-Na­mens­räu­men und kon­fi­gu­rier­ba­ren Be­rech­ti­gun­gen. Zugriff auf Dateien des Hosts erhält er nur dann, wenn ent­spre­chen­de Ver­zeich­nis­se gezielt ein­ge­bun­den werden. Auch Netz­werk­zu­grif­fe und ver­füg­ba­re Sys­tem­res­sour­cen lassen sich zu­sätz­lich ein­schrän­ken.

Dabei sollte ein Container jedoch nicht als un­ein­ge­schränk­te Si­cher­heits­ga­ran­tie ver­stan­den werden. Besonders Optionen wie --privileged, weit­rei­chen­de Host-Mounts oder das Einbinden des Docker-Sockets können die Schutz­wir­kung erheblich re­du­zie­ren.

IONOS CLOUD AI Model Hub
Erste deutsche, mul­ti­mo­da­le KI-Plattform
  • 100 % DSGVO-konform und sicher in Deutsch­land gehostet
  • Die leis­tungs­stärks­ten KI-Modelle auf einer Plattform
  • Kein Vendor Lock-in durch Open Source

Si­cher­heits­vor­tei­le der Con­tai­ne­ri­sie­rung

Der wich­tigs­te Vorteil besteht darin, dass Sie einem MCP-Server nach dem Prinzip der minimal not­wen­di­gen Rechte nur die Res­sour­cen zur Verfügung stellen können, die er tat­säch­lich benötigt.

✓ Das Da­tei­sys­tem des Hosts bleibt weit­ge­hend getrennt. Nur explizit ein­ge­bun­de­ne Ver­zeich­nis­se werden für den Container sichtbar. Wenn der MCP-Server Dateien lediglich lesen soll, können Sie diese zu­sätz­lich als schreib­ge­schütz­ten Mount einbinden.

✓ Die Rechte des Ser­ver­pro­zes­ses lassen sich re­du­zie­ren. Ein MCP-Server sollte innerhalb des Con­tai­ners nicht als root, sondern als de­di­zier­ter User ohne ad­mi­nis­tra­ti­ve Rechte aus­ge­führt werden.

✓ Netz­werk­zu­grif­fe lassen sich begrenzen. Ein MCP-Server, der aus­schließ­lich mit lokal ein­ge­bun­de­nen Dateien arbeitet, kann bei­spiels­wei­se mit --network=none ohne externen Netz­werk­zu­griff gestartet werden. Benötigt das Tool externe APIs oder Da­ten­ban­ken, muss der not­wen­di­ge Netz­werk­zu­griff ent­spre­chend zu­ge­las­sen werden.

✓ Zu­sätz­li­che Linux-Be­rech­ti­gun­gen können entzogen werden. Optionen wie --cap-drop=ALL und --security-opt no-new-privileges=true re­du­zie­ren Mög­lich­kei­ten zur Pri­vi­le­gi­en­aus­wei­tung weiter. Docker verwendet darüber hinaus stan­dard­mä­ßig ein Seccomp-Profil, das ver­schie­de­ne si­cher­heits­kri­ti­sche Sys­tem­auf­ru­fe blockiert.

✓ Ab­hän­gig­kei­ten bleiben vom Host-System getrennt. Node.js-, Python- oder Sys­tem­bi­blio­the­ken befinden sich im Container-Image und müssen nicht global auf dem Ent­wick­lungs­rech­ner in­stal­liert werden. Un­ter­schied­li­che MCP-Server können dadurch un­ter­schied­li­che Versionen derselben Ab­hän­gig­kei­ten verwenden.

✓ Die Aus­füh­rungs­um­ge­bung wird re­pro­du­zier­ba­rer. Dasselbe Image kann auf un­ter­schied­li­chen Systemen mit einer kom­pa­ti­blen Docker-Umgebung ein­ge­setzt werden. Host-spe­zi­fi­sche Un­ter­schie­de ver­schwin­den dadurch al­ler­dings nicht voll­stän­dig: Ins­be­son­de­re Pfade für Bind-Mounts und einige Platt­form­de­tails müssen weiterhin be­rück­sich­tigt werden.

✓ Third-Party-Tools werden stärker isoliert. Enthält ein fremder MCP-Server feh­ler­haf­ten oder kom­pro­mit­tier­ten Code, begrenzt die Container-Kon­fi­gu­ra­ti­on, auf welche Host-Res­sour­cen dieser zugreifen kann.

Schlankes Do­cker­file für einen MCP-Server erstellen

Für einen Node.js-basierten MCP-Server eignet sich bei­spiels­wei­se ein kleines of­fi­zi­el­les Node-Image wie node:24-alpine. Im Gegensatz zum be­weg­li­chen Tag node:lts-alpine bleibt damit zumindest die Node.js-Major-Version fest­ge­legt. Für voll­stän­dig re­pro­du­zier­ba­re Builds sollte das Basis-Image zu­sätz­lich auf eine konkrete Version oder einen Digest fest­ge­legt werden. Alpine-basierte Images sind besonders kompakt, verwenden al­ler­dings musl statt glibc. Bei nativen Ab­hän­gig­kei­ten kann deshalb eine Debian-basierte Slim-Variante kom­pa­ti­bler sein.

Ein einfaches Do­cker­file kann fol­gen­der­ma­ßen aufgebaut sein:

FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .
ENV NODE_ENV=production
USER node
CMD ["node", "src/index.js"]
do­cker­file

Die Anweisung FROM definiert zunächst das Basis-Image. Mit WORKDIR /app wird an­schlie­ßend das Ar­beits­ver­zeich­nis innerhalb des Con­tai­ners fest­ge­legt.

Danach werden zunächst package.json und die zu­ge­hö­ri­ge Lock-Datei kopiert und die Pro­duk­ti­ons­ab­hän­gig­kei­ten über npm ci --omit=dev in­stal­liert. Erst an­schlie­ßend folgt der ei­gent­li­che Quellcode. Diese Rei­hen­fol­ge er­mög­licht es Docker, bereits erzeugte Build-Layer wie­der­zu­ver­wen­den, solange sich die Ab­hän­gig­kei­ten nicht geändert haben.

Besonders wichtig für die Isolation ist die Zeile USER node. Ohne eine ent­spre­chen­de USER-Anweisung läuft der Haupt­pro­zess eines Con­tai­ners stan­dard­mä­ßig als root. Das of­fi­zi­el­le Node-Image stellt bereits den User node bereit, sodass für dieses Beispiel kein zu­sätz­li­cher Benutzer angelegt werden muss.

Das Image bauen Sie an­schlie­ßend bei­spiels­wei­se mit folgendem Befehl:

docker build -t my-mcp-server:local .
bash

Für pro­duk­ti­ve oder besonders re­pro­du­zier­ba­re Um­ge­bun­gen empfiehlt es sich zu­sätz­lich, Basis-Images kon­trol­liert zu ak­tua­li­sie­ren oder auf einen konkreten Image-Digest fest­zu­le­gen.

Schreib­zu­grif­fe zu­sätz­lich be­schrän­ken

Ein Non-Root-Benutzer ver­hin­dert nicht au­to­ma­tisch sämtliche Schreib­zu­grif­fe innerhalb des Con­tai­ners. Deshalb kann der Container zu­sätz­lich mit einem schreib­ge­schütz­ten Root-Da­tei­sys­tem gestartet werden:

docker run --rm -i --read-only my-mcp-server:local
bash

Falls die Anwendung temporäre Dateien benötigt, kann /tmp separat als flüch­ti­ger Speicher be­reit­ge­stellt werden:

--tmpfs /tmp:rw,nosuid,nodev,noexec,size=64m
bash

Die Daten in einem solchen tmpfs werden nicht dauerhaft ge­spei­chert und ver­schwin­den beim Beenden des Con­tai­ners. Falls der MCP-Server aus­führ­ba­re Dateien in /tmp ablegt oder startet, kann noexec zu Fehlern führen und sollte für diesen An­wen­dungs­fall entfernt werden.

IONOS CLOUD Compute Engine
Die ideale IaaS für Ihre Workloads
  • Kos­ten­güns­ti­ge vCPUs und leis­tungs­star­ke de­di­zier­te Cores
  • Höchste Fle­xi­bi­li­tät ohne Min­dest­ver­trags­lauf­zeit
  • Inklusive 24/7 Experten-Support

MCP-Server über Docker in den MCP-Client einbinden

Bei einem lokalen MCP-Server mit stdio muss der Client nicht mehr un­mit­tel­bar node, python oder eine andere Runtime starten. Statt­des­sen kann er docker run aufrufen. Docker startet daraufhin den iso­lier­ten Container und verbindet dessen Stan­dard­ein­ga­be und Stan­dard­aus­ga­be mit dem MCP-Client.

Bei Claude Desktop werden lokale MCP-Server über das Objekt mcpServers in der Datei claude_desktop_config.json kon­fi­gu­riert. Dies ist von den über die Claude-Ober­flä­che ein­ge­rich­te­ten Remote-MCP-Con­nec­tors zu un­ter­schei­den.

Eine gehärtete Bei­spiel­kon­fi­gu­ra­ti­on kann fol­gen­der­ma­ßen aussehen:

{
    "mcpServers": {
        "isolated-tools": {
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "--read-only",
                "--cap-drop=ALL",
                "--security-opt",
                "no-new-privileges=true",
                "--pids-limit=128",
                "--memory=512m",
                "--cpus=1",
                "--network=none",
                "--tmpfs",
                "/tmp:rw,nosuid,nodev,noexec,size=64m",
                "--mount",
                "type=bind,src=/ABSOLUTER/PFAD/ZUM/PROJEKT,dst=/data,readonly",
                "my-mcp-server:local"
            ]
        }
    }
}
json

Der Platz­hal­ter /ABSOLUTER/PFAD/ZUM/PROJEKT muss durch das Ver­zeich­nis ersetzt werden, auf das der MCP-Server zugreifen darf. Benötigt der Server überhaupt keine Dateien vom Host, sollte auf diesen Mount voll­stän­dig ver­zich­tet werden.

Die wich­tigs­ten Parameter haben dabei folgende Funk­tio­nen:

Docker-Parameter Funktion beim MCP-Betrieb
-i Hält stdin offen und er­mög­licht die MCP-Kom­mu­ni­ka­ti­on über stdio
--rm Entfernt den Container au­to­ma­tisch nach dem Beenden. Nach einem Absturz des MCP-Clients sollten Sie mit docker ps prüfen, ob der Container weiterhin läuft.
--mount … readonly Bindet einen Host-Pfad schreib­ge­schützt in den Container ein
--read-only Macht das Root-Da­tei­sys­tem des Con­tai­ners schreib­ge­schützt
--network=none De­ak­ti­viert den Netz­werk­zu­griff des Con­tai­ners
--cap-drop=ALL Entfernt zu­sätz­li­che Linux-Be­rech­ti­gun­gen
--security-opt no-new-privileges=true Ver­hin­dert das Erlangen zu­sätz­li­cher Pri­vi­le­gi­en
--memory, --cpus, --pids-limit Begrenzen Speicher, CPU und Pro­zess­an­zahl
--tmpfs Stellt tem­po­rä­ren, nicht per­sis­ten­ten Speicher bereit

Nicht jeder MCP-Server benötigt sämtliche Här­tungs­op­tio­nen. Ein Tool für eine Web-API funk­tio­niert bei­spiels­wei­se nicht mit --network=none, während ein Tool, das Dateien be­ar­bei­ten soll, ein gezielt frei­ge­ge­be­nes Read-Write-Ver­zeich­nis benötigt. Ent­schei­dend ist deshalb, Rechte nicht pauschal ein­zu­räu­men, sondern vom tat­säch­li­chen Ein­satz­zweck des Servers ab­zu­lei­ten.

Für stdio-basierte MCP-Server gilt außerdem eine wichtige tech­ni­sche Regel: Die Stan­dard­aus­ga­be stdout dient dem MCP-Protokoll. Zu­sätz­li­che Log­mel­dun­gen sollten daher über stderr aus­ge­ge­ben werden. Bereits eine ge­wöhn­li­che Log­aus­ga­be auf stdout kann den JSON-RPC-Da­ten­strom stören.

Hinweis

Als Al­ter­na­ti­ve zur manuellen Container-Kon­fi­gu­ra­ti­on bietet Docker das MCP Toolkit mit Catalog und MCP Gateway an. Damit lassen sich con­tai­ne­ri­sier­te MCP-Server zentral verwalten und mit MCP-Clients verbinden. Das Toolkit wird in Docker Desktop über die Beta-Funk­tio­nen aktiviert: „Settings“ → „Beta features“ → „Enable Docker MCP Toolkit“. Die aktuelle Docker-Do­ku­men­ta­ti­on be­schreibt die Ober­flä­che ab Docker Desktop 4.62; ältere Versionen können davon abweichen.

Nur not­wen­di­ge Ver­zeich­nis­se freigeben

Bind-Mounts gehören zu den wich­tigs­ten Si­cher­heits­ent­schei­dun­gen bei einem con­tai­ne­ri­sier­ten MCP-Server. Ein Container benötigt bei­spiels­wei­se keinen Zugriff auf das gesamte Home-Ver­zeich­nis, wenn das Tool lediglich mit einem einzelnen Pro­jekt­ord­ner arbeiten soll.

Statt -v /Users/name:/data sollte daher möglichst nur der tat­säch­lich er­for­der­li­che Pfad ein­ge­bun­den werden:

--mount type=bind,src=/Users/name/projekt,dst=/data,readonly
bash

Bind-Mounts besitzen stan­dard­mä­ßig Schreib­zu­griff. Ein kom­pro­mit­tier­ter oder feh­ler­haf­ter MCP-Server könnte dadurch Dateien auf dem Host verändern oder löschen. Wenn Schreib­zu­griff nicht aus­drück­lich benötigt wird, sollte der Mount deshalb mit readonly be­zie­hungs­wei­se ro versehen werden. Unter Linux gilt die Schreib­schutz­wir­kung für ent­hal­te­ne Unter-Mounts erst ab Kernel 5.12 rekursiv.

Vermieden werden sollte das Einbinden von /var/run/docker.sock, sofern der MCP-Server nicht aus­drück­lich den Docker-Daemon verwalten muss. Zugriff auf diesen Socket erlaubt einem Container weit­rei­chen­de Kontrolle über Docker und kann die zuvor auf­ge­bau­te Isolation praktisch aushebeln. Auch ein schreib­ge­schütz­ter Socket-Mount beseitigt dieses Risiko nicht.

Grenzen der Container-Iso­lie­rung

Auch ein ge­här­te­ter Docker-Container bietet keine voll­stän­di­ge Trennung vom Host. Si­cher­heits­lü­cken in Container-Runtime oder Docker können grund­sätz­lich Container-Escapes er­mög­li­chen, weshalb Docker und die ver­wen­de­ten Images re­gel­mä­ßig ak­tua­li­siert werden sollten. Zu­sätz­li­chen Schutz können bei­spiels­wei­se Rootless Docker mit der Docker Engine unter Linux oder Docker Desktops Enhanced Container Isolation (ECI, nur mit Docker-Business-Abo) bieten. Zu­gangs­da­ten und API-Keys sollten außerdem möglichst nicht unnötig als Um­ge­bungs­va­ria­blen übergeben werden, sondern über geeignete Secret-Me­cha­nis­men be­reit­ge­stellt werden.

Fazit

Docker eignet sich gut, um lokale MCP-Server von der ei­gent­li­chen Ent­wick­lungs­um­ge­bung zu trennen. Laufzeit, Bi­blio­the­ken und weitere Ab­hän­gig­kei­ten befinden sich im Container, während Datei-, Netzwerk- und Sys­tem­zu­grif­fe gezielt ein­ge­schränkt werden können. Dadurch lassen sich MCP-Tools re­pro­du­zier­ba­rer und mit deutlich kleineren Be­rech­ti­gun­gen betreiben als bei einer un­ein­ge­schränk­ten lokalen Aus­füh­rung.

Ent­schei­dend ist die konkrete Container-Kon­fi­gu­ra­ti­on. Ein Non-Root-Benutzer, möglichst kleine Images, re­strik­ti­ve und vor­zugs­wei­se schreib­ge­schütz­te Mounts, begrenzte Res­sour­cen und der Verzicht auf unnötige Netzwerk- oder Docker-Daemon-Zugriffe bilden zusammen eine sinnvolle Grundlage.

Zum Hauptmenü