原理讲解
基础概念
Introduction - Model Context Protocol
- MCP Host:想要通过 MCP 访问数据的程序,例如 Claude Desktop、IDE 或 AI 工具
- MCP Clients:与服务器保持 1:1 连接的协议客户端
- MCP Servers:轻量级程序,每个程序通过标准化模型上下文协议公开特定功能
- Local Data Sources: MCP 服务器可以安全访问的计算机文件、数据库和服务
- Remote Services: MCP 服务器可以通过互联网(例如,通过 API)连接的外部系统
核心组件
协议层
协议层处理消息框架,请求/响应链接和高级通信模式。
class Protocol<Request, Notification, Result> {// Handle incoming requests, 处理请求setRequestHandler<T>(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise<Result>): void// Handle incoming notifications, 处理通知, 不需要对方响应的请求setNotificationHandler<T>(schema: T, handler: (notification: T) => Promise<void>): void// Send requests and await responses, 请求request<T>(request: Request, schema: T, options?: RequestOptions): Promise<T>// Send one-way notifications, 通知notification(notification: Notification): Promise<void>
}
传输层
运输层处理客户与服务器之间的实际通信。 MCP支持多种运输机制:
- Stdio transport
-
- 使用标准输入/输出进行通信
- 适用于本地流程的处理
- HTTP with SSE transport
-
- 使用服务器范围的事件进行服务器到客户消息
- 使用 http POST方式发送消息,用于客户到服务器消息
所有运输都使用JSON-RPC 2.0交换消息。有关模型上下文协议消息格式的详细信息,请参见规格。
消息类型
MCP具有这些主要消息类型:
- 请求期望对方有回应:
interface Request {method: string;params?: { ... };
}
- 结果是对请求的成功响应:
interface Result {[key: string]: unknown;
}
- 错误表明请求失败:
interface Error {code: number;message: string;data?: unknown;
}
- 通知是单向消息,不会期望回复:
interface Notification {method: string;params?: { ... };
}
生命周期
初始化
- 客户以协议版本和功能发送
initialize
请求 - 服务器响应其协议版本和功能
- 客户将
initialized
通知发送为确认 - 正常消息交换开始
- init client, connect server
- init model, get tools, query, tool call
- tool result -> model
- model summary
尝试使用
通过mcp工具读取本地文件内容
- clone 官方提供的mcp服务项目:
git clone git@github.com:modelcontextprotocol/servers.git
- 构建本地服务:
docker build -t mcp/filesystem -f src/filesystem/Dockerfile .
- 镜像构建完成后, 采用
LangChain4j
进行测试用例构建:
package dev.langchain4j.example.mcp;import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolProvider;import java.io.File;
import java.util.List;public class McpToolsExampleOverStdio {// We will let the AI read the contents of this file/*** This example uses the `server-filesystem` MCP server to showcase how* to allow an LLM to interact with the local filesystem.* <p>* Running this example requires npm to be installed on your machine,* because it spawns the `server-filesystem` as a subprocess via npm:* `npm exec @modelcontextprotocol/server-filesystem@0.6.2`.* <p>* Of course, feel free to swap out the server with any other MCP server.* <p>* The communication with the server is done directly via stdin/stdout.* <p>* IMPORTANT: when executing this, make sure that the working directory is* equal to the root directory of the project* (`langchain4j-examples/mcp-example`), otherwise the program won't be able to find* the proper file to read. If you're working from another directory,* adjust the path inside the StdioMcpTransport.Builder() usage in the main method.*/public static void main(String[] args) throws Exception {ChatLanguageModel model = OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).baseUrl(System.getenv("OPENAI_API_URL")).modelName("gpt-4o-mini").logRequests(true).logResponses(true).build();McpTransport transport = new StdioMcpTransport.Builder().command(List.of("docker", "run", "-i", "--rm","--mount", "type=bind,src=/Users/louye/fun-project/langchain4j-examples/mcp-example/src/main/resources,dst=/projects","mcp/filesystem","/projects")).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("修改文件 /projects/file.txt 的内容, 将内容修改为: Hello, world!");System.out.println("RESPONSE: " + response);} finally {mcpClient.close();}}
}
参考文档: https://github.com/modelcontextprotocol/servers/blob/main/src/filesystem/README.md
实际上McpTransport
就是帮用户通过特定的命令进行启动MCP的server服务器