MCP协议

原理讲解

基础概念

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支持多种运输机制:

  1. Stdio transport
    • 使用标准输入/输出进行通信
    • 适用于本地流程的处理
  1. HTTP with SSE transport
    • 使用服务器范围的事件进行服务器到客户消息
    • 使用 http POST方式发送消息,用于客户到服务器消息

所有运输都使用JSON-RPC 2.0交换消息。有关模型上下文协议消息格式的详细信息,请参见规格

消息类型

MCP具有这些主要消息类型:

  1. 请求期望对方有回应:
interface Request {
  method: string;
  params?: { ... };
}
  1. 结果是对请求的成功响应:
interface Result {
  [key: string]: unknown;
}
  1. 错误表明请求失败:
interface Error {
  code: number;
  message: string;
  data?: unknown;
}
  1. 通知是单向消息,不会期望回复:
interface Notification {
  method: string;
  params?: { ... };
}

生命周期

初始化

  1. 客户以协议版本和功能发送initialize请求
  2. 服务器响应其协议版本和功能
  3. 客户将initialized通知发送为确认
  4. 正常消息交换开始

  1. init client, connect server
  2. init model, get tools, query, tool call
  3. tool result -> model
  4. model summary

尝试使用

通过mcp工具读取本地文件内容

  1. clone 官方提供的mcp服务项目:
git clone git@github.com:modelcontextprotocol/servers.git
  1. 构建本地服务:
docker build -t mcp/filesystem -f src/filesystem/Dockerfile .

  1. 镜像构建完成后, 采用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服务器

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值