← Kembali ke Blog

Docker MCP Gateway: Jalankan MCP Server di Container Terisolasi

Docker MCP Gateway: jalankan MCP server di container terisolasi

Coba lihat config MCP milik orang yang pakai Claude Desktop, Cursor, dan VS Code barengan. Empat server yang sama ditulis tiga kali. Semuanya dijalankan lewat npx, semuanya baca API key dari file JSON tanpa enkripsi, dan semuanya jalan sebagai child process dengan akses filesystem yang sama persis dengan editor yang melahirkannya. Mau ganti versi server? Edit tiga file. Mau rotate key? Ulang edit yang sama.

Docker MCP Gateway memindahkan semua itu ke dalam Docker. Server jadi OCI image, tiap server jalan di container sendiri dengan batas CPU dan memory, secret diambil dari keychain OS, dan semua client di mesin kamu ngobrol dengan satu proses gateway, bukan N server.

Yang perlu disiapkan

  • Docker Desktop 4.62 atau lebih baru untuk perintah CLI docker mcp, atau Docker Engine dengan satu langkah tambahan (Step 1 di bawah)
  • Docker engine yang jalan
  • Client MCP: Claude Desktop, VS Code, Cursor, atau apa pun yang bisa stdio atau Streamable HTTP
  • Nggak butuh Node.js. Justru itu salah satu alasannya.

Step 1: siapkan CLI plugin

Cek dulu yang ada di mesin kamu:

docker mcp version

Kalau jawabannya "docker: 'mcp' is not a docker command", berarti Docker Desktop kamu di bawah 4.62 atau kamu pakai Docker Engine polos. Di Engine, gateway dikirim sebagai binary terpisah yang dibaca Docker sebagai CLI plugin:

# download binary rilis terbaru dari github.com/docker/mcp-gateway/releases
chmod +x docker-mcp
mkdir -p ~/.docker/cli-plugins
mv docker-mcp ~/.docker/cli-plugins/docker-mcp
docker mcp version

Path-nya sama untuk Linux dan macOS. Di Windows plugin-nya ada di %USERPROFILE%\.docker\cli-plugins.

Step 2: lihat isi katalog

Gateway mengambil definisi server dari katalog OCI. Cek isi katalog resminya:

docker mcp catalog server ls mcp/docker-mcp-catalog

Tiap baris keluaran kasih nama server seperti playwright atau github-official. Nama itu yang dipakai sebagai server ID di langkah berikutnya. Di Docker Desktop, nilai yang sama ada di MCP Toolkit > Catalog > Server ID.

Step 3: bikin profile dan tambahkan server

Profile adalah kumpulan server beserta config-nya. Inilah yang dimuat gateway saat start, dan ini juga yang bikin "tools buat kerjaan web-dev" jadi sesuatu yang bisa dinyalakan sekali perintah.

docker mcp profile create --name web-dev

docker mcp profile server add web-dev \
  --server catalog://mcp/docker-mcp-catalog/github-official \
  --server catalog://mcp/docker-mcp-catalog/playwright

Referensi server bisa nunjuk ke empat jenis sumber:

Bentuk URI Sumber
catalog://<catalog>/<server-id> Katalog OCI, kasus yang paling umum
docker://<image>:<tag> Image Docker apa pun
https://<registry>/v0/servers/<id> Registry komunitas MCP
file://<path> Definisi lokal dalam YAML atau JSON

Bentuk file itulah cara membungkus server yang belum dipublikasikan siapa pun. Minimal butuh nama, image, dan deskripsi:

name: my-server
title: My Server
type: server
image: myimage:latest
description: Description of the server
docker mcp profile server add web-dev --server file://./my-server.yaml
docker mcp profile show web-dev

Step 4: pasang config dan secret

Server yang butuh token atau endpoint diatur lewat config profile:

docker mcp profile config web-dev --set github-official.personal_access_token=<token>
docker mcp profile config web-dev --get-all

Perhatikan di mana nilai itu mendarat. Untuk apa pun yang sensitif, pakai secret store, yang menyimpan nilainya di keychain OS dan bukan di file profile:

docker mcp secret --help

Server yang butuh OAuth (contohnya server resmi GitHub) diotorisasi di Docker Desktop setelah ditambahkan, di bagian MCP Toolkit. Langkah consent ini nggak ada promptnya di terminal.

Step 5: jalankan gateway

Untuk satu client lokal, stdio sudah cukup. Client yang menjalankan gateway, lalu gateway yang menyalakan container server saat dibutuhkan:

docker mcp gateway run --profile web-dev

Dari situ pertanyaan soal lifecycle server terjawab: nggak ada yang start sampai ada tool call masuk. Gateway mengenali server mana yang punya tool itu, menyalakan container-nya, menyuntikkan credential, lalu meneruskan request. Lihat prosesnya dari terminal kedua:

