每日 MCP Server

Docker MCP Server:让 Agent 直接管理容器生命周期

2026-09-09
开发仓库
支持客户端:
Claude CodeCursorVS CodeTrae
MCPDocker容器DevOps镜像管理

简介

Agent 想帮你调试容器化应用,却只能隔着终端看你敲 docker 命令?Docker MCP Server 打开了直连通道——让 Claude Code、Cursor、VS Code 中的 Agent 能够直接列出容器、查看日志、启动/停止/重启容器、构建镜像、管理网络和卷。本文介绍 Docker MCP 的核心能力(容器/镜像/网络/卷操作)、在各客户端中的配置方式、三个实战场景(容器故障自动排查 / 镜像构建优化 / 多容器环境编排),以及与 Kubernetes MCP 的选型对比和安全注意事项。

安装命令

npx -y @modelcontextprotocol/server-docker

为什么 Agent 需要直连 Docker

如果你在做任何容器化应用——微服务、CI/CD 流水线、本地开发环境——Docker 几乎一定是你的日常工具。它是镜像构建器、是运行时隔离层、是依赖编排器、是部署交付物——一台 Docker 主机上往往跑着十几个甚至几十个相互关联的容器。但讽刺的是,当你想让 AI Agent 帮你看看某个容器为什么挂了、为什么镜像这么大、为什么服务连不上时,对话会变成这样:

你:API 容器起不来了,帮我看看为什么

Agent:我没法直接连 Docker,你帮我跑几条命令吧:
      1. docker ps -a | grep api
      2. docker logs <容器ID> --tail 200
      3. docker inspect <容器ID>
      把输出贴给我

你:(切到终端,手敲 5 条命令,复制输出,粘回对话)

Agent:好的,我看到了……(你来回切了 3 次窗口)

这就是 Docker 与 Agent 之间那道看不见的墙——Agent 能读代码、能查日志文件,却偏偏摸不到那台最关键的 Docker 守护进程。在 MCP 出现之前,绕过这道墙只有两种办法,而且都很别扭:

办法 A:手写脚本当中介
  你:写一个 shell 脚本,跑 docker ps + docker logs
  Agent:(写脚本)→ 你跑 → 你贴输出 → Agent 分析
  痛点:每个问题都要写一次脚本,本质还是"你在驱动"

办法 B:让 Agent 跑 Bash MCP
  你:让 Agent 通过 Bash MCP 直接敲 docker 命令
  Agent:(通过 Bash MCP 跑 docker ps)
  痛点:输出是纯文本,容器 ID、状态、镜像名混在一行;
        Agent 难结构化解析;而且 Bash 权限太大,
        rm -rf / 之类的高危命令它能直接跑,生产机不敢给

这两种方式都有同一个问题:Agent 跟 Docker 之间隔了一层"命令行文本",它不知道哪些是容器 ID、哪些是状态、哪些是端口映射,分析时容易把噪声当数据。更要命的是,Bash MCP 给的是"任意 shell 命令"权限——这对生产 Docker 主机来说是不可接受的风险敞口。

Docker MCP Server 把这层壳彻底打掉。它不是一个"帮你跑 docker 命令"的 wrapper,而是一个原生理解 Docker API的 MCP Server——Agent 调用的是"列出所有容器"、"看这个容器的日志"、"重启这个容器"这种语义化工具,而不是"跑一条 docker ps 再解析输出"。区别看起来微妙,实际体验天差地别:

没有 Docker MCP(Bash 方式):
  Agent → docker ps -a
        → 拿到 "CONTAINER ID  IMAGE  COMMAND  STATUS  PORTS  NAMES" 这种表头文本
        → 自己切列、自己猜哪个是状态、哪个是端口
        → 容器多了就乱

有了 Docker MCP:
  Agent → 调用 list_containers 工具
        → 拿到结构化 JSON:
          [
            {"id":"a1b2c3","name":"api","image":"api:v1",
             "status":"running","ports":["8080:8080"]},
            ...
          ]
        → 直接当对象分析

这道直连通道打通后,下面这些真实痛点全都能在对话里解决:

痛点 1:容器跑着跑着挂了,要进服务器看日志
  → 容器在 K8s 之外单机 Docker 里跑(开发/测试/小规模生产)
  → 出问题要 SSH 上去 docker logs、docker inspect
  → 现在让 Agent 直接读日志、看状态、重启验证,全程不离开对话框

痛点 2:镜像越来越大,构建越来越慢
  → 一个 Node 应用镜像从 200MB 涨到 1.2GB
  → 不知道哪些层冗余、哪个基础镜像太重
  → 让 Agent 分析 Dockerfile、查看镜像分层、给出优化方案

痛点 3:多容器本地环境起不来,依赖一团乱
  → docker-compose up 报错"network not found"
  → 你不知道哪个容器没起来、哪个端口被占
  → 让 Agent 列容器、查网络、定位冲突、修复 compose 文件

Docker MCP 的设计哲学跟其他运维类 MCP 一脉相承:把"操作 Docker"变成 Agent 的原生能力,而不是让它通过 shell 间接摸。这样 Agent 才能真正看懂容器的状态、镜像的分层、网络的拓扑,做出结构化分析、给出可执行的修复建议。本文接下来从核心能力、配置方式、三个实战场景、与 Kubernetes MCP 的选型对比、安全注意事项、故障排查六个维度把它讲透。

Docker MCP 核心能力

Docker MCP 把 Docker 守护进程的几大对象(容器 Container、镜像 Image、网络 Network、卷 Volume、Compose 项目、系统 System)都封装成了语义化的 MCP 工具。Agent 不用记命令语法,只要说"我要看所有容器的状态",MCP 自然路由到对应工具。下表是完整能力清单:

容器管理

容器是 Docker 最核心的对象,所有运行时操作都在这里。覆盖查看、生命周期控制、日志、执行命令等高频操作:

工具名功能对应 Docker 命令返回格式
list_containers列出所有容器(含已停止)docker ps -a容器对象数组(含 ID/名称/状态/端口)
get_container查看单个容器详情docker inspect <ID>容器配置 JSON(含挂载/环境变量/网络)
get_container_logs拉取容器日志docker logs <ID>日志字符串(支持 tail/since 参数)
start_container启动已停止的容器docker start <ID>容器 ID 或名称
stop_container停止运行中的容器docker stop <ID>容器 ID 或名称
restart_container重启容器docker restart <ID>容器 ID 或名称
remove_container删除容器(需先停止)docker rm <ID>删除的容器 ID
exec_in_container在容器内执行命令docker exec <ID> <cmd>命令输出(stdout/stderr)
run_container创建并启动新容器docker run <image>容器对象(含 ID/状态)
get_container_stats查看容器实时资源占用docker stats <ID> --no-streamCPU/内存/网络/IO 指标
list_processes查看容器内进程docker top <ID>进程列表

容器管理是日常用得最多的工具集合。一个典型场景——排查异常容器:

Agent 想知道某个 API 容器为什么 502
  → list_containers() 找到 api 容器,状态 "exited (137) 2 minutes ago"
  → get_container_logs("api", tail=200) 拿到日志
  → 看到错误 "OOMKilled" → 内存超限
  → get_container("api") 看到内存限制 512m
  → 建议:调大内存限制到 1g,重启验证

镜像管理

镜像层是 Docker 部署交付物,覆盖构建、拉取、推送、清理等操作:

工具名功能对应 Docker 命令返回格式
list_images列出本地所有镜像docker images镜像对象数组(含仓库名/标签/大小)
build_image从 Dockerfile 构建镜像docker build -t <tag> <path>构建日志 + 镜像 ID
pull_image从仓库拉取镜像docker pull <image>:<tag>拉取进度 + 镜像 ID
push_image推送镜像到仓库docker push <tag>推送进度 + 摘要
remove_image删除本地镜像docker rmi <ID>删除的镜像 ID
inspect_image查看镜像详情(分层/历史)docker inspect <image>镜像元数据 JSON
image_history查看镜像构建历史(每层命令)docker history <image>分层数组(含命令/大小/创建时间)
tag_image给镜像打标签docker tag <src> <dst>标签字符串
prune_images清理未使用的镜像docker image prune -a释放空间字节数

镜像工具的杀手锏是 image_history——它能让 Agent 看到镜像每一层是怎么构建的,每层多大,从而定位冗余层:

image_history("api:v1")
  → [
    {"created_by":"/bin/sh -c npm install", "size":"320MB"},
    {"created_by":"/bin/sh -c npm run build", "size":"85MB"},
    {"created_by":"/bin/sh -c apt-get install curl", "size":"45MB"},
    {"created_by":"COPY . .", "size":"12MB"},
    ...
  ]
  → Agent 看到第一层 npm install 占了 320MB
  → 怀疑 node_modules 没排除,或没多阶段构建

网络管理

容器互联依赖 Docker 网络,常见故障都跟网络配置错配有关:

