模型上下文协议(MCP)的理解

0 引言

刚接触MCP协议时,作者感觉听抽象的,难以理解,所以想着记录一篇MCP协议的简单理解版本,简单代码+文字的方式梳理一遍整个协议,希望给刚刚学习MCP协议的读者们一个快速并且易懂的MCP协议解析版本,快速入门,如果存在理解不对的地方,随时可以找作者讨论修改!

1 定义

模型上下文协议(Model Context Protocol)是一种标准化的大模型工具管理框架,用于统一工具的定义、注册、发现、调用等功能;

2 协议架构

协议主要存在三种架构:Host / Client / Server, 接下来分别介绍**:**

2.1 Host

MCP Host可以看作是用户可以直接交互程序应用,比如各种AI助手等;

Host的主要功能:

1)基础功能:接收用户的prompt以及调用大模型对prompt进行响应;

2)与MCP相关功能:根据大模型指令通过MCP client调用工具;

2.2 Client

MCP Client是Host内部的通信组件的同时又负责和Server交互

Client的主要功能:

1)可以通过Host调用Client与Server交互;

2)可以和Server建立连接,发送请求以及接收响应等;

2.3 Server

MCP Server主要作用是存储具体的调用工具的具体信息,以及工具的具体执行,随后返回结果给Client

2.4 Host / Client / Server 三者联系

Host可以连接多个Client ,但是每一个Client都只负责连接一个Server

3 核心能力

MCP的架构介绍完毕,接下来介绍MCP的三大核心功能:Tools/Resouces/Prompts

3.1 Tools--工具调用

我们回忆一下,如果使用普通的生成式大模型,它的特点是只能使用语言对你的问题进行回答,而不能进行调用接口来执行某些具体操作 ,例如帮我获取用户"小林学编程"的CSDN简介,这个问题就不再是一个可直接回答的问题,是需要具体访问CSDN的网站,来获取相关信息,所以为了给大模型补足这一缺点,诞生了Function Call,Function Call的本质就是模型会根据你的问题,让大模型回答应该调用某些工具来执行。

ps:具体的执行在你的应用程序,大模型只是返回你需要执行的工具以及相关输入参数;

给一个Function Call的例子:


Host 与大模型第一轮交互

1)Host拼接prompt = "获取用户"小林学编程"的CSDN简介内容" + 所定义工具列表(包含每个工具有名字、描述、参数定义)

2)大模型根据输入分析出需要使用访问网页相关工具执行,大模型的输出 = 访问网页的工具名称以及相关需要输入的参数;(例如:分析出需要使用访问网页的工具,输入参数是(网页URL,用户名))


Host 与大模型第二轮交互

Host 需要拦截第一次大模型输出,并解析需要调用的工具是什么,输入参数是什么,然后再本地寻找相关工具,执行并返回执行结果;

1)Host输入prompt = "获取用户"小林学编程"的CSDN简介内容" + 所定义工具列表(包含每个工具有名字、描述、参数定义) + "简介内容是XXXX"(也就是调用工具后的输出结果);

2)大模型得到相关内容后返回最终答案:"小林学编程的简介内容是XXXXXXXXX";

Function Call就是定义了大模型可以通过意图识别以及输入的工具列表,输出相关工具的调用逻辑,让Host执行这个工具后,再次与大模型交互,最终输出给用户答案;

Function Call内容理解后,就可以描述MCP的tools功能了!!

MCP的tools能力主要是在Function Call 之上,提供一层标准化的管理框架;

也就是说Function Call所需要定义的工具从Host端,被转移到了MCP Server进行存储,实现了跨语言系统的互通; 给一个例子,例如你的一些工具使用Java语言定义,如果你的应用程序Host使用python代码写的,那么Java定义的工具就没办法使用!!

加上MCP协议后就相当于封装了一层统一访问协议,如果存在这样的结构:使用Java写的Host存在两个Client1/Client2,分别连接Server1/Server2,Server1/Server2分别存储由Java以及Python写的工具,那么Host可以及访问JAVA以及Python写的工具,而不单单只能访问Java写的工具了!!!!

PS:Client初始化时自动从相关Server获取工具列表,然后host端就可以获取所有工具,并拼接进第一次与大模型交互的prompt中;

3.2 Resouces--资源

Resouces是MCP提供的第二种能力,和tools一样也是存储于Server中,但是作用是让Server提前暴露数据给大模型;

我的理解就是提前提供一点基础信息给host端,减少对tools的依赖,也就是说节省一部分大模型调用的损耗

举一个例子:当用户需要开启对话时,host端其实可以获取到用户ID,然后可以通过Client向Server请求围绕着用户ID的定义的Resouces,例如

