AI在线 AI在线

简述MCP的原理-AI时代的USB接口

1 简介2 执行流程3 mcp架构3.1 mcp架构设计3.2 mcp基本功能4 mcp通信原理4.1 JSON-RPC4.2 通信方式5 生命周期5.1 环境搭建5.2 建立连接获取可用工具列表5.3 调用工具6 总结1.简介随着AI的不断发展,RAG(检索增强生成)和function calling等技术的出现,使得大语言模型的对话生成能力得到了增强。 然而,function calling的实现逻辑比较复杂,一个简单的工具调用和实现方式需要针对不同的系统和大模型单独编写适配接口,十分复杂。 在此背景下,mcp应运而生,为当前业内AI高效可靠地调用外部工具实现了标准化。
  • 1 简介
  • 2 执行流程
  • 3 mcp架构

3.1 mcp架构设计

3.2 mcp基本功能

  • 4 mcp通信原理
  • 4.1 JSON-RPC
  • 4.2 通信方式
  • 5 生命周期
  • 5.1 环境搭建
  • 5.2 建立连接获取可用工具列表
  • 5.3 调用工具
  • 6 总结

1.简介

随着AI的不断发展,RAG(检索增强生成)和function calling等技术的出现,使得大语言模型的对话生成能力得到了增强。然而,function calling的实现逻辑比较复杂,一个简单的工具调用和实现方式需要针对不同的系统和大模型单独编写适配接口,十分复杂。

在此背景下,mcp应运而生,为当前业内AI高效可靠地调用外部工具实现了标准化。下面,我将带大家一起认识下mcp的基本原理和实现方式。

2.执行流程

在我们开始今天的正题之前,需要先了解下通常用户与大模型进行一次交互的执行流程:↓

图片图片

当用户问“北京今天天气怎么样”时,我们的程序会将用户的问题、以及预先识别到的工具列表包装成提示词发送给大模型。熟悉function calling原理的小伙伴们都知道,这时候大模型会基于预训练的function calling技术识别到想要调用的工具是什么,并将其结构化输出。我们的程序识别后再去调用对应的工具,最后将得到的结果和之前的上下文再次发送给大模型,得到最终的结果返回给用户。当然,如何让大模型选择要调用的工具不是本期的重点,这里不再赘述。

我们需要关注重点在于工具调用的这部分逻辑,在mcp没有诞生之前是这样子调用的:

图片图片

每次新增一个系统,都需要开发者单独做适配,即使tool的功能很简单,也会有极大的重复开发量。 在mcp出现后,调用方式发生了变化:

图片图片

系统与工具的调用方式实现了解耦,调用逻辑统一封装到了mcp client和 mcp server之间,这一步的交互方式由官方提供了不同开发语言的sdk,不再需要我们开发者处理了。

3.mcp架构

3.1 mcp架构设计

接下来让我们详细看下mcp的架构设计,mcp实现采用了标准的C/S架构模式。

图片图片

host:用于承载接受用户请求,与大模型交互,调用工具的一段程序。广义上我们可以将其看作是一个AI Agent。

client: 基于mcp规则实现的客户端,负责与mcp服务端进行通信。

server: 基于mcp规则实现的服务端,实现了工具内部的逻辑操作,并将执行结果返回给mcp客户端。

3.2 mcp基本功能

当下主流的与大模型交互的三要素无非是:工具、资源、提示词,而mcp针对这三类均做了标准化处理。 以下是几个重要的功能:

  • Resource:类似文件的数据,可以被客户端读取,如数据库数据或文件内容。
  • Tools:可以被大模型调用的函数。
  • prompt:预先编写的模板,帮助用户完成特定任务。
  • sampling:允许server主动通过client调用大模型获取数据进行采样。

4.mcp通信原理

4.1 JSON-RPC

MCP采用JSON-RPC作为底层的通信协议。JSON-RPC是一种基于JSON的轻量级远程调用协议,相较于HTTP来说它更加简洁、高效、容易处理。

请求结构体

复制
{
  jsonrpc: "2.0",
  id: number | string,
  method: string,
  params?: object
}

响应结构体

复制
{
  jsonrpc: "2.0",
  id: number | string,
  result?: object,
  error?: {
    code: number,
    message: string,
    data?: unknown
  }
}

在发起通信的源码中我们也可以看到确实使用到了json-rpc

复制
@Override
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
  String requestId = this.generateRequestId();

return Mono.<McpSchema.JSONRPCResponse>create(sink -> {
   this.pendingResponses.put(requestId, sink);
   // 构建json-rpc请求
   McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, method,requestId, requestParams);
            // 发送请求
   this.transport.sendMessage(jsonrpcRequest)
    .subscribe(v -> {}, error -> {
     this.pendingResponses.remove(requestId);
     sink.error(error);
    });
  }).timeout(this.requestTimeout).handle((jsonRpcResponse, sink) -> {
            // 省略异常处理
  });
 }

json-rpc与http的对比

属性

HTTP

JSON-RPC

本质