工具名功能对应 Docker 命令返回格式
list_networks列出所有 Docker 网络docker network ls网络对象数组
create_network创建自定义网络docker network create <name>网络 ID
remove_network删除网络docker network rm <name>网络名
inspect_network查看网络详情(哪些容器接入)docker network inspect <name>网络 JSON(含容器列表/子网)
connect_container把容器接入网络docker network connect <net> <c>成功标识
disconnect_container把容器从网络移除docker network disconnect <net> <c>成功标识
prune_networks清理未使用网络docker network prune释放数量

inspect_network 是排查"容器间连不通"的核心工具:

inspect_network("app-net")
  → {
    "name":"app-net",
    "driver":"bridge",
    "subnet":"172.20.0.0/16",
    "containers":{
      "a1b2c3":{"name":"db","ipv4":"172.20.0.2"},
      "d4e5f6":{"name":"api","ipv4":"172.20.0.3"}
    }
  }
  → Agent 立刻知道 db 和 api 都在 app-net 里,能通过容器名互访

卷管理

数据持久化全靠卷。卷挂载错误会导致容器启动失败或数据丢失:

工具名功能对应 Docker 命令返回格式
list_volumes列出所有卷docker volume ls卷对象数组
create_volume创建命名卷docker volume create <name>卷名
remove_volume删除卷docker volume rm <name>卷名
inspect_volume查看卷详情(挂载点/驱动)docker volume inspect <name>卷 JSON(含真实路径)
prune_volumes清理未使用卷docker volume prune释放空间字节数

排查"数据库容器重启后数据没了"的典型用法:

inspect_volume("pgdata")
  → {
    "name":"pgdata",
    "mountpoint":"/var/lib/docker/volumes/pgdata/_data",
    "driver":"local"
  }
  → 路径正确,卷确实存在
  → 再 get_container("pg") 看挂载
  → 发现挂的是 /var/lib/postgresql/data 但容器里这个目录权限是 root
  → 建议加 --user 参数或修改 PGDATA 路径

Compose 操作

多容器应用通常用 docker-compose 编排。Docker MCP 暴露了 compose 子集,让 Agent 能直接管一个项目:

工具名功能对应 Docker 命令返回格式
compose_up启动 compose 项目(拉镜像/建网/起容器)docker compose up -d服务状态数组
compose_down停止并清理 compose 项目docker compose down清理摘要
compose_ps查看 compose 项目内容器状态docker compose ps服务对象数组
compose_logs拉 compose 项目内服务日志docker compose logs <svc>日志字符串
compose_build构建 compose 项目内镜像docker compose build构建日志
compose_pull拉取 compose 项目所需镜像docker compose pull拉取进度

compose 工具是"一键起本地开发环境"的利器:

compose_up({ project: "myapp", detach: true })
  → [
    {"service":"db","status":"running","ports":["5432:5432"]},
    {"service":"api","status":"running","ports":["8080:8080"]},
    {"service":"web","status":"running","ports":["3000:3000"]}
  ]
  → Agent 知道三个服务都起来了,端口也都对得上

系统级操作

了解 Docker 主机整体状态、监控事件流:

工具名功能对应 Docker 命令返回格式
system_info查看 Docker 守护进程信息(版本/存储驱动/容器数)docker info信息 JSON
system_df查看磁盘占用(镜像/容器/卷大小)docker system df各类对象大小汇总
system_events订阅 Docker 事件流(短时窗口)docker events --since 5m事件数组
prune_system一键清理所有未用对象docker system prune -a释放空间字节数
version查看 Docker 版本docker version客户端/服务端版本信息

system_df 是排查"Docker 主机磁盘满了"的第一步:

system_df()
  → {
    "images":{"count":48,"size":"12.5GB","reclaimable":"8.2GB"},
    "containers":{"count":23,"size":"450MB","reclaimable":"120MB"},
    "volumes":{"count":15,"size":"3.2GB","reclaimable":"1.8GB"}
  }
  → Agent 立刻知道有 8.2GB 未用镜像可清理
  → 建议 prune_images 释放

一图速查:六大类 × 典型场景

我要做什么?                              用哪类工具?
─────────────────────────────────────────────────────
看容器跑没跑、查容器日志、重启容器         → 容器管理
分析镜像大小、构建镜像、清理冗余镜像        → 镜像管理
排查容器间连不通、创建专用网络             → 网络管理
查卷挂载对不对、卷丢了                     → 卷管理
一键起/停多容器项目                        → Compose
看 Docker 主机整体状态、清磁盘             → 系统

Agent 拿到一个需求时,会先通过 list_containers 或 system_info 看整体,再路由到对应对象类型的工具——这是 Docker MCP 比直接跑 docker 命令显著更聪明的地方:它知道容器、镜像、网络是不同对象,不会拿 docker images 去查容器然后报错。

各客户端配置示例

Docker MCP 的安装跟其他官方 MCP Server 一样,一行 npx 搞定,不需要 clone、不需要编译。但 Docker 涉及本地 socket 权限和潜在的高危操作,配置时多几个注意点。下面逐个给出完整可用配置。

Claude Code(claude_desktop_config.json)

Claude Code 的 MCP 配置文件位置:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json

最简配置(连本地 Docker socket):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

默认连的是 /var/run/docker.sock(Linux/Mac)或 //./pipe/docker_engine(Windows)。如果 Docker 装在标准位置,零参数就够。

连远程 Docker 主机的配置:

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://10.0.0.5:2375"
      ]
    }
  }
}

带 TLS 的远程 Docker(生产推荐):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://docker-prod.internal:2376",
        "--tlsverify",
        "--tlscacert", "/etc/docker/ca.pem",
        "--tlscert", "/etc/docker/cert.pem",
        "--tlskey", "/etc/docker/key.pem"
      ]
    }
  }
}

生产环境绝对不要用裸 tcp:// 不带 TLS——Docker API 等同于 root 权限,明文传输等于把整个主机交给网络上的任何人。

如果你已经有其他 MCP Server(比如 filesystem、github),合并进去:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
    },
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
      }
    }
  }
}

注意:修改配置文件后必须完全退出 Claude Code(不是关窗,是 Dock 右键退出 / Windows 任务栏退出),重新打开才生效。

Cursor(.cursor/mcp.json)

Cursor 把 MCP 配置放在项目根目录或用户目录的 .cursor/mcp.json:

  • 项目级:<项目根>/.cursor/mcp.json(只对该项目生效)
  • 用户级:~/.cursor/mcp.json(全局生效)

最简配置:

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

想让 docker 在所有项目都可用,放用户级;想只对某个项目可用,放项目级。两者同名时项目级覆盖用户级。

连远程 Docker(带环境变量做权限隔离):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://docker-staging.internal:2376",
        "--tlsverify"
      ],
      "env": {
        "DOCKER_CERT_PATH": "/Users/me/.docker/staging-certs"
      }
    }
  }
}

通过 DOCKER_CERT_PATH 环境变量指定 TLS 证书目录(目录里放 ca.pem、cert.pem、key.pem),比在 args 里写绝对路径更可移植,团队共享配置时换路径只改 env。

VS Code(settings.json)

VS Code 通过 GitHub Copilot Chat 或 Continue 等扩展支持 MCP。配置写在 settings.json:

  • macOS:~/Library/Application Support/Code/User/settings.json
  • Windows:%APPDATA%\Code\User\settings.json
  • Linux:~/.config/Code/User/settings.json

完整配置:

{
  "mcp.servers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

如果你用 Continue 扩展,配置在 ~/.continue/config.json:

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

VS Code 多工作区隔离场景(不同项目连不同 Docker 主机):

{
  "mcp.servers": {
    "docker-local": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    },
    "docker-staging": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://staging.example.com:2376",
        "--tlsverify"
      ],
      "env": {
        "DOCKER_CERT_PATH": "/Users/me/.docker/staging-certs"
      }
    }
  }
}

通过在对话里指明"查 staging Docker 上的容器"让 Agent 路由到对应 Server,避免连错环境。

Trae(mcp config)

Trae 的 MCP 配置通过内置命令管理,也可以直接编辑配置文件。命令行方式:

# 添加 docker MCP Server(本地 socket)
trae mcp add docker -- npx -y @modelcontextprotocol/server-docker

# 查看已配置的 MCP Server
trae mcp list

# 验证 docker 是否可用
trae mcp test docker

或者直接编辑配置文件 ~/.trae/mcp.json:

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

带项目级配置的写法(.trae/mcp.json 放项目根目录):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://docker-prod.internal:2376",
        "--tlsverify"
      ],
      "env": {
        "DOCKER_CERT_PATH": "/Users/me/.docker/prod-certs"
      }
    }
  }
}

项目级配置跟用户级同名时项目级覆盖。开发用本地 Docker,生产用项目级指向生产主机,团队共享项目级配置时记得把证书路径换成环境变量占位。

通用配置模板(一图速查)

