Model Context Protocol (MCP) | LangChain4j
LangChain4j 支持使用模型上下文协议 (MCP) 与 MCP 兼容服务器进行通信,这些服务器能够提供和执行工具。关于该协议的通用信息可以在 MCP 网站上找到。
协议规定了两种类型的传输方式,均得到支持:
HTTP
:客户端请求一个服务器发送事件的 SSE 通道,然后通过 HTTP POST 请求发送命令。stdio
:客户端可以将 MCP 服务器作为本地子进程运行,并通过标准输入/输出直接与其通信。
要让你的聊天模型或 AI 服务运行 MCP 服务器提供的工具,需要创建一个 MCP 工具提供程序的实例。
MCP 传输
首先,需要一个 MCP 传输实例。
对于 stdio - 此示例展示如何将服务器作为子进程启动:
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("/usr/bin/npm", "exec", "@modelcontextprotocol/server-everything@0.6.2"))
.logEvents(true) // 仅在希望在日志中看到流量时
.build();
对于 HTTP,需要两个 URL,一个用于启动 SSE 通道,另一个用于通过 POST 提交命令:
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("http://localhost:3001/sse")
.logRequests(true) // 如果希望在日志中看到流量
.logResponses(true)
.build();
MCP 客户端
从传输创建 MCP 客户端:
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
MCP 工具提供程序
最后,从客户端创建 MCP 工具提供程序:
ToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(List.of(mcpClient))
.build();
注意,一个 MCP 工具提供程序可以同时使用多个客户端。如果利用这一点,还可以指定当从特定服务器检索工具失败时工具提供程序的行为 - 通过 builder.failIfOneServerFails(boolean)
方法实现。默认值为 false
,意味着工具提供程序将忽略一个服务器的错误并继续使用其他服务器。如果设置为 true
,任何服务器的失败都将导致工具提供程序抛出异常。
要将工具提供程序绑定到 AI 服务,只需在 AI 服务构建器中使用 toolProvider
方法:
Bot bot = AiServices.builder(Bot.class)
.chatLanguageModel(model)
.toolProvider(toolProvider)
.build();
有关 LangChain4j 中工具支持的更多信息,请参见此处。
日志记录
MCP 协议还定义了服务器向客户端发送日志消息的方式。默认情况下,客户端的行为是将这些日志消息转换并使用 SLF4J 日志记录器进行记录。如果希望更改此行为,有一个名为 dev.langchain4j.mcp.client.logging.McpLogMessageHandler
的接口,作为接收日志消息的回调。如果创建自己的 McpLogMessageHandler
实现,将其传递给 MCP 客户端构建器:
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.logMessageHandler(new MyLogMessageHandler())
.build();
资源
要获取服务器上的 MCP 资源列表,使用 client.listResources()
,如果是资源模板,则使用 client.listResourceTemplates()
。这将返回 ResourceRef
对象列表(或 ResourceTemplateRef
对应列表)。这些对象包含资源的元数据,最重要的是 URI。
要获取资源的实际内容,使用 client.readResource(uri)
,提供资源的 URI。这将返回 ResourceContents
对象列表(单个 URI 上可能有更多资源内容,例如 URI 表示目录时)。每个 ResourceContents
对象表示二进制块或字符串。对于二进制块,使用 resourceContents.asBlob()
访问实际数据,对于文本,使用 resourceContents.asText()
。
通过 Docker 使用 GitHub MCP 服务器
现在,让我们看看如何使用模型上下文协议 (MCP) 以标准化方式将 AI 模型与外部工具桥接。以下示例将通过 LangChain4j MCP 客户端与 GitHub 交互,以获取并总结公共 GitHub 存储库的最新提交。为此,无需重新发明轮子,我们可以使用 MCP GitHub 仓库中提供的现有 GitHub MCP 服务器实现。
这个想法是构建一个 Java 应用程序,通过 Docker 连接到本地运行的 GitHub MCP 服务器,以获取并总结最新提交。该示例使用 MCP 的 stdio 传输机制在 Java 应用程序和 GitHub MCP 服务器之间进行通信。
在 Docker 中打包和执行 GitHub MCP 服务器
要与 GitHub 交互,首先需要通过 Docker 设置 GitHub MCP 服务器。GitHub MCP 服务器通过模型上下文协议提供与 GitHub 交互的标准化接口,支持文件操作、存储库管理和搜索功能。
要为 GitHub MCP 服务器构建 Docker 镜像,需要从 MCP 服务器的 GitHub 仓库获取代码,通过克隆仓库或下载代码实现。然后,导航到根目录并执行以下 Docker 命令:
docker build -t mcp/github -f src/github/Dockerfile .
Dockerfile
设置了必要的环境并安装了 GitHub MCP 服务器实现。构建完成后,镜像将作为 mcp/github
本地可用。
docker image ls
REPOSITORY TAG IMAGE ID SIZE
mcp/github latest b141704170b1 173MB
让我们创建一个名为 McpGithubToolsExample
的 Java 类,使用 LangChain4j 连接到 GitHub MCP 服务器。这个类将:
- 使用 Docker 命令在 Docker 容器中启动 GitHub MCP 服务器(
docker
命令在/usr/local/bin/docker
中可用) - 使用 stdio 传输建立连接
- 使用 LLM 总结 LangChain4j GitHub 存储库的最后 3 次提交
注意:在下面的代码中,我们通过环境变量
GITHUB_PERSONAL_ACCESS_TOKEN
传递 GitHub 令牌。但对于某些不需要身份验证的公共存储库操作,这是可选的。
以下是实现:
public static void main(String[] args) throws Exception {
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.logRequests(true)
.logResponses(true)
.build();
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("/usr/local/bin/docker", "run", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "-i", "mcp/github"))
.logEvents(true)
.build();
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
ToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(List.of(mcpClient))
.build();
Bot bot = AiServices.builder(Bot.class)
.chatLanguageModel(model)
.toolProvider(toolProvider)
.build();
try {
String response = bot.chat("Summarize the last 3 commits of the LangChain4j GitHub repository");
System.out.println("RESPONSE: " + response);
} finally {
mcpClient.close();
}
}
注意:此示例使用 Docker,因此执行
/usr/local/bin/docker
中可用的 Docker 命令(根据操作系统更改路径)。如果希望使用 Podman 而不是 Docker,请相应更改命令。
执行代码
要运行示例,请确保系统上正在运行 Docker。同时,在环境变量 OPENAI_API_KEY
中设置 OpenAI API 密钥。
然后运行 Java 应用程序。您应该会收到总结 LangChain4j GitHub 存储库最后 3 次提交的响应,例如:
以下是 LangChain4j GitHub 存储库中最后三次提交的摘要:
1. **提交 [36951f9](https://github.com/langchain4j/langchain4j/commit/36951f9649c1beacd8b9fc2d910a2e23223e0d93)**(日期:2025 年 2 月 5 日)
- **作者:** Dmytro Liubarskyi
- **消息:** 更新至 `upload-pages-artifact@v3`。
- **详情:** 此次提交将用于上传页面工件的 GitHub Action 更新至版本 3。
2. **提交 [6fcd19f](https://github.com/langchain4j/langchain4j/commit/6fcd19f50c8393729a0878d6125b0bb1967ac055)**(日期:2025 年 2 月 5 日)
- **作者:** Dmytro Liubarskyi
- **消息:** 更新至 `checkout@v4`、`deploy-pages@v4` 和 `upload-pages-artifact@v4`。
- **详情:** 此次提交将多个 GitHub Actions 更新至版本 4。
3. **提交 [2e74049](https://github.com/langchain4j/langchain4j/commit/2e740495d2aa0f16ef1c05cfcc76f91aef6f6599)**(日期:2025 年 2 月 5 日)
- **作者:** Dmytro Liubarskyi
- **消息:** 更新至 `setup-node@v4` 和 `configure-pages@v4`。
- **详情:** 此次提交将 `setup-node` 和 `configure-pages` GitHub Actions 更新至版本 4。
所有提交均由同一位作者 Dmytro Liubarskyi 在同一天完成,重点是将各种 GitHub Actions 更新至新版本。