应用层协议(Web核心协议)

轻量级RPC协议(基于JSON格式)

数据格式

支持JSON/XML/二进制等多种格式

强制JSON格式,结构更简洁

协议功能

包含缓存/认证/状态码等完整功能

仅定义RPC调用规范(无底层逻辑)

通信模式

无状态,支持GET/POST等多方法

无状态,基于method字段调用

适用场景

Web API、浏览器交互、复杂业务

微服务内部调用、物联网等轻量场景

典型应用

RESTful接口、网页加载

服务间函数调用、嵌入式设备通信

4.2 通信方式

mcp基于以上通信协议,实现了以下通信方式:

STDIO

采用STDIO的方式,server端会在client端启动时,作为client端的子进程一起启动。这种方式适用于client和server在同一台机器上通信的场景,通常用于工具调试。 它的实现原理是client和server两个进程间通过stdin和stdout进行双向通信。

优点:

  • 无外部依赖
  • 进程间通信极快
  • 脱机可用

缺点

  • 并发能力差,是同步阻塞模型
  • 不支持多进程通信

SSE

全名是server send event,是一种基于服务端到客户端的流式传输方式,同时客户端向服务端通信采用http的方式进行传输。一般用于client在本地,server在远程服务器的场景。

图片图片

具体执行流程如下:

  • 客户端会向服务端的/sse端点发送http请求,服务端会返回sessionID等信息建立sse连接。
  • 初始化连接完成后,客户端会向服务端请求tools/list接口获取所有的tool列表,用于之后发送给大模型。
  • 在工具调用时,客户端会将调用信息如method,args通过post请求调用tools/call接口发送给服务端处理,服务端通过sse连接通知客户端结果。

从本质上看,sse是一种异步非阻塞的通信模型,极大的提高了agent的吞吐能力,但其服务器和客户端需要做长连接容易连接中断,会丢失上下文。而官方在今年又推出了一项通信方式的更新,使用streamable http替代sse解决了以上的问题。

5.生命周期

以下是mcp的生命周期:

图片图片

在mcp client和mcp server建立连接后,client会立即向server请求获取可用的工具列表,这里也体现了mcp工具的动态可插拔性。 接下来我将用Spring AI带大家一起了解下mcp client的调用流程。

我们需要引入Spring AI的maven依赖,以及对spring AI对Mcp的依赖。

5.1 环境搭建

我们需要在server端向外暴露一个工具。

复制
/** 构建根据城市获取天气的tool
     * @param city 城市名称
     * @return 天气信息
     */
    @Tool(name = "getWeather", description = "根据城市获取天气")
    public String getWeather(String city) {
        return new String((city).getBytes(), StandardCharsets.UTF_8) + " 天气为晴天 25℃";
    }

SpringAi会将标有@Tool注解的方法自动注入到ToolCallbackProvider中。 在client端,我们需要配置下mcp server的地址。

复制
spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            server1: # sse服务端
              url: http://127.0.0.1:8080

写一个demo来模拟用户询问大模型的流程。

复制
@Bean
    public CommandLineRunner callToolByLLM(ChatClient.Builder chatClientBuilder,
                                                 ToolCallbackProvider toolCallbackProvider,
                                                 ConfigurableApplicationContext context) {

        return args -> {
            System.out.println("基于spring-ai,llm调用方法------");
            Gson gson = new Gson();
            // 模拟用户输入的信息,并把工具列表传给LLM
            String userInput = "获取北京的天气";
            System.out.println("用户问: " + userInput);
            var chatClient = chatClientBuilder
                    .defaultUser("获取北京的天气")
                    .defaultTools(toolCallbackProvider)
                    .build();
            // 包装请求LLM
            String content = chatClient.prompt(userInput).call().content();
            System.out.println("AI回答: " + gson.toJson(content));
            // 结束会话
            context.close();
        };
    }

5.2 建立连接获取可用工具列表

当程序启动后,spring会自动注入McpClient和ToolCallbackProvider,此时会向server端发送请求获取所有可用的工具列表。

复制
public class SyncMcpToolCallbackProvider implements ToolCallbackProvider {
    @Override
    public ToolCallback[] getToolCallbacks() {

        var toolCallbacks = new ArrayList<>();

        this.mcpClients.stream().forEach(mcpClient -> {
            // mcpClient.listTools()
            toolCallbacks.addAll(mcpClient.listTools()
                    .tools()
                    .stream()
                    .filter(tool -> toolFilter.test(mcpClient, tool))
                    .map(tool -> new SyncMcpToolCallback(mcpClient, tool))
                    .toList());
        });
        var array = toolCallbacks.toArray(new ToolCallback[0]);
        validateToolCallbacks(array);
        return array;
    }
}

mcpClient会用json-rpc的格式调用tools/list方法,获取当前server下所有可用的工具列表。