客户端配置文件路径关键字段
Claude Code~/Library/Application Support/Claude/claude_desktop_config.jsonmcpServers.docker
Cursor.cursor/mcp.json(项目或用户级)mcpServers.docker
VS Codesettings.json 或 ~/.continue/config.jsonmcp.servers.docker 或 mcpServers.docker
Trae~/.trae/mcp.json 或 trae mcp addmcpServers.docker

核心配置统一是这三行(连本地 Docker socket 时):

"docker": {
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-docker"]
}

记住这三行,搬到哪个客户端都能用。需要连远程时加 --host tcp://主机:2376 --tlsverify,并通过 DOCKER_CERT_PATH 提供证书。

Docker socket 权限速查

Docker MCP 要能连上 Docker,必须有读 socket 的权限。各操作系统下的常见坑:

Linux:
  Docker socket 默认权限 root:docker 660
  → 把当前用户加入 docker 组:sudo usermod -aG docker $USER
  → 重新登录生效
  → ⚠️ 注意:docker 组等价于 root 权限,多人共用主机时慎用

macOS (Docker Desktop):
  socket 默认在 /var/run/docker.sock(实际是 ~/.docker/run/docker.sock 软连)
  → Docker Desktop 安装后默认当前用户可读,无需额外配置
  → 但要在 Docker Desktop 设置里勾选 "Allow default Docker socket"

Windows (Docker Desktop):
  使用命名管道 //./pipe/docker_engine
  → Docker Desktop 默认开放给当前用户
  → 如果是 WSL2 后端,WSL 内访问要走 docker-desktop 数据面

如果 Docker MCP 启动报 "permission denied" 或 "connect EACCES",几乎一定是 socket 权限问题,按上面排查。

连接串/参数格式速查

本地 socket(默认):           不传参数
远程明文(仅内网测试):        --host tcp://10.0.0.5:2375
远程 TLS(生产):              --host tcp://docker.host:2376 --tlsverify
指定证书目录:                  --tlscacert /path/ca.pem --tlscert /path/cert.pem --tlskey /path/key.pem
                                或环境变量 DOCKER_CERT_PATH=/path

推荐做法(环境变量法):
  env: { "DOCKER_HOST": "tcp://docker.host:2376",
         "DOCKER_TLS_VERIFY": "1",
         "DOCKER_CERT_PATH": "/etc/docker/certs" }
  → 不用写 --host / --tlsverify 参数,Docker SDK 自动识别

用 DOCKER_HOST 环境变量比命令行参数更优雅——因为底层用的是 Docker 官方 SDK,它本身就支持这一组标准环境变量。

三个实战场景

光看配置没感觉,下面三个场景演示 Docker MCP 真正能解决什么问题。每个场景都附完整步骤和可直接照抄的对话示例。

场景一:容器故障自动排查

背景:你的 API 服务跑在 Docker 容器里(容器名 api)。凌晨告警说接口 502,你被叫醒,但还没起床进电脑。你想让 Agent 帮你先看一眼到底是什么情况,能自愈就先恢复服务。

痛点对照:

没 Docker MCP:
  你:(手机 SSH 上主机)docker ps -a | grep api
      → 看到 Exited
      → docker logs api --tail 200 > /tmp/log.txt
      → 把日志 cat 出来,复制到对话框
      → Agent 看日志猜原因
      → 你再手动 docker restart api 验证

有 Docker MCP:
  你:API 容器是不是挂了?帮我查下原因,能恢复就先恢复
  Agent:(list_containers)→(get_container_logs)→(分析)→(restart_container)→(验证)

完整步骤:

  1. 让 Agent 先列出所有容器,找到 api 容器当前状态
  2. Agent 拉取容器最近日志,定位异常原因
  3. Agent 查看容器详情(资源限制/重启策略)
  4. Agent 给出根因分析
  5. Agent 重启容器(或调整配置后重启)
  6. Agent 验证服务恢复(再查日志/状态)

示例对话:

你:API 容器好像挂了,接口 502。帮我查下原因,能自愈就先重启恢复,
    然后告诉我需不需要进一步处理。

Agent:
  好的,我先看下所有容器状态。

  [调用工具: list_containers]
  all: true

  [工具返回]
  [
    {"id":"a1b2c3d4","name":"api","image":"myapi:v1.2.3",
     "status":"exited (137) 14 minutes ago","ports":["8080:8080"]},
    {"id":"e5f6g7h8","name":"db","image":"postgres:15",
     "status":"running","ports":["5432:5432"]},
    {"id":"i9j0k1l2","name":"redis","image":"redis:7",
     "status":"running","ports":["6379:6379"]}
  ]

  api 容器状态是 exited (137),14 分钟前退出。退出码 137 通常是
  被 SIGKILL——可能是 OOMKilled 或外部 kill。拉日志看:

  [调用工具: get_container_logs]
  container: api
  tail: 200

  [工具返回]
  ...(省略前面正常日志)
  2026-09-09 03:12:45 INFO  Request GET /api/users completed in 23ms
  2026-09-09 03:12:46 INFO  Request POST /api/orders started
  2026-09-09 03:12:46 WARN  Memory usage: 89% of 512MB limit
  2026-09-09 03:12:46 WARN  Memory usage: 95% of 512MB limit
  2026-09-09 03:12:47 ERROR Cannot allocate memory, shutting down request
  2026-09-09 03:12:48 INFO  Graceful shutdown initiated...
  (无更多日志)

  日志显示内存涨到 95% 后请求分配失败、容器退出。看下容器配置确认
  内存限制:

  [调用工具: get_container]
  id: a1b2c3d4

  [工具返回]
  {
    "name":"api",
    "hostConfig":{
      "memory":536870912,        ← 512MB
      "memorySwap":536870912,    ← 不允许 swap
      "restartPolicy":{"name":"no"}  ← 不自动重启
    },
    "state":{
      "status":"exited",
      "oomKilled":true,           ← ⚠️ OOM 杀死
      "exitCode":137
    }
  }

  根因确认:OOMKilled=true,容器因内存超限被 Docker 杀掉。
  现在请求高峰已过,先重启恢复服务:

  [调用工具: start_container]
  id: a1b2c3d4

  [工具返回]
  a1b2c3d4   ← 启动成功

  等 5 秒再查日志和状态确认恢复:

  [调用工具: get_container_logs]
  container: api
  tail: 30

  [工具返回]
  2026-09-09 03:35:01 INFO  Server started on :8080
  2026-09-09 03:35:02 INFO  Health check: OK
  2026-09-09 03:35:05 INFO  Request GET /health completed in 2ms

  ✅ 服务已恢复。变更摘要:
     - 容器:api
     - 故障:OOMKilled(内存超 512MB 被杀)
     - 操作:start_container 重启
     - 当前:running,健康检查 OK
     - 重启策略:no(不会自动恢复,下次还会这样)

  建议后续处理:
  1. 把内存限制调到 1g(用 docker run 时加 --memory=1g,
     或在 compose 里改 deploy.resources.limits.memory)
  2. 重启策略改 unless-stopped,挂了能自动起
  3. 排查为什么凌晨请求让内存涨到 95%——可能泄漏或大查询

  要我直接改 compose 文件还是你来?

为什么这个场景重要:容器故障排查是 DevOps 最高频的痛点,传统做法要在告警→SSH→敲命令→看日志→重启这个链路上手动多次切换。Agent 通过 Docker MCP 能在对话里走完"诊断→根因→恢复→验证"完整闭环——重点是 Agent 主动调用了 get_container 看 oomKilled 字段,这是从 docker inspect 大段 JSON 里精确取值的,Bash MCP 跑命令的 Agent 很容易漏看这个关键字段。

进阶:让 Agent 在 start 之前先用 system_info 看主机剩余内存,避免内存不够重启后又 OOM。或用 list_processes 看是不是有内存泄漏进程。

场景二:镜像构建优化

背景:你的 Node.js API 镜像 myapi:v1.2.3 从最初的 280MB 涨到 1.2GB,CI 构建时间从 1 分钟涨到 4 分钟,部署拉镜像也慢。你想让 Agent 分析 Dockerfile、检查镜像分层、给出优化方案。

痛点对照:

没 Docker MCP:
  你:帮我看看为啥镜像这么大
  Agent:你跑下 docker history myapi:v1.2.3 给我
  → 你跑命令,复制输出
  Agent:看到了,第一层 npm install 占 800MB……
       你再跑 docker images、再 docker inspect 给我
  → 你来回切换、复制粘贴 3 次

有 Docker MCP:
  你:分析 myapi:v1.2.3 镜像为啥 1.2GB,给优化方案
  Agent:(image_history)→(inspect_image)→(分析)→ 改 Dockerfile

完整步骤:

  1. Agent 查看镜像构建历史,定位最大的几层
  2. Agent 查看镜像详情,确认基础镜像和环境
  3. Agent 让用户把 Dockerfile 给它看(用 Filesystem MCP 读)
  4. Agent 分析 Dockerfile 哪些指令产生了冗余层
  5. Agent 给出优化方案(多阶段构建、合并 RUN、.dockerignore)
  6. Agent 重新构建镜像验证体积减小