java 复制代码
public void BaseToChat(String userId) {
    String level = mcpClient.readResource("customer://users/" + userId + "/level");
    String sex = mcpClient.readResource("customer://users/" + userId + "/gender");

    String context = level + "\n" + gender;
    LLM(systemPrompt, context, userMessage);
}

我们通过Client获取Server中的定义的Resouces,通过输入Server需要执行的URL+用户ID拼接,Server会访问这些URL(最重要的一点Server已经定义了相关Resouces了,才能匹配),并执行相关代码,来提前获取这个用户ID下的会员等级以及性别;

随后通过组装prompt输入给大模型,这样的话,如果存在这些相关问题的提问(我的会员等级是多少?),就省去了大模型返回调用工具的一轮了,直接输出结果就好;

直观一点看就是,当用户提问我的会员等级是多少?:

1)使用Resouces;

提前获取Server资源相关信息后,prompt = "我的会员等级是多少 + 会员等级:XX;性别:XX"--大模型根据提示词可以直接返回结果:您的会员等级为XX;

2)使用tools:

prompt = "我的会员等级是多少" + 工具列表--大模型判断需要调用会员等级工具--prompt = "我的会员等级是多少" + 工具列表 + 调用工具输出的结果"会员等级:XX' --大模型根据提示词可以直接返回结果:您的会员等级为XX;

很明显看出省略了访问大模型的一步!!!减少了额外的推理以及调用延迟;

3.3 Prompt--提示词模板

与前两者相似,prompt也是存储于Server中,可以使得多client共用一份prompt,一般使用场景为作为一开始的System message的封装 或者文档摘要生成等模板化prompt;例如作为prompt封装的消息:

java 复制代码
String userMessage = String.format("""
                你是一个企业知识库助手。请严格遵守以下规则:

                【回答规则】
                1. 只基于「参考资料」中的内容回答,不要使用你自己的知识。
                2. 如果参考资料中没有相关信息,请回答:抱歉,我在知识库中没有找到相关信息,建议您联系人工客服获取帮助。
                3. 不要编造、推测或补充参考资料中没有的细节。

                【引用规则】
                1. 回答中引用参考资料时,使用 [编号] 标注来源,例如 [1]、[2]。
                2. 只引用你实际使用的片段,不要空挂引用。
                3. 如果多个片段支持同一个观点,可以同时引用,例如 [1][2]。

                【格式要求】
                1. 先给结论,再给详细解释。
                2. 使用简洁的中文回答。
                3. 如果信息有冲突,以更新时间较近的片段为准。

                参考资料:
                %s

                问题:%s
                """, context, question);

代码中存在的**%s** 就是host借助client向server发送prompt的请求时需要携带的输入参数;

4 结论

1)MCP协议的三层架构为Host/Client/Server,分别负责与大模型交互/与Server交互/执行命令后返回结果;

2)MCP协议的三种核心功能Tools/Resouces/Prompts,Tools与Resouces之间的区别关键,是否是只读操作(例如通过用户ID读取会员等级--就是一个只读操作),若是只读操作可以封装成Resouces进行使用,减少与大模型的交互次数;若还需要一些写操作(如用户想下订单,需要修改数据库等数据),就封装为tools进行使用;

3)Tools/Resouces/Prompts的封装都位于Server中,等待Client的调用 ,体现了MCP的统一调度能力,即不同语言编写的Host,也可以复用其他语言编写的Tools/Resouces/Prompts;

相关推荐
软泡芙3 小时前
【Bug】ReactiveUI WPF绑定中依赖属性不更新的问题分析与解决方案
java·bug·wpf
小程故事多_803 小时前
Harness实战指南,在Java Spring Boot项目中规范落地OpenSpec+Claude Code
java·人工智能·spring boot·架构·aigc·ai编程
浪扼飞舟3 小时前
WPF输入验证(ValidationRule)
java·javascript·wpf
砍材农夫8 小时前
spring-ai 第四多模态API
java·人工智能·spring
她说..10 小时前
Java 对象相关高频面试题
java·开发语言·spring·java-ee
土豆125010 小时前
LangGraph TypeScript 版入门与实践
人工智能·llm
庞轩px11 小时前
深入理解 sleep() 与 wait():从基础到监视器队列
java·开发语言·线程··wait·sleep·监视器
土豆125011 小时前
OpenSpec:让 AI 编码助手从"乱猜"到"照单执行"
人工智能·llm
小码哥_常11 小时前
Spring Boot 中JWT登录授权+无感刷新,看这篇就够了!
后端