docker ps

Kalau ada beberapa client sekaligus, atau kamu butuh satu endpoint yang hidup lama di mesin headless, pindah ke transport jaringan:

docker mcp gateway run --profile web-dev --port 8080 --transport streaming

--transport menerima stdio, sse, atau streaming. Tanpa --port, gateway tetap di stdio.

Flag yang berguna begitu basic-nya jalan:

  • --servers server1,server2 dengan --tools server1:* --tools server2:tool2 membatasi daftar tool ke allowlist tertentu. Tool lebih sedikit berarti deskripsi lebih sedikit di context model.
  • --secrets=docker-desktop:./.env menambah sumber secret cadangan setelah keychain.
  • --verbose --log-calls mencetak trace pemanggilan, ini yang kamu butuh saat tool call balik dengan hasil nggak berguna.
  • --dry-run menyalakan gateway tanpa mendengarkan koneksi, jadi kamu bisa validasi profile sebelum disambungkan ke client.
  • --watch memuat ulang config saat file berubah, praktis waktu sedang iterasi profile.

Dua default keamanan sudah aktif: --block-secrets mencegah secret terkirim ke tool, dan --verify-signatures memeriksa tanda tangan image. Batas container default 1 CPU dan 2 GB per server, keduanya bisa diubah lewat --cpus dan --memory.

Step 6: arahkan client ke gateway

Claude Desktop baca claude_desktop_config.json. Satu entri menggantikan semua server yang tadinya ada di situ:

{
  "mcpServers": {
    "MCP_DOCKER": {
      "command": "docker",
      "args": ["mcp", "gateway", "run", "--profile", "web-dev"]
    }
  }
}

Untuk client yang sudah dikenal Docker, biar CLI yang menulis file-nya:

docker mcp client connect vscode --profile web-dev

Perintah itu bikin .vscode/mcp.json di direktori saat ini, yang sifatnya spesifik per user:

echo ".vscode/mcp.json" >> .gitignore

Step 7: jalan tanpa Docker Desktop

Di server atau di CI biasanya nggak ada Desktop sama sekali. Gateway juga tersedia sebagai image container:

services:
  gateway:
    image: docker/mcp-gateway
    command:
      - --servers=duckduckgo
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
docker compose up

Perhatikan apa yang diberikan mount itu. Unix socket setara akses root di host, jadi gateway bisa menyalakan container lain. Jalankan ini di mesin yang kamu kuasai, bukan di shared runner milik orang lain.

Kapan pakai, kapan nggak

Setup Isolasi Titik config Cocok kalau
Server via npx di config tiap client Nggak ada, user-nya sama dengan editor Satu per client Satu client, dua server, masih coba-coba
Docker MCP Gateway Satu container per server, batas CPU dan memory, secret di keychain Satu Beberapa client, beberapa server, ada server yang bukan buatanmu
Remote MCP server hosted dengan OAuth Jalan di sisi vendor Satu per client plus flow consent Integrasi yang dikelola vendor, nggak mau runtime lokal

Tradeoff jujurnya: gateway menambah satu dependensi (Docker) dan satu langkah build untuk apa pun yang belum ada di katalog. Kalau kamu cuma pakai satu MCP server di satu client, config stdio biasa lebih ringan dan sebaiknya dipertahankan.

Troubleshooting

  • docker: 'mcp' is not a docker command: Docker Desktop di bawah 4.62, atau binary plugin nggak ada di ~/.docker/cli-plugins. Cek docker info untuk melihat direktori plugin yang benar-benar dibaca Docker.
  • Gateway jalan tapi container server nggak muncul: bukan masalah. Container dibuat saat tool call pertama. Pastikan dengan docker mcp gateway run --verbose plus prompt nyata.
  • Model mengabaikan tool-mu: kemungkinan gateway mengekspos lebih banyak dari yang perlu. Pakai --tools untuk memangkas daftarnya sesuai tugas.
  • Server nggak bisa akses API-nya: cek nilai config di profile dulu, baru default --block-network dan --block-secrets.
  • Client nunjukin nol tool: jalankan docker mcp profile show web-dev dan pastikan server-nya memang terpasang di profile yang kamu kirim lewat --profile.

Langkah lanjut

Tambahkan allowlist --tools ke profile yang paling sering kamu pakai, lalu bandingkan berapa definisi tool yang dikirim client sebelum dan sesudahnya. Kalau yang kamu butuh kontrol akses per user di server remote, itu masalah berbeda: urusannya ada di layer OAuth spesifikasi MCP, bukan di gateway.

Butuh Bantuan Implementasi?

Saya membantu tim mendesain dan membangun infrastruktur cloud scalable, pipeline DevOps, dan sistem production-grade.

Konsultasi Gratis