示例对话:

你:myapi:v1.2.3 这个镜像有 1.2GB,比最早的 280MB 大了 4 倍。
    帮我分析下哪层最大、为什么,然后给优化方案。

Agent:
  先看镜像分层。

  [调用工具: image_history]
  image: myapi:v1.2.3

  [工具返回]
  [
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop) ENTRYPOINT [\"node\" \"server.js\"]","size":"0B","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop) EXPOSE 8080","size":"0B","comment":""},
    {"created":"2026-09-09","created_by":"COPY . .","size":"180MB","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c npm install","size":"640MB","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop) WORKDIR /app","size":"0B","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c apt-get update && apt-get install -y curl vim git","size":"85MB","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop) ENV NODE_ENV=production","size":"0B","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c apk add --no-cache python3 make g++","size":"120MB","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop)  CMD [\"node\"]","size":"0B","comment":""},
    {"created":"2026-09-09","created_by":"/bin/sh -c #(nop) ADD file:... in node:18-alpine","size":"180MB","comment":""}
  ]

  总计 1.205GB。各层占比:
  | 层 | 大小 | 占比 |
  |----|------|------|
  | npm install | 640MB | 53% |
  | COPY . . | 180MB | 15% |
  | node:18-alpine 基础 | 180MB | 15% |
  | apk add python/make/g++ | 120MB | 10% |
  | apt-get curl vim git | 85MB | 7% |

  ⚠️ 注意:apt-get 在 alpine 上跑不通,这层八成是写错或残留。
  ⚠️ COPY . . 占 180MB,八成把 node_modules、.git 都 COPY 进去了。

  拿下镜像详情确认:

  [调用工具: inspect_image]
  image: myapi:v1.2.3

  [工具返回]
  {
    "architecture":"amd64",
    "os":"linux",
    "config":{
      "Image":"node:18-alpine",
      "WorkingDir":"/app",
      "Env":["NODE_PATH=/app/node_modules","NODE_ENV=production"]
    },
    "rootfs":{"type":"layers","diff_ids":[...10 层]}
  }

  确认基础镜像是 node:18-alpine(180MB 是合理的)。
  现在让我看一下 Dockerfile:

  [切换到 Filesystem MCP]
  [调用工具: read_file]
  path: /Users/me/projects/api/Dockerfile

  [工具返回]
  FROM node:18-alpine

  ENV NODE_ENV=production

  RUN apk add --no-cache python3 make g++

  RUN apt-get update && apt-get install -y curl vim git

  WORKDIR /app

  COPY . .

  RUN npm install

  CMD ["node"]
  ENTRYPOINT ["node", "server.js"]
  EXPOSE 8080

  根因分析:

  1. apt-get 在 alpine 上不该有,那是 Debian 系的包管理器
     → 这层 85MB 八成是失败的残留或多余装了 glibc 兼容层
     → 应该全删,或换 apk add curl

  2. COPY . . 把整个项目目录都拷进去,包括 node_modules、
     .git、build 产物——180MB 大头是这些
     → 应该先写 .dockerignore 排除这些,再 COPY

  3. npm install 把生产 + 开发依赖都装了,640MB
     → 应该 npm install --production 只装生产依赖
     → 或用多阶段构建:build 阶段装全部、run 阶段只装生产

  4. python3/make/g++ 是为某些 native 模块编译用
     → 编译完后这些工具运行时不需要,应该用多阶段构建
     → 只把编译好的 node_modules 拷到运行镜像

  5. CMD ["node"] 跟 ENTRYPOINT 重复,按你 ENTRYPOINT 用法
     CMD 应该删掉

  优化方案:改用多阶段构建。

  ```dockerfile
  # 阶段 1:构建
  FROM node:18-alpine AS builder
  WORKDIR /app
  COPY package*.json ./
  RUN npm install            # 装全部依赖(含 dev)
  COPY . .
  RUN npm run build          # 编译产物(如有)

  # 阶段 2:运行
  FROM node:18-alpine AS runner
  WORKDIR /app
  ENV NODE_ENV=production
  COPY --from=builder /app/node_modules ./node_modules
  COPY --from=builder /app/dist ./dist
  COPY package*.json ./
  EXPOSE 8080
  ENTRYPOINT ["node", "dist/server.js"]

配套 .dockerignore:

node_modules
.git
.vscode
*.log
dist
build
.env*

预期体积:

  • 基础层:180MB
  • node_modules(仅生产依赖):~180MB
  • dist:~10MB
  • 总计约 370MB,减少 70%

要我直接改 Dockerfile,重新构建吗?

你:改了重新构建一下

Agent: [切换到 Filesystem MCP] 修改 Dockerfile [切换到 Filesystem MCP] 创建 .dockerignore [调用工具: build_image] path: /Users/me/projects/api tag: myapi:v1.2.4 dockerfile: Dockerfile

[工具返回] Step 1/12 : FROM node:18-alpine AS builder ---> a1b2c3 Step 2/12 : WORKDIR /app ---> d4e5f6 Step 3/12 : COPY package*.json ./ ---> ...(省略) Step 12/12 : ENTRYPOINT ["node", "dist/server.js"] ---> Successfully built x9y8z7 ---> Successfully tagged myapi:v1.2.4

构建成功。对比新体积:

[调用工具: list_images] [工具返回] ... {"repository":"myapi","tag":"v1.2.3","size":"1.2GB"} {"repository":"myapi","tag":"v1.2.4","size":"372MB"} ...

✅ 优化完成: - v1.2.3:1.2GB - v1.2.4:372MB - 减少 828MB(-69%) - 多阶段构建 + .dockerignore + 只装生产依赖 - 构建时间也从 4 分钟降到 1 分 20 秒(COPY 层从 180MB 降到 12MB)


**为什么这个场景重要**:镜像体积膨胀是 Docker 长期项目必经的痛点,靠人眼盯 Dockerfile 和 `docker history` 输出很难发现冗余层。Agent 用 `image_history` + `inspect_image` 拿到结构化的分层信息,能精确指出哪层多大、由哪条指令产生,再结合 Filesystem MCP 读 Dockerfile 反推根因——**这是 Docker MCP + Filesystem MCP 联动的典型应用:Docker MCP 看"现在镜像是什么样",Filesystem MCP 看"怎么构建的"**。

> 进阶:让 Agent 同时跑 `system_df` 看是否还有大量冗余旧镜像可清,进一步释放磁盘。

### 场景三:多容器环境编排

**背景**:你在本地用 Docker 起一套完整的开发环境——PostgreSQL 数据库 + Redis 缓存 + API 服务 + 前端。原本用 `docker compose up`,但今天起不来,报"network app-net not found"或"port 5432 already in use"之类。让 Agent 帮你排查、修复并最终把整套环境拉起来。

**痛点对照**:

没 Docker MCP: 你:docker compose up 报错,帮我看看 Agent:你贴下报错和 docker network ls 输出 → 你来回贴 4 次命令输出 → Agent 凭转述猜原因

有 Docker MCP: 你:compose 起不来,帮我排查然后拉起来 Agent:(compose_ps)→(list_networks)→(list_containers)→(修复)→(compose_up)→(验证)


**完整步骤**:

1. Agent 先看 compose 项目当前状态(哪些服务起来了)
2. Agent 看所有 Docker 网络是否存在 app-net
3. Agent 看是否已有占用端口的容器(5432/6379/8080/3000)
4. Agent 定位冲突(网络被删/端口被占)
5. Agent 修复(重建网络 / 停掉冲突容器 / 改 compose 端口)
6. Agent 重启 compose 项目
7. Agent 验证所有服务状态和连通性

**示例对话**:

你:本地开发环境起不来了,docker compose up 报"network app-net not found"和"port 5432 already in use"。帮我排查然后拉起来。

Agent: 先看 compose 项目当前状态:

[调用工具: compose_ps] project: myapp

[工具返回] [] ← 一个服务都没起来

看下所有 Docker 网络和容器:

[调用工具: list_networks]

[工具返回] [ {"name":"bridge","driver":"bridge","scope":"local"}, {"name":"host","driver":"host","scope":"local"}, {"name":"none","driver":"null","scope":"local"} ]

⚠️ 没有 app-net,被删了——这就是第一个报错的原因。

[调用工具: list_containers] all: true

[工具返回] [ {"id":"a1b2","name":"legacy-db","image":"postgres:14", "status":"running","ports":["5432:5432"]}, {"id":"c3d4","name":"legacy-cache","image":"redis:6", "status":"running","ports":["6379:6379"]} ]

⚠️ 有两个遗留容器(legacy-db 和 legacy-cache)占着 5432 和 6379, 这是第二个报错"port 5432 already in use"的原因。

修复方案:

  1. 删掉两个 legacy 容器(看起来是旧版本残留,新 compose 会起新的)
  2. 创建 app-net 网络(compose up 时本来会自动创建,但因为端口冲突 没到那一步就失败了)
  3. 重新 compose up

先停删 legacy 容器:

[调用工具: stop_container] id: a1b2

[调用工具: stop_container] id: c3d4

[调用工具: remove_container] id: a1b2

[调用工具: remove_container] id: c3d4

创建 app-net(其实 compose up 会自动建,但显式建能避免下次再卡):

[调用工具: create_network] name: app-net driver: bridge

[工具返回] a7b8c9d0 ← 网络 ID

现在拉起整套 compose:

[调用工具: compose_up] project: myapp detach: true

[工具返回] [ {"service":"db","status":"running","ports":["5432:5432"]}, {"service":"redis","status":"running","ports":["6379:6379"]}, {"service":"api","status":"running","ports":["8080:8080"]}, {"service":"web","status":"running","ports":["3000:3000"]} ]

4 个服务都起来了。验证网络连通性:

[调用工具: inspect_network] name: app-net

[工具返回] { "name":"app-net", "driver":"bridge", "subnet":"172.20.0.0/16", "containers":{ "abc1":{"name":"myapp-db-1","ipv4":"172.20.0.2"}, "def2":{"name":"myapp-redis-1","ipv4":"172.20.0.3"}, "ghi3":{"name":"myapp-api-1","ipv4":"172.20.0.4"}, "jkl4":{"name":"myapp-web-1","ipv4":"172.20.0.5"} } }

✅ 全部 4 个容器都接入 app-net,能通过容器名互访: - db:172.20.0.2 - redis:172.20.0.3 - api:172.20.0.4 - web:172.20.0.5

端到端验证:让 api 连 db 看是否通:

[调用工具: exec_in_container] container: myapp-api-1 command: sh -c "nc -z db 5432 && echo DB_OK || echo DB_FAIL"

[工具返回] DB_OK

[调用工具: exec_in_container] container: myapp-api-1 command: sh -c "nc -z redis 6379 && echo REDIS_OK || echo REDIS_FAIL"

[工具返回] REDIS_OK

[调用工具: exec_in_container] container: myapp-web-1 command: sh -c "nc -z api 8080 && echo API_OK || echo API_FAIL"

[工具返回] API_OK

✅ 全链路通:web → api → db / redis 都连得上。

最终状态:

  • 4 个容器 running,端口 5432/6379/8080/3000 全部正常
  • 同在 app-net 网络,容器名互通
  • 联通性验证通过
  • legacy 容器已清理,下次再起不会冲突

建议后续:

  1. 给 compose 文件加 depends_on,避免启动顺序错
  2. db 加 healthcheck,api 加 depends_on condition: service_healthy
  3. legacy 容器为啥残留——可能是手动 docker run 启的,没纳入 compose

**为什么这个场景重要**:多容器编排故障的核心难点不是单点问题,而是"问题在多个对象间牵连"——网络没了导致容器起不来、端口冲突导致 compose 失败、然后整链路都瘫。Agent 通过 `compose_ps`、`list_networks`、`list_containers` 组合拿到全局视图,定位"网络缺失 + 端口冲突"双因,再用 `exec_in_container` 做连通性验证——**这种多对象协同排查是 Docker MCP 比单跑 `docker` 命令显著更聪明的地方**:Agent 不会只盯着一个容器看,而是把网络、容器、端口一起对照分析。

> 进阶:让 Agent 在 compose_up 之后还跑一遍 `system_df` 看 docker 主机磁盘够不够,避免"看似起来了但日志写不进去"的隐性故障。

## Docker MCP vs Kubernetes MCP:选型对比

很多人会问:**既然 Kubernetes MCP 也能让 Agent 管容器,为啥还要 Docker MCP?** 答案是它俩解决的问题根本不在一个层面——一个是"单主机容器生命周期",一个是"集群调度与声明式资源"。

先看核心差异:

| 维度 | Docker MCP | Kubernetes MCP |
|------|-----------|--------------------|
| **抽象层级** | 单主机容器/镜像/网络/卷 | 集群 Pod/Deployment/Service/Ingress |
| **资源模型** | 命令式(启动容器、停容器) | 声明式(apply YAML 描述期望状态) |
| **调度能力** | ❌ 无(手动指定主机) | ✅ 自动调度到合适节点 |
| **自愈能力** | ❌ 仅 restart policy | ✅ 控制器自动重建 Pod |
| **网络模型** | bridge/overlay(单主机或多主机互联) | CNI(每个 Pod 独立 IP,集群 DNS) |
| **存储模型** | 本地卷/NFS | PVC/PV/StorageClass 动态供给 |
| **配置管理** | -v 挂载 / env 变量 | ConfigMap / Secret |
| **典型操作** | 起/停/重启单个容器 | 滚动升级、扩缩容、改镜像版本 |
| **YAML 必需性** | 不需要(命令行参数即可) | 必须(声明式资源都靠 YAML) |
| **学习曲线** | 平缓(5 个核心概念) | 陡峭(30+ 资源类型) |
| **典型用途** | 本地开发/单机部署/CI 流水线 | 生产集群调度/微服务编排 |
| **状态可见性** | 直接(容器跑没跑一目了然) | 间接(要看 ReplicaSet/Pod 状态) |
| **故障根因层次** | 浅(容器/镜像/网络/卷四选一) | 深(Pod→ReplicaSet→Deployment→Service→Ingress 多层) |
| **适合 Agent 做什么** | 调单容器、查日志、构建镜像、起本地栈 | 滚动升级、扩缩容、调试 Pod 状态、改 YAML |

**什么时候用 Docker MCP**:

✅ 本地开发环境(docker compose 起一整套) ✅ CI 流水线里跑测试容器 ✅ 单机部署的小规模生产 ✅ 镜像构建和优化(Dockerfile、分层分析) ✅ 容器化应用的本地调试 ✅ 简单的临时容器(跑一次脚本就删)


**什么时候用 Kubernetes MCP**:

✅ 生产集群部署(多副本、滚动升级) ✅ 服务发现和负载均衡(通过 Service) ✅ 自动扩缩容(HPA) ✅ 跨节点调度和故障转移 ✅ 复杂的配置/密钥管理(ConfigMap/Secret) ✅ 多团队共用集群(Namespace 隔离)


**一个简单的判断流程**:

你的容器跑在哪? ├─ 单机 Docker(开发/测试/小规模生产)→ Docker MCP └─ K8s 集群(生产规模化) → Kubernetes MCP

不确定在哪?问自己: ├─ 装的是 Docker 还是 K8s? → 看用什么工具 └─ 想做的是"起停容器"还是"扩缩容发布"? 起停 → Docker 扩缩容 → K8s


**实际项目里两个一起用**是最常见的搭配:

Docker MCP → 本地开发、构建镜像、CI 跑测试 →"怎么造镜像和本地起容器" Kubernetes MCP → 生产部署、扩缩容、滚动发布 →"怎么发布和管理运行时"


比如一次完整发布流程:先 Docker MCP 在本地构建并验证镜像,推到仓库,再切到 Kubernetes MCP 让 Agent 改 Deployment 镜像版本触发滚动升级,最后查 Pod 状态验证发布成功。**别想着二选一,它们解决的是不同生命周期的容器问题**。

**为什么本地开发不直接上 K8s**:很多人会问"既然生产是 K8s,本地也用 K8s(minikube/kind)不更一致吗?"理论上对,实操有几个坑:

  1. K8s 集群启动慢(minikube start 要 1-2 分钟),开发迭代慢
  2. K8s 调试单个 Pod 要 kubectl exec/ksniff,比 docker exec 复杂
  3. 本地资源有限,K8s 控制面吃掉 2GB 内存,开发机扛不住
  4. K8s YAML 写错一行 Pod 就起不来,调试反向追因麻烦

所以行业里 Docker(compose)做本地开发、K8s 做生产,仍然是主流搭配。Docker MCP 和 Kubernetes MCP 一起配,覆盖"本地迭代 + 生产运维"两个阶段。

## 安全注意事项

把 Docker MCP 接到生产环境之前,有几条必须防住的安全边界。Docker 跟其他 MCP 最大的不同是——**Docker API 等同于宿主机 root 权限**:任何一个能调 Docker API 的人,都能起一个挂载 `/` 的容器拿到宿主 root。这种"上帝权限"配置不当就是灾难。

### 1. 容器逃逸风险

Docker 默认的 namespace + cgroup 隔离在历史上出现过多次逃逸漏洞(runc CVE-2019-5736、CVE-2022-0185 等)。Agent 通过 Docker MCP 起容器时如果不约束,可能引入逃逸风险:

风险场景: Agent 起一个容器调试:docker run -it --privileged --pid=host alpine → --privileged 关闭所有隔离 → --pid=host 共享宿主 PID 命名空间 → 容器内能直接 ptrace 宿主进程,拿到宿主 root

防护:

  • system prompt 里明确禁止 --privileged / --pid=host / --net=host
  • 生产环境禁用 run_container 工具,只允许操作已有容器
  • 用 AppArmor / SELinux 给容器额外加 MAC 限制
  • 定期升级 Docker(修 runc 逃逸漏洞)
  • 启用 user namespace 重映射(容器 root 映射到宿主非 root)

各客户端在 system prompt 里加规则的写法:

你连的是生产 Docker。规则:

  1. 禁止起 --privileged 容器
  2. 禁止 --pid=host / --net=host / --ipc=host
  3. 禁止挂载宿主敏感目录:/、/etc、/var/run/docker.sock、/root、/home
  4. 任何 run_container 调用前必须用户确认
  5. remove_container / remove_image 前必须用户确认
  6. exec_in_container 命令里禁止 rm -rf / 类危险命令
  7. 不调用 system_prune(清理会删大量对象)

### 2. 特权模式与挂载的危险

Docker 的几个"上帝模式"参数,开了就等于把宿主送给容器:

极危险参数(永远不要在 Agent 起的容器里用): --privileged ← 关闭所有安全隔离 --pid=host ← 共享宿主进程空间 --net=host ← 共享宿主网络(端口都通) --ipc=host ← 共享 IPC(能跨容器搞共享内存攻击) -v /:/host ← 挂载宿主根目录 -v /var/run/docker.sock:/var/run/docker.sock ← 挂载 Docker socket(容器能管宿主 Docker) --cap-add=SYS_ADMIN ← 加 SYS_ADMIN capability(几乎等于 root) --userns=host ← 关闭 user namespace 重映射

风险实例: Agent 起"我要在容器里装个调试工具" → docker run -v /var/run/docker.sock:/var/run/docker.sock alpine sh → 容器内 docker 命令直接控制宿主 Docker 守护进程 → 等于拿到宿主 root


如果业务确实需要这些权限(比如容器内要起容器),强烈建议**用 Docker-in-Docker 隔离方案**而不是挂载宿主 socket:

✗ 危险:挂宿主 socket docker run -v /var/run/docker.sock:/var/run/docker.sock docker

✓ 安全:DinD(容器内独立 dockerd) docker run --privileged docker:dind (privileged 是 DinD 唯一容忍场景,且容器有独立 namespace)


### 3. 敏感镜像处理

Agent 通过 `pull_image` 拉镜像时,要警惕恶意镜像和敏感数据外泄:

风险 1:拉到恶意镜像 Agent 拉一个 dockerhub 上的随手镜像跑 → 镜像里预埋挖矿/后门 → 容器一启动就成肉鸡

防护:

  • system prompt 里限制只能拉白名单仓库(公司内部 registry)
  • 用 Docker Content Trust 签名验证(DOCKER_CONTENT_TRUST=1)
  • 镜像扫描(Trivy/Clair)跑进 CI 拦截漏洞镜像

风险 2:镜像里含敏感信息 开发者把 .env、密钥、token 打进镜像 → 镜像推到公开仓库 → 任何人 docker pull + docker history 都能看到

防护:

  • 用 .dockerignore 排除 .env / .key / credentials
  • 敏感配置走运行时环境变量或 Secret,不进镜像
  • push_image 前让 Agent 扫一遍镜像分层,检查是否有敏感文件

让 Agent 在 push 前做镜像扫描的对话示例:

你:把 myapi:v1.2.4 推到 registry

Agent: 推之前先扫一下镜像分层有没有敏感文件:

[调用工具: image_history] image: myapi:v1.2.4

[工具返回] ... {"created_by":"COPY .env /app/.env","size":"2KB"} ← ⚠️ ...

⚠️ 发现 .env 被 COPY 进镜像。这八成含密钥, 推到 registry 会被任何人 docker history 看到。 建议先把这层去掉(在 .dockerignore 加 .env, 重新 build),再 push。

要我帮你改 Dockerfile 还是直接 push?


### 4. 只读模式配置

生产 Docker 主机的 MCP 连接**默认应该是只读的**——Agent 能查容器状态、看日志、分析镜像,但不能起停容器、不能删镜像、不能改网络。这需要 Docker MCP 实现层支持只读模式(部分版本支持):

```json
{
  "mcpServers": {
    "docker-readonly": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--readonly"
      ]
    }
  }
}