复制
public Mono<McpSchema.ListToolsResult> listTools(String cursor) {
    return this.withInitializationCheck("listing tools", initializedResult -> {
        if (this.serverCapabilities.tools() == null) {
            return Mono.error(new McpError("Server does not provide tools capability"));
        }
        return this.mcpSession.sendRequest(McpSchema.METHOD_TOOLS_LIST, new McpSchema.PaginatedRequest(cursor),
                LIST_TOOLS_RESULT_TYPE_REF);
    });
}

5.3 调用工具

当用户询问"北京今天天气怎么样"时,程序会将上述获取到的所有工具和用户的信息生成提示词告诉大模型,大模型选择一个合适的工具告诉程序去调用工具。

复制
public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse) {

        // 构建提示词、工具
        ChatCompletionRequest request = createRequest(prompt, false);
        // 构建要调用的大模型信息
        ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
                .prompt(prompt)
                .provider(OpenAiApiConstants.PROVIDER_NAME)
                .requestOptions(prompt.getOptions())
                .build();

        ChatResponse response = ChatModelObservationDocumentation.CHAT_MODEL_OPERATION
                .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
                        this.observationRegistry)
                .observe(() -> {
                    // post请求大模型Api
                    ResponseEntity<ChatCompletion> completionEntity = this.retryTemplate
                            .execute(ctx -> this.openAiApi.chatCompletionEntity(request, getAdditionalHttpHeaders(prompt)));
                    // 解析结果省略步骤 ...
                    return chatResponse;
                });

        // 判断是否是工具调用
        if (toolExecutionEligibilityPredicate.isToolExecutionRequired(prompt.getOptions(), response)) {
            var toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, response);
            // 判断是否返回结果
            if (toolExecutionResult.returnDirect()) {
                // Return tool execution result directly to the client.
                return ChatResponse.builder()
                        .from(response)
                        .generations(ToolExecutionResult.buildGenerations(toolExecutionResult))
                        .build();
            }
            else {
                // 带着工具结果直接调用
                returnthis.internalCall(new Prompt(toolExecutionResult.conversationHistory(), prompt.getOptions()),response);
            }
        }
        return response;
    }

这里我们对大模型返回的结果进行抓包,可以看到大模型想要调用的方法信息

复制
[
    {
        "assistantMessage": {
            "toolCalls": [
                {
                    "id": "call_b4a9cb0f04a3495d941b71",
                    "type": "function",
                    "name": "spring_ai_mcp_client_server1_getWeather",
                    "arguments": "{\"city\": \"北京\"}"
                }
            ],
        // 中间内容省略...
        "chatGenerationMetadata": {
            "metadata": {},
            "finishReason": "TOOL_CALLS",
            "contentFilters": []
        }
    }
]

mcpClient执行调用逻辑。

复制
public Mono<McpSchema.CallToolResult> callTool(McpSchema.CallToolRequest callToolRequest) {
  return this.withInitializationCheck("calling tools", initializedResult -> {
   if (this.serverCapabilities.tools() == null) {
    return Mono.error(new McpError("Server does not provide tools capability"));
   }
   return this.mcpSession.sendRequest(McpSchema.METHOD_TOOLS_CALL, callToolRequest, CALL_TOOL_RESULT_TYPE_REF);
  });
 }

执行完成后,程序会携带结果和上下文再次请求大模型获取结果,直到大模型认为可以结束了,会将最终的结果返回给用户。 此次请求的执行结果如下:

图片图片

6.总结

本文介绍了mcp的基本底层原理,mcp作为AI大模型时代的标准化交互协议,具备显著的优势。对于开发者来说mcp的出现降低了功能集成的成本,有更大的发展前景。但mcp当下也有很多不可回避的缺点,比如频繁与大模型交互,为了保证消息连贯上下文内容剧增,token消耗大,使用成本变高。另外在安全性方面不够健全,对于提示词注入等手段没有成熟的解决方案。

尽管mcp当前不是那么的完美无缺,但他的出现给AI的发展提供了一种全新的交互模式和更多的可能。

关于作者

张皓昱,转转门店后端开发工程师

相关资讯

手把手教你找免费AI服务:搜公开的DeepSeek模型接口

网上很多教程教你怎么自己搭 AI 模型,但今天我要教大家一个野路子——用搜索引擎直接找别人已经搭好的 AI(Ollama)服务(前提是合法使用)。 就像有人忘记关 Wi-Fi,我教你怎么发现这些"公共资源"。 一、用 Fofa 找公开的 AI 服务Fofa 是什么?
2/14/2025 12:00:00 AM
wayn

马斯克脑机接口公司Neuralink高层动荡:联合创始人兼总裁离职,曾想建侏罗纪公园

马克斯 · 霍达克的离职会对 Neuralink 的未来发展造成什么影响呢?埃隆 · 马斯克又会选择谁来接任总裁一职呢?这些我们都拭目以待吧!
5/3/2021 12:06:00 PM
机器之能

大语言模型做数据助手,浙大Data-Copilot高效调用、处理、可视化数据

Data-Copilo:大型语言模型,做你最贴心省事的数据助手。
6/26/2023 2:18:00 PM
机器之心
  • 1