Model Context Protocol (MCP) 正在改变我们构建软件的方式。它提供了大型语言模型(LLM)与现实世界交互的"API"。这让AI代理能够查询数据库、读取文件或调用第三方服务。这种新能力带来了新的挑战。MCP服务器(AI使用的后端工具)并非传统的微服务。它们的"用户"是一个非确定性的AI,并且它们通常需要访问敏感系统。
我们如何可靠地构建、部署和保护这些服务器?清晰的答案是Docker。整个MCP生态系统,包括Docker自己的MCP工具包和目录,都围绕容器化构建。在Docker中运行你的MCP服务器不仅是一个好主意;它是必要的最佳实践。本文涵盖了构建生产就绪的Docker化MCP服务器的五个关键原则。
1. 容器化所有内容以实现隔离与可移植性
你首要且最重要的规则是:MCP服务器应该始终是一个Docker镜像。永远不要将其作为原始脚本在主机机器上运行。这样做的原因归结为两个关键因素:隔离和可移植性。
构建服务时,安全性至关重要。AI代理可能是不可预测的。一个恶意提示可能会诱骗它用危险的输入调用你的工具。如果你的pdf-reader工具存在漏洞,你肯定不希望它拥有与你的aws-s3-uploader相同的用户权限运行。Docker容器创建了一个安全的环境,将服务器的进程、文件系统和网络隔离开来。
可移植性解决了"在我机器上能运行"的问题。你基于Python的Postgres服务器和基于Node.js的GitHub服务器具有不同且冲突的依赖项。Docker将服务器及其所有依赖项打包成一个单一的、可移植的包,在任何地方都能以相同的方式工作。
2. 遵循单一职责原则
给定的MCP服务器本质上是一个微服务,应该遵循最好的微服务架构,即单一职责原则。对于MCP来说,这意味着每个逻辑域对应一个服务器。
避免创建连接GitHub、Postgres和Stripe的庞大"全能服务器"。相反,应该构建更小、更专注的服务器,例如 mcp-github-server、mcp-database-server 和 mcp-billing-server。
这种方法有两个主要好处。首先,它提高了安全性。你可以应用"最小权限"模型。GitHub服务器获得一个只读令牌,并且没有网络访问你的数据库的权限。即使它被攻破,影响也有限。其次,它提供了清晰性。对于LLM来说,与"数据库"服务器提供的一小组特定工具协作,远比从长达50个不同函数的列表中挑选正确的工具要容易得多。
3. 编写"AI优先"的工具描述
你工具描述中的"用户"指的是AI代理,而不是人类开发者。你的目标应该是确保清晰的理解,而不是巧妙地简洁。大型语言模型缺乏人类的"常识"。它无法推断你的意图。它完全依赖你工具定义中的字符串描述和JSON模式来理解工具的作用、参数的含义以及何时使用它。
不清晰 ❌:
为什么不好 ❌: “JH"是什么?它获取多少个问题,一个还是多个?它使用什么标识符来获取?这会混淆LLM,它只能猜测。
好的命名 ✅:
为什么好 ✅:
description: "该命令从指定的仓库获取GitHub问题的完整详尽细节,包括标题、正文、作者和标签。使用此工具需要完整的仓库名称和数字问题编号。"
“好"的例子很啰嗦,但对LLM来说是理想的。它清楚地解释了做什么(“获取完整细节”)、返回什么(“标题、正文、作者、标签”)以及需要什么(“完整的仓库名称”、“数字问题编号”)。这大大提高了"命中率”,即代理成功使用你工具的机会。
4. 强化你的Docker镜像
你正在构建一个AI可以根据需要随时调用的服务。这带来了新的安全风险。你的Docker镜像是你的第一道防线,因此它必须是安全的。如果攻击者发现你服务器代码中的弱点,你的镜像强化措施应该让他们没有工具来加强攻击。
为实现此目的,请使用最小的基础镜像,如distroless或Alpine,它们不包含shell或包管理器。确保始终以”非root用户“运行应用程序/服务,在Dockerfile中使用USER指令。获得访问权限的攻击者将没有root权限。
最后,使用多阶段构建,仅将最终的应用工件复制到你的生产镜像中。这将留下构建工具、源代码和编译器。在你的CI/CD流水线中集成漏洞扫描器,例如Docker Scout。这将自动扫描你的镜像以查找已知漏洞,并在发现严重问题时使构建失败。
5. 像测试真实服务一样测试,而非模拟
使用模拟的单元测试可能很脆弱,并且常常不能真实反映实际行为。对于MCP服务器,集成测试是必要的。在容器化环境中进行集成测试的最佳方式是使用Testcontainers。
Testcontainers是一个库,允许你的测试代码以编程方式启动和停止任何Docker容器。你的pytest或JUnit测试不是模拟数据库,而是可以启动一个真实的、临时的Postgres容器在一个随机端口上。
然后你的测试启动你的mcp-database-server(同样作为一个容器),并将其配置为连接到此临时数据库。它还充当MCP客户端来调用你的query_users工具。然后你可以检查是否从真实数据库收到了真实数据。测试完成后,Testcontainers会自动删除两个容器。这种详细的测试可以捕获连接字符串、SQL语法和权限方面的真实错误,而这些错误是模拟测试会遗漏的。
结论
为AI优先的世界构建需要新的规范。将你的MCP服务器视为一流的、容器化的微服务。遵循这五个实践:容器化所有内容、拥抱单一职责、编写AI优先的描述、强化你的镜像以及使用Testcontainers进行验证。这种方法将为下一代AI驱动的应用程序创建一个坚实、生产就绪的基础。