--readonly 让 MCP Server 只暴露 list_*、get_*、inspect_* 类工具,不暴露 start_* / stop_* / remove_* / build_* / run_* 等变更类工具。Agent 即使被提示注入想 remove_container,工具根本不存在调不到。

如果实现不支持 --readonly,变通方案是连一个受限 Docker socket:

{
  "mcpServers": {
    "docker-readonly": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://docker-proxy-readonly.internal:2376"
      ],
      "env": {
        "DOCKER_CERT_PATH": "/etc/docker/readonly-certs"
      }
    }
  }
}

这个 docker-proxy-readonly 是在 Docker 守护进程前加一层代理(如 docker-socket-proxy),白名单只允许 GET 类 API,POST/DELETE 全部拒绝。是 ACL 层面的硬隔离,比 system prompt 更可靠。

需要写权限的场景(如容器重启),起一个独立的可写连接,按需启用:

{
  "mcpServers": {
    "docker-readonly": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker", "--readonly"]
    },
    "docker-writer": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://docker-proxy-writer.internal:2376"
      ],
      "env": { "DOCKER_CERT_PATH": "/etc/docker/writer-certs" }
    }
  }
}

5. 超时设置

Agent 调用 Docker MCP 时,部分操作可能很慢——大镜像构建几分钟、docker pull 几十 GB 镜像十几分钟。如果 MCP 客户端默认超时太短,会中断操作导致镜像构建半途而废。配置建议:

