OpenCode's TOML-based config and terminal-first TUI make it a natural fit for Docker work — you're usually already in a terminal next to your Docker daemon, and OpenCode's scrollable output pane handles long docker inspect payloads and build logs better than a chat bubble would. This topic covers connecting mcp-server-docker to OpenCode, running image/container/Compose workflows from the TUI, a full crash-loop investigation, and the integration's current rough edges.
Installing and Connecting Docker MCP to OpenCode
Prerequisites
curl -fsSL https://opencode.ai/install | bash
npm install -g opencode-ai
- Docker Engine running, with your user in the
dockergroup (or an equivalent rootless setup) uvinstalled foruvx mcp-server-docker
Global config
OpenCode reads MCP server definitions from ~/.config/opencode/config.toml:
[mcp.docker]
type = "local"
command = ["uvx", "mcp-server-docker"]
If you run against a non-default Docker context, pass it through explicitly rather than relying on ambient shell state, since OpenCode may launch the MCP process with a different environment than your interactive shell:
[mcp.docker]
type = "local"
command = ["uvx", "mcp-server-docker"]
[mcp.docker.environment]
DOCKER_HOST = "unix:///var/run/docker.sock"
Project-level config
For teams with a per-repo Docker setup (a specific Compose file, a non-standard socket path in a devcontainer), commit a project-level .opencode/config.toml:
[mcp.docker]
type = "local"
command = ["uvx", "mcp-server-docker"]
[mcp.docker.environment]
DOCKER_HOST = "unix:///var/run/docker.sock"
COMPOSE_FILE = "./docker/docker-compose.yml"
This is safe to commit — there's no credential in it, since Docker socket access is an OS-level permission, not an API key. That's a meaningful difference from most other MCP integrations in this course, and worth calling out to your team the first time someone asks "wait, is this token committed?"
Verify the connection
opencode
List your available Docker tools, then list all running containers.
Tips
- Restart OpenCode after editingconfig.toml— the TOML config is read at startup, not hot-reloaded.
- IfDOCKER_HOSTisn't set anywhere,mcp-server-dockerfalls back to the default socket path for your OS — that's usually fine for solo local dev, but be explicit once more than one Docker context exists on the machine.
- Commit the project-level config so teammates get a working Docker MCP connection without repeating setup steps.
Managing Images, Containers, and Compose Stacks from OpenCode
Once connected, day-to-day container management moves from separate docker CLI invocations into a single conversational session, with OpenCode's TUI rendering the (often large) JSON responses in a scrollable pane.
Image management:
List all local images, sorted by size descending. Flag any over 500MB.
Pull postgres:16-alpine and confirm the digest matches what's currently
referenced in docker-compose.yml.
Container lifecycle:
List all containers, including stopped ones. For any that exited with a
non-zero code, show the exit code and the last 20 log lines.
Restart the "worker" container and confirm it reaches a running state
within 10 seconds.
Compose stack operations:
Bring up the stack defined in docker-compose.yml in detached mode, then
run compose_ps and confirm all services report "running" or "healthy".
Tail the last 50 lines of logs for the "db" service in the compose
stack, then bring the whole stack down.
A representative compose_ps-style response the agent reasons over:
NAME IMAGE STATUS PORTS
myapp-api-1 myapp-api:dev Up 2 minutes (healthy) 0.0.0.0:3000->3000/tcp
myapp-db-1 postgres:16-alpine Up 2 minutes (healthy) 5432/tcp
myapp-worker-1 myapp-worker:dev Restarting (1) 3s ago
That output alone — one service in a restart loop while its peers are healthy — is usually enough for the agent to propose the next diagnostic step without you having to spell it out:
The worker service is restarting. Fetch its logs and cross-reference
its environment variables against what api and db are getting — is it
missing something they have?
OpenCode's TUI pagination (Page Up/Page Down, Ctrl+L to clear) is genuinely useful here — a compose_logs call across three services can run to hundreds of lines, and being able to scroll rather than lose the top of the output to terminal scrollback limits matters for multi-service debugging.
Tips
- Ask for compose service status as a table before diving into any single service's logs — it gives you the "which service is actually broken" answer in one call instead of guessing.
- When comparing environment variables across services, ask explicitly for a diff-style answer ("what does api have that worker doesn't") rather than two separate dumps — it's faster to read and the model does the comparison work for you.
- Use/in the OpenCode TUI to enter a new prompt without losing the current session's tool-call history — chaining "now check the network for that same container" works because context carries over.
Practical Example: Debugging a Crash-Looping Container in OpenCode
Scenario: docker compose up brings up api, db, and worker. The worker service restarts continuously. Here's a full session from symptom to fix.
Step 1: Confirm the loop and get its shape.
Inspect the "worker" container. Show me its restart count, exit code,
and the interval between its last two restarts.
Expected agent-reasoned output:
- Exit code: 1
- Restart count: 14
- Interval between restarts: ~4 seconds — consistent with a crash during startup, not a slow degradation.
Step 2: Pull the actual crash log.
Fetch the last 40 log lines for "worker".
Error: connect ECONNREFUSED 172.19.0.2:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16)
at process.exit (worker.js:9:1)
Step 3: Rule out the obvious cause — is the dependency actually up yet?
Inspect the "db" container. What's its health status, and when did it
last transition to "healthy"?
The db container reports "Health": { "Status": "healthy", "Log": [...] } with a healthy transition roughly 6 seconds after worker first attempted to connect — meaning the real problem isn't that Postgres never comes up, it's that worker doesn't wait for it.
Step 4: Check the compose file for a missing dependency condition.
Read docker-compose.yml. Does the worker service have a depends_on
entry for db, and does it use a health-based condition?
services:
worker:
build: ./worker
depends_on:
- db
A plain depends_on: [db] only waits for the container to start, not for Postgres inside it to accept connections — a very common Compose misunderstanding.
Step 5: Apply and verify the fix.
services:
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 3s
timeout: 3s
retries: 5
worker:
build: ./worker
depends_on:
db:
condition: service_healthy
Update docker-compose.yml with a healthcheck on db and a
service_healthy condition on worker's depends_on. Bring the stack down
and back up, then confirm worker no longer restarts.
myapp-worker-1 myapp-worker:dev Up 8 seconds (healthy)
Step 6: Close the loop.
Summarize the root cause and the fix in three sentences, suitable for a
PR description.
Tips
- Always get the restart interval, not just the restart count — a tight loop (seconds apart) points to a startup-time failure, while a loop with minutes between restarts often points to something more like a memory leak triggering periodic OOM kills.
-depends_onwithout a health condition is one of the most common root causes of exactly this failure pattern — worth checking early rather than last.
- Ask the agent to verify the fix by actually bringing the stack down and back up, not just editing the YAML — a plausible-looking fix that wasn't re-tested is not a confirmed fix.
Known Limitations for Docker MCP in OpenCode
No live log streaming inside a single tool call. fetch_container_logs returns a snapshot at call time. For a container producing output slowly, OpenCode has to poll — ask the agent to "check again in a moment" — rather than watching output arrive the way docker logs -f would in a terminal.
Compose file discovery isn't always automatic. If your Compose file isn't named docker-compose.yml/compose.yaml at the project root, or you use an override file (docker-compose.override.yml), you often need to state the path explicitly in the prompt or set COMPOSE_FILE in the server's environment block — the agent won't reliably discover a nonstandard layout on its own.
[mcp.docker.environment]
COMPOSE_FILE = "./infra/docker-compose.yml:./infra/docker-compose.override.yml"
No built-in image vulnerability scanning. Unlike Docker Desktop's own Scout integration, mcp-server-docker doesn't expose a scan_image tool. If you need CVE data as part of an AI-assisted workflow, run docker scout cves separately and paste the summary into the prompt, or shell out to it via OpenCode's general command-execution capability rather than expecting a dedicated MCP tool.
docker scout cves myapp:dev --only-severity critical,high
Rate of context growth with large builds. A verbose multi-stage build log easily runs past a thousand lines. OpenCode's context window handles this better than a chat UI, but very long build sessions still benefit from asking the agent to summarize and discard raw output between steps rather than keeping every build attempt's full log in context.
Version sensitivity. mcp-server-docker's tool schemas have changed across releases (notably around how inspect_container structures nested fields). If prompts that used to work start returning schema-mismatch errors, check uvx mcp-server-docker --version against the project's pinned version before assuming it's a prompt problem.
uvx mcp-server-docker --version
uv tool upgrade mcp-server-docker
Tips
- For anything needing real-time log tailing, keep a plaindocker compose logs -frunning in a second terminal pane alongside your OpenCode session rather than fighting the snapshot model.
- Pinmcp-server-dockerto a known-good version in shared project configs (uvx mcp-server-docker==<version>) so a teammate's fresh install doesn't silently pick up a schema change mid-project.
- Pair Docker MCP with a scheduleddocker scout cvesin CI rather than expecting the AI session to catch vulnerabilities — it currently can't see that data unless you hand it over manually.
Tips
Tips
- SetDOCKER_HOSTandCOMPOSE_FILEexplicitly in OpenCode's config rather than relying on inherited shell environment — the MCP subprocess doesn't always see the same environment your interactive terminal does.
- Use the restart-count-plus-interval pattern from the crash-loop example as your default first move on any "container keeps dying" report — it takes one tool call and immediately tells you whether you're looking at a startup failure or a slow degradation.
- Keep a terminal-nativedocker compose logs -fhandy for real-time tailing; treat OpenCode's Docker MCP session as the analysis layer on top of snapshots, not a replacement for live log watching.