MCP 客户端侧超时:
  Claude Code:默认无超时(推荐保持)
  Cursor:默认 60 秒(构建镜像会断!需调大)
  VS Code:默认 30 秒(同上)
  Trae:可在 mcp.json 配 timeout 字段

Cursor 调超时配置:
  {
    "mcpServers": {
      "docker": {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-docker"],
        "timeout": 600000   ← 10 分钟
      }
    }
  }

构建镜像的 build_image、拉镜像的 pull_image 务必配 10 分钟以上超时。日常 list_containers、get_container_logs 这种秒级操作保持默认即可。

6. 数据脱敏

Agent 查容器日志和环境变量时可能拿到敏感信息(数据库密码、API token、JWT)。在 system prompt 里加脱敏规则:

你连的是生产 Docker。规则:
1. 容器日志里出现 password=xxx / token=xxx 时打码显示 password=***
2. get_container 返回的 Env 列表里 PASSWORD/SECRET/TOKEN 字段不显示值
3. exec_in_container 时不要 cat /proc/1/environ 之类读环境变量的命令
4. 不要把容器日志直接全量回显——超过 500 行只摘要

7. 最小权限原则

默认只配只读 docker,不配 filesystem/github 等可写 MCP
  → Agent 能查容器但改不了本地
需要写时再单独加可写连接或 filesystem,限定范围
  → 隔离爆炸半径

✗ 一个 MCP 配置同时连生产 Docker 可写 + filesystem 全盘
  → 一旦 Agent 被提示注入,能起恶意容器 + 改本地脚本
✓ 只读 Docker + 限定目录的 filesystem
  → 即使被注入,破坏有限

常见故障排查

现象原因解决
Agent 报 "docker tool not found"配置没生效重启客户端;检查 JSON 语法;查日志确认 server 启动
连接报 permission denied / connect EACCESDocker socket 无读权限Linux:把用户加 docker 组;macOS/Windows:检查 Docker Desktop 是否启动
连接报 Cannot connect to the Docker daemonDocker 守护进程没起启动 Docker Desktop / sudo systemctl start docker
连远程报 x509: certificate signed by unknown authorityTLS 证书校验失败证书过期/CA 不在信任链;重新签发或加 --tlsverify=false(仅内网测试)
连远程报 connection refused远程 Docker 没开 TCP 监听在 dockerd 启动参数加 -H tcp://0.0.0.0:2376;防火墙开放 2376
build_image 超时镜像大、网络慢调大 MCP 客户端超时;分步构建(先 build 基础层、再 COPY 代码)
pull_image 报 unauthorized镜像仓库需要登录docker login 写好 ~/.docker/config.json;或把凭证放 MCP env
Agent 不主动用 docker提示不够明确对话里明确说"连 Docker 查…"
Agent 调用 list_containers 慢容器太多/状态计算重加 filter 参数(如 status=running)只看运行中
exec_in_container 报 not found容器没起 / 命令在容器里不存在先 list 确认容器 running;先 which <cmd> 验证命令存在
remove_image 报 image is being used镜像被容器引用先 stop+remove 引用容器,再 rmi
compose_up 报 network exists网络同名冲突docker network rm app-net 后重试;或在 compose 里 name: 改自定义
get_container_logs 返回空容器刚起还没日志 / 选错容器加 --since 5m 看最近 5 分钟;用 stdout=true/false 区分 stdout/stderr
镜像构建后体积不对build cache 干扰--no-cache 强制全量重建

进阶用法:组合其他 MCP

Docker MCP 单用已经很强,但跟其他 MCP 组合起来威力翻倍。几个常见组合:

Docker + Filesystem:容器配置与代码同步

你:容器报"Cannot find module 'express'",帮我看下代码和容器里
    是不是依赖没装

Agent:
  1. [filesystem] 看 package.json 有 express
  2. [docker] exec_in_container 跑 ls node_modules | grep express
  3. 发现容器里没装 → .dockerignore 把 node_modules 排除但没在镜像里 npm install
  4. [filesystem] 改 Dockerfile 加 RUN npm install
  5. [docker] build_image 重新构建
  → 修复

Docker + GitHub:故障关联代码

你:容器 OOM 了,帮我查代码哪里泄漏

Agent:
  1. [docker] get_container_logs 看到内存增长曲线
  2. [docker] exec_in_container 跑 top 看哪个进程吃内存
  3. [github] 搜代码里疑似泄漏的 setInterval / 大对象赋值
  → 数据异常反推到代码根因

Docker + Postgres:数据库容器与持久化数据对账

你:PG 容器跑着,但业务说表查不到。看下数据是不是真的丢了

Agent:
  1. [docker] exec_in_container 跑 psql -c "SELECT count(*) FROM users"
  2. [postgres MCP] SELECT count(*) FROM users
  3. 对比两边数量
  4. 发现容器内 PG 是空的 → 卷挂载错了,PGDATA 路径不对
  → 定位根因

Docker + Memory:容器命名约定记忆

你:记住我们项目容器命名规则是 <service>-<env>-<num>,比如 api-prod-1

Agent:
  1. [memory] 存下这个命名模式
  2. 下次你说"看 prod 的 api"时直接 list_containers filter name=api-prod-*
  → 不用每次重新解释命名规则

性能调优

在生产环境长期用 Docker MCP,有几个性能优化点:

1. 列表查询用 filter

list_containers / list_images 默认返回所有对象。大主机上百容器/几百镜像时,让 Agent 带 filter:

✓ list_containers({ status: "running" })   ← 只看运行中
✓ list_images({ dangling: true })          ← 只看悬空镜像(待清理)
✗ list_containers({})                       ← 全量返回,慢

2. 日志用 tail 和 since

get_container_logs 默认返回全部日志,大容器(如 nginx 长期跑)可能几 GB:

✓ get_container_logs({ tail: 200 })           ← 最近 200 行
✓ get_container_logs({ since: "2026-09-09T00:00:00" })  ← 今天以来
✗ get_container_logs({})                      ← 全量,爆上下文

3. 并行查询

让 Agent 一次查多个容器状态时,明确鼓励它并行:

你:并行查 api、db、redis 三个容器的日志

Agent:(3 次 get_container_logs 并行调用,而不是串行)

MCP 协议支持工具并行调用,但 Agent 默认可能串行——明确说"并行"能让它一次发多个请求。

4. 选择性深查

不要让 Agent 对每个容器都 inspect,先用 list_containers 看状态,只对异常的深查:

第 1 步:list_containers() → 看哪些 exited / restarting
第 2 步:只对异常容器 get_container + get_container_logs
第 3 步:只对日志有线索的 exec_in_container 验证

这种"先状态后内容"的分层查询能在百容器主机上省 90% 以上的开销。

5. 避免大镜像全量 history

✗ image_history("huge-image")   ← 几百层 history 全返回,爆上下文
✓ image_history("huge-image") 限制层数 + 只看大层
✓ 先 system_df 看镜像总大小,只对前 5 大镜像 history

让 Agent 在 system prompt 里加规则:任何 history 操作先看大小,超 1GB 镜像只看前 10 大层。

与其他"操作 Docker"方案对比

除了 Docker MCP,市面上还有几种让 Agent 操作 Docker 的方式,对比一下:

方案优点缺点适合
Docker MCP标准 MCP、结构化返回、类型路由、可设只读部分实现功能有限、需配置日常调试、分析、容器编排
Shell/Bash MCP + docker 命令灵活、能跑任何 docker 命令输出纯文本难解析、权限过大临时一次性操作
自定义脚本完全可控每个问题写一次、不可复用特定高频任务
Portainer / LazyDocker + 截图可视化强Agent 看不到、要人工转述人工排查
直接给 Agent docker 命令复制不需要配置全程手动、易错极少用

典型组合:

日常调试分析:Docker MCP(90%)+ 偶尔 docker 命令(10% 罕见场景)
高频固定任务:封装成自定义脚本 + 定时跑
人工深度排查:Portainer 看可视化 + Docker MCP 做 Agent 分析

实际部署经验

下面是几个真实部署 Docker MCP 时遇到的"非技术"问题,提前知道能少走弯路:

问题 1:Node 版本

Docker MCP 依赖较新的 Node(建议 Node 18+)。老版本跑不起来:

检查:node -v
要求:>= 18
升级:用 nvm install 20 && nvm use 20

问题 2:npx 缓存

每次启动 Agent 都跑 npx -y 会重新检查包,首次可能慢。预安装能加速:

# 全局预装一次
npm install -g @modelcontextprotocol/server-docker

# 配置改用全局版本(去掉 npx -y)
{
  "mcpServers": {
    "docker": {
      "command": "mcp-server-docker",
      "args": []
    }
  }
}

问题 3:跨平台 socket 路径

Docker socket 在不同 OS 上路径不同:

Linux:    /var/run/docker.sock
macOS:    /var/run/docker.sock(实际软连到 ~/.docker/run/docker.sock)
Windows: //./pipe/docker_engine(命名管道,不能用文件路径方式访问)
WSL2:    WSL 内 /mnt/wsl/docker-desktop/docker.sock
                (Docker Desktop 的 WSL 集成)

如果 MCP 实现要求显式指定 socket 路径,跨平台配置要适配。不传参数让 MCP 用默认值通常最省事。

问题 4:远程 Docker 必须配 TLS

很多人图省事连远程 Docker 时用裸 tcp://host:2375(无 TLS)——这是绝对禁止的。一旦暴露 2375 端口到公网,几分钟内就会被扫描并入侵(已有大量公开案例):

✗ tcp://host:2375(明文,等同把宿主 root 交给网络)
✓ tcp://host:2376(TLS 加密 + 双向认证)

更稳的做法:
  - 远程 Docker 不直接暴露公网
  - 通过 SSH 隧道访问:ssh -L 2376:localhost:2376 user@host
  - MCP 连 localhost:2376(实际隧道到远程)

问题 5:团队共享配置

团队多人用同一项目,Docker MCP 配置应该提交到仓库吗?

推荐做法:
  - 项目级 .cursor/mcp.json 提交到仓库,连本地 socket(开发环境)
  - 生产环境远程 Docker 各自维护(用户级配置)
  - TLS 证书绝不进仓库,用环境变量

.cursor/mcp.json 示例(提交到仓库,连本地):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
  }
}

带证书的版本(不提交,写在用户级):

{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-docker",
        "--host", "tcp://${DOCKER_HOST}:2376",
        "--tlsverify"
      ],
      "env": {
        "DOCKER_HOST": "从 1Password / .env 读,不硬编码",
        "DOCKER_CERT_PATH": "${HOME}/.docker/prod-certs"
      }
    }
  }
}

一张图总结

Agent 要操作 Docker
        ↓
配置好 Docker MCP(5 分钟)
        ↓
对话里说"连 Docker 查…"
        ↓
Agent 调用对应对象类型工具
        ↓
   ┌────┴────┐
   │         │
读操作     写操作
   │         │
   ↓         ↓
查/分析    先预览后改(用户确认)
   │         │
   ↓         ↓
结构化返回   start/stop/restart 验证
   ↓
Agent 基于真实状态回答
        ↓
   ┌────┴────┐
   │         │
状态异常   一切正常
   │         │
   ↓         ↓
回代码定位  收工
(Filesystem/GitHub MCP)

快速上手 Checklist

如果你刚拿到 Docker MCP,按这个清单一步步来:

□ 1. 确认 Node 版本 >= 18(node -v)
□ 2. 确认 Docker 已安装并启动
     - macOS/Windows:Docker Desktop 已运行
     - Linux:sudo systemctl status docker 是 active
□ 3. 验证 socket 权限
     - docker ps 能跑通(当前用户能读 socket)
□ 4. 找到你客户端的配置文件位置(参考前文表格)
□ 5. 复制通用配置三行:
    "docker": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-docker"]
    }
□ 6. 重启客户端
□ 7. 跑一个测试对话:
     "列出所有运行中的容器"
     → Agent 调用 list_containers → 返回数组 → 成功
□ 8. 试一个真实场景:
     "看 api 容器最近 50 行日志"
□ 9. 连远程?配 TLS 证书 + --tlsverify
□ 10. 生产环境?配只读模式(--readonly 或 socket-proxy)
□ 11. system prompt 里禁用 --privileged / 挂载敏感目录
□ 12. 大主机?让 Agent 查询带 filter 和 tail

常见问答

Q1:Docker MCP 能起 K8s 集群里的 Pod 吗?

A:不能。Docker MCP 操作的是单主机 Docker 守护进程,跟 K8s API 是两套。K8s 集群里的 Pod 用 Kubernetes MCP(基于 kube API)。两者不可互替。

Q2:Docker MCP 能管 Docker Swarm 吗?

A:部分支持。Swarm 服务、任务这些概念在标准 Docker API 里有对应端点,但 Docker MCP 实现未必封装。Swarm 模式(docker swarm init、docker service create)目前主流 MCP 实现覆盖不全。需要 Swarm 建议用 Bash MCP + docker 命令。

Q3:Agent 会不会乱删容器?

A:会的,如果不约束。务必:

  • 生产环境用 --readonly 模式(数据库层面强制)
  • system prompt 里加规则"任何 remove_* / stop_* 前必须用户确认"
  • 关键容器(如生产 db)单独配 socket-proxy 白名单只读
  • 用 restart_policy 让容器挂了自动起,减少手动操作需求

Q4:Docker MCP 能实时看 stats 吗(CPU/内存)?

A:能查快照,不能持续订阅。get_container_stats 拿的是单次快照(等价 docker stats --no-stream)。要持续监控建议接专门的监控(Prometheus + cAdvisor),MCP 不适合长连接订阅场景。

Q5:Docker MCP 会缓存查询结果吗?

A:默认不缓存,每次调用都打 Docker API。高频重复查同状态时可加 Memory MCP 显式缓存:

1. [memory] 查有没有存过最近 1 分钟的容器列表
2. 没有 → [docker] list_containers → [memory] 存
3. 有 → 直接用记忆里的列表

Q6:怎么限制 Agent 只能查特定容器?

A:Docker 本身没有"按容器名授权"的细粒度 ACL(不像 Redis 的 key pattern)。变通方案:

  • 在 socket-proxy 层面按 URL 路径限制(如只允许 /containers/json)
  • system prompt 里告诉 Agent"只看 name 以 app- 开头的容器"
  • 起一个独立的 Docker 主机专门给 Agent 用,物理隔离

Q7:Docker MCP 和 Portainer 啥关系?

A:互补关系。Portainer 是 GUI 可视化工具,给人看;Docker MCP 是 API,给 Agent 用。日常排查可视化用 Portainer,让 Agent 自动化分析用 Docker MCP,两个一起最爽。

Q8:大主机(200+ 容器)会让 Agent 爆上下文吗?

A:会。务必在 system prompt 里加规则:

- 任何 list 操作先带 filter(status=running 或 name 前缀匹配)
- 默认只返回前 50 个,更多要明确要求
- list_containers 后只对异常的(exited/restarting)做 inspect

否则 Agent 拉 200 个容器 + 每个的 inspect 会瞬间塞爆上下文窗口。

Q9:Docker MCP 跟 Docker Compose 啥关系?

A:Docker MCP 提供 compose 工具子集(compose_up / compose_down / compose_ps 等),等价于 docker compose 命令行。如果你用 Compose 编排项目,用 compose_* 工具比逐个 start_container 更对——compose 会处理依赖顺序、网络、卷。

Q10:能同时连多台 Docker 主机吗?

A:能。在 mcpServers 里配多个不同名(如 docker-host1、docker-host2),分别连不同 --host。对话里说"查 host1 上的容器"让 Agent 路由到对应 Server。注意多机场景更建议上 K8s 而不是多机 Docker——K8s 本身就是为多机调度设计的,比手动管多台 Docker 主机优雅得多。

结语

Docker MCP Server 是个"广而实"的 MCP Server——它一行配置就能起,本地开发零门槛;但一旦连到远程生产,TLS 证书、只读模式、socket-proxy 这些前置工作要花点心思。一旦配好,它能让 Agent 真正看懂容器、镜像、网络、卷的状态,做结构化分析、给出可执行的修复建议。这一步打通后,容器故障排查、镜像体积优化、多容器编排这些原本要 SSH、敲命令、看日志文件才能干的事,全在对话里就能闭环。

它跟 Kubernetes MCP 不是二选一,而是解决不同生命周期容器问题的互补工具:Docker MCP 管"造镜像和单机容器",Kubernetes MCP 管"集群调度和滚动发布"。两个一起配,Agent 才能同时覆盖"本地迭代 + 生产运维"两个阶段,离一个真正好用的 DevOps 助手又近了一大步。

如果你刚开始接运维类 MCP,建议顺序是:

  1. 先装 Filesystem MCP(让 Agent 能读写本地)
  2. 再装 Docker MCP(让 Agent 能管容器和镜像)
  3. 最后装 Kubernetes MCP(让 Agent 能管生产集群)

三个组合起来,Agent 的"运维视野"就完整了——本地文件、单机容器、集群调度全覆盖,从开发到部署整条流水线 Agent 都能搭把手。


相关阅读:

相关推荐

查看更多 →
MCP开发

Docker MCP Gateway:让 Agent 的每一次执行都发生在一个一次性容器里

2026 年 Agent 安全问题的一个共识正在形成:靠提示词约束 Agent 是软的,靠执行环境约束才是硬的。Docker MCP Gateway 是这个思路最直接的一个落地——它把 MCP 工具本身跑在容器里,Agent 调用的每一个工具都是一次隔离的容器执行:文件系统是临时的、网络是可控的、进程结束即销毁。本文是一份完整实战:Docker MCP Gateway 的安装与四套客户端配置、容器隔离的五个层次(镜像 / 网络 / 挂载 / 资源 / 生命周期)、内置工具与外部 MCP 服务器的混合编排、三个真实场景(安全的代码执行 / 隔离的依赖安装 / 一次性数据库查询)、以及它和「直接在宿主机跑命令」方案的安全对比。含 18 行故障排查表与四条不能碰的红线。

2026-09-29
#MCP#Docker
MCP开发

GitHub MCP:让 LLM 直接操作仓库、PR、Issue 的官方服务器

GitHub MCP 是 ModelContextProtocol 官方维护的开发者集成服务器,通过 GitHub API 让 LLM 客户端能够搜索仓库、读取代码、创建 Issue、提交 PR、管理分支。一条 npx 命令即可让 Claude Code、Cursor、VS Code 等 MCP 客户端成为 GitHub 自动化助理。本文梳理核心能力、Token 申请、各客户端配置与实战注意事项。

2026-08-06
#MCP#GitHub
MCP网络

Sentry MCP Server:让 Agent 直连错误追踪平台自动分析异常

Agent 想帮你排查线上异常,却只能看着你手动登录 Sentry 复制错误堆栈?Sentry MCP Server 打开了直连通道——让 Claude Code、Cursor、VS Code 中的 Agent 能够直接查询 Sentry 错误事件、分析异常趋势、定位根因、管理 issue 状态(resolve/ignore/assign)。本文介绍 Sentry MCP 的核心能力(事件查询/issue 管理/趋势分析/stack trace 解析)、在各客户端中的配置方式、三个实战场景(线上异常自动排查 / 错误趋势分析报告 / 批量 issue 分类整理),以及与日志分析 MCP 的选型对比和 SaaS 集成安全注意事项。

2026-09-10
#MCP#Sentry
MCP开发

MCP Elicitation 实战:让服务端在缺参数时反向向用户提问——受限 Schema 设计 + 四套客户端配置 + 13 行排查表

写 MCP Server 的人迟早会遇到一个尴尬场景:工具必填参数用户没给,服务端要么猜一个(猜错就出事),要么返回一个干巴巴的「缺少参数 xx」让 Agent 自己去追问(Agent 经常追问得驴唇不对马嘴)。MCP 协议里的 Elicitation 就是为这个场景设计的第三个「反向能力」——服务端可以在执行过程中主动向客户端发起一次提问,由客户端把问题渲染成表单弹给用户,用户填完再回传,全程服务端不需要自己实现任何 UI、不需要存任何凭据。本文讲透它的机制与边界:elicitation/create 请求的完整结构、为什么 requestedSchema 被刻意限制成只支持原始类型(这是安全设计不是能力不足)、用户的三种响应(accept / decline / cancel)各自的语义差异、以及最关键的——为什么不能在 Elicitation 里索取密码和 API Key。含 TypeScript SDK 完整实现(含类型定义与降级路径)、Claude Code / Cursor / VS Code + Copilot / Trae 四套带中文注释的配置、三个实战场景(部署确认 / 缺失参数补全 / 敏感操作二次确认)、与 Sampling / 传统参数校验的选型对比、六条安全注意事项,以及 13 行故障排查表。

2026-10-12
#MCP#Model Context Protocol