MCP协议从原理到开发:一文读懂大模型交互的标准化革命!

1、什么是 MCP

1.1 MCP 介绍

MCP(Model Context Protocol,模型上下文协议) 起源于 2024 年 11 月 25 日 Anthropic 发布的文章:Introducing the Model Context Protocol。

可以用“AI 扩展坞”来比喻 MCP 在 AI 领域的作用。就像现代扩展坞可以连接显示器、键盘、移动硬盘等多种外设,为笔记本电脑瞬间扩展功能一样,MCP Server 作为一个智能中枢平台,能够动态接入各类专业能力模块(如知识库、计算工具、领域模型等)。当 LLM 需要完成特定任务时,可以像"即插即用"般调用这些模块,实时获得精准的上下文支持,从而实现能力的弹性扩展。这种架构打破了传统 AI 模型的封闭性,让大语言模型像搭载了多功能扩展坞的超级工作站,随时都能获取最合适的专业工具。

img

1.2 为什么要有 MCP

终结工具调用碎片化

不同模型在定义 Function Call(函数调用)时,采用的结构和参数格式各不相同,使得对多模型集成、统一管理和标准化接入变得复杂而繁琐。

属性维度OpenAIClaudeGeminiLLaMA
调用结构名称tool_callstool_usefunctionCallfunction_call
参数格式JSON字符串JSON对象JSON对象JSON对象
特殊字段finish_reason字段包含id和``args字段命名与OpenAI结构相似

img

对于开发者来说,针对不同模型去实现不同的工具调用方法,所谓的定制化开发不仅消耗大量时间和资源,而且维护也变得困难。

而 MCP 作为一种 AI 模型的标准化接入协议,能够显著简化模型之间的集成。

实现多功能应用与创新体验的突破

MCP 的潜力不仅限于连接现有工具,它还在推动客户端应用向“万能应用”演进,并创造全新的用户体验。

以代码编辑器 Cursor 为例,作为 MCP 客户端,用户可以通过集成不同的 MCP 服务器,将其转变为具备 Slack 消息收发、邮件发送(Resend MCP)、甚至图像生成(Replicate MCP)等多种功能的综合工作站。

更具创造力的是,在单一客户端中组合多个 MCP 服务器可以解锁复杂的新流程。例如,AI 代理可以一边生成前端界面代码,一边调用图像生成服务器为主页创作视觉元素。这种模式超越了传统应用的单一功能限制,为用户带来多样化的操作体验。

2、MCP Server 开发

MCP server 是 MCP 架构中的关键组件,目前提供 3 种主要类型的功能,

  • 资源(Resources):类似文件的数据,可以被客户端读取,如 文件内容。
  • 工具(Tools):可以被 LLM 调用的函数。
  • 提示(Prompts):预先编写的prompt模板,帮助用户完成特定任务。

还有其他两种(samping 和 roots)但是目前还没被很好的支持。

img

以开发一个企业微信机器人 mcp server 为例,用到的是社区sdk typescript-sdk 。(https://github.com/modelcontextprotocol/typescript-sdk)

2.1 项目搭建开发

可以参考官方 quickstart(https://modelcontextprotocol.io/quickstart/server)

环境:nodejs > v16 (我用的是 v22.6)

npm init -y

# Install dependencies
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
mkdir src
touch src/index.ts
创建 mcp-server 实例
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
export const server = new McpServer({ 
     name: "wechat-mcp-server",  
     version: "0.0.1",
     });

可以直接使用 sdk 封装好的 McpServer 函数。

创建 tools 工具

定义 mcp 提供给 client 或者 llm 使用的工具,企业微信机器人主要就是 发送文本、发送 markdown、发送图片等等,这里我们举例一个发送文本的工具实现

text.ts
// Helper function for sending WeChat messages
export async function sendWeChatTextMessage(webhookKey: string, content: string, chatid: string = 
"@all_group", mentioned_list?: string[], mentioned_mobile_list?: string[], visible_to_user?: string):
 Promise<boolean> {
   const WECHAT_API_BASE = ` http://in.qyapi.wbin/webhook/send?key=${ webhookKey}`;  
   const headers = {  
       "Content-Type": "application/json",  };      
       const body = JSON.stringify({     
         "msgtype": "text",     
          "text": {        
               "content": content,             
               "mentioned_list": mentioned_list,            
                "mentioned_mobile_list": mentioned_mobile_list  
    },      
     "chatid": chatid,       
     "visible_to_user": visible_to_user ? visible_to_user.split('|') : undefined 
       });    
         try {   
             const response = await fetch(WECHAT_API_BASE, { headers, method: "POST", body });     
               if (!response.ok) {         
                   throw new Error(`HTTP error! status: ${response.status}`); 
 }     
   return true;   
       } catch (error) {  
              console.error("Error sending WeChat message:", error);         
              return false;    
}   }

通过 server.tool 注册发送文本工具,注册工具有四个函数,比如有些可以加描述,有些是0参数调用等等,选一个合适自己的即可。我们这里必须需要知道回调的 webhook key 和 content 。

img

import { sendWeChatTextMessage } from "./text.js";
// Register WeChat message tool
server.tool( 
 "sendWeChatTextMessage",  
 "send WeChat text message",  
 {   
    webhookKey: z.string().describe("WeChat webhook key"), // 必填      
    content: z.string().describe("WeChat message content"),// 必填     
     chatid: z.string().describe("WeChat message chatid").optional(), // optional 选填      
     mentioned_list: z.array(z.string()).describe("WeChat message mentioned list").optional(),     
      mentioned_mobile_list: z.array(z.string()).describe("WeChat message mentioned mobile list").optional(), 
      },    
      async ({ webhookKey, content, chatid, mentioned_list, mentioned_mobile_list }) => {        
        const success = await sendWeChatTextMessage(webhookKey, content, chatid, mentioned_list,   
         mentioned_mobile_list);        

   if (!success) {   
          return {         
                 content: [              
                             {                    
                                       type: "text",           
                                                    text: "Failed to send WeChat message",           
                                        },      
                         ],        
                   };       
           }         

 return {     
        content: [           
             {                
                 type: "text",     
                                text: "WeChat message sent successfully",      
                       },    
                              ],    
                                   };    
                                      },  
                                        );

发送文本工具就注册好了,其他功能工具开发类似。

创建resource资源

这里我们放一个企业微信机器人的文档。

server.resource( 
 "api",
   "file:///api.md",  
   async (uri) => {   
      try {        
        console.info(uri)          
        const __filename = fileURLToPath(import.meta.url);          
        const __dirname = path.dirname(__filename);          
        const filePath = path.join(__dirname.replace('build', 'assets'), 'api.md');         
         const content = await fs.promises.readFile(filePath, 'utf-8');    

      return {        
            contents: [{             
                 uri: uri.href,              
                      text: content         
                           }]    
                                 };     
           } catch (error) {      
               return {              
               contents: [{             
                    uri: uri.href,               
                      text: "读取文件失败"          
                          }]     
     };     
      }
        });
创建prompt

提示符是可重用的模板,可以帮助LLMs有效地与服务器交互。这里我们可以做一个参数检查的prompt。

server.prompt( 
 "parameter_check", 
  "参数检查", 
   {    
    param: z.string().describe("参数"),    
    apiContent: z.string().describe("API文档")
      }, 
       ({ param,apiContent }) => ({     
        messages: [{      
        role: "user",          
        content: {          
            type: "text",         
                 text: `              
                 <instruction>               
                  <instructions>                    
1. 接收API文档文本和用户数据作为输入。                   
2. 从API文档中提取所有参数的要求,包括参数名称、类型、是否必需、默认值等信息。                    
3. 对照用户提供的数据,检查每个参数是否满足API的要求。                   
4. 对于每个参数,记录以下信息:             
 - 参数名称                        
- 用户提供的值                      
 - 是否满足API要求(是/否)                        
- 如果不满足,说明原因                    
5. 将所有检查结果整理成一个清晰的报告,确保输出不包含任何XML标签。                    
6. 确保报告的格式简洁明了,便于用户理解。       
         </instructions>                
         <examples>                   
         <example>                      
         <input>                          
         API文档文本: "参数: username, 类型: string, 必需: 是; 参数: age, 类型: integer, 必需: 否;"                          
         用户数据: "{\"username\": john_doe, \"age\": 25}"                  
             </input>                      
             <output>                         
              "参数: username, 用户提供的值: john_doe, 满足要求: 是; 参数: age, 用户提供的值: 25, 满足要求: 是;"             
                       </output>                  
                       </example>                
                       </examples>              
                       </instruction>              
                       API文档文本:${apiContent}              
                       用户数据:${param}     
                                `          
                                }  
                                    }]
                                      }
                                      )
                                      );
2.2 运行调试

可以使用社区Inspector工具来调试我们的mcp。我使用的版本是v0.6.0,如果是用devcloud开发的同学可能会无法调试使用,因为代理地址写死了是localhost,导致连接失败,已经给社区提了PR #201并合并,远程开发的同学可以直接拉源码或者等待工具发布新版本。

调试tools

img

img

调试resource

img

调试prompt

img

3、MCP Client 开发

MCP Client的主要任务是连接到MCP Server,可以通过标准输入/输出或 SSE (Server-Sent Events) 与 MCP 服务器进行通信。

3.1 实现步骤

初始化客户端和会话对象

class MCPClient:   
 def __init__(self):    
     # 初始化 session 和 client 对象        
     self.session: Optional[ClientSession] = None        
     self._streams_context: Optional[sse_client] = None        
     self._session_context: Optional[ClientSession] = None        
     self.exit_stack = AsyncExitStack()  # 初始化异步退出栈
连接到MCP服务
async def connect_to_sse_server(self, server_url: str):   
 """连接到使用 SSE 传输的 MCP 服务器"""    
 if not server_url.startswith(" http://" ) and not server_url.startswith(" https://" ):   
      raise ValueError("服务器 URL 必须以 ' http://'  或 'https://' 开头")   

 # 存储上下文管理器以保持其存活    
 self._streams_context = sse_client(url=server_url)    
 streams = await self._streams_context.__aenter__()    
 self._session_context = ClientSession(*streams)    
 self.session: ClientSession = await self._session_context.__aenter__()    

# 初始化   
 await self.session.initialize()    
 async def connect_to_server(self, server_script_path: str):      
   """        
   连接到通过标准输入/输出通信的 MCP 服务器                

参数:       
     server_script_path: 服务器脚本路径(.py 或 .js 文件)            
    示例: "server.py" 或 "server.js"    
        """      
  is_python = server_script_path.endswith('.py')       
   is_js = server_script_path.endswith('.js')        
   if not (is_python or is_js):           
    raise ValueError("Server script must be a .py or .js file")        
    command = "python" if is_python else "node"        
    server_params = StdioServerParameters(       
         command=command,            
         args=[server_script_path],            
         env=None        
         )      
           stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))        
           self.stdio, self.write = stdio_transport        
           self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))       
            await self.session.initialize()

有两种连接方式,分别是:

  1. stdio(标准输入输出通信)。
  2. HTTP with Server-Sent Events (SSE)(HTTP 服务端发送事件)。

清理资源

class MCPClient:   
 def __init__(self):     
    # 初始化 session 和 client 对象        
    self.session: Optional[ClientSession] = None    

async def connect_to_sse_server(self, server_url: str):       
 """连接到使用 SSE 传输的 MCP 服务器"""      
   if not server_url.startswith(" http://" ) and not server_url.startswith(" https://" ):            
raise ValueError("服务器 URL 必须以 ' http://'  或 'https://' 开头")   

     # 存储上下文管理器以保持其存活       
      self._streams_context = sse_client(url=server_url)        
      streams = await self._streams_context.__aenter__()      

  self._session_context = ClientSession(*streams)       
   self.session: ClientSession = await self._session_context.__aenter__()        
   
   # 初始化   
        await self.session.initialize()    
        async def cleanup(self):     
           """清理 session 和 streams"""      
             if self._session_context:          
               await self._session_context.__aexit__(None, None, None)    
                   if self._streams_context:    
                           await self._streams_context.__aexit__(None, None, None)

3.2 调用
async def main():  
  if len(sys.argv) < 2:     
     print("用法: uv run client.py <SSE MCP 服务器的 URL (例如 " "=""> http://localhost:8080/sse)>" )       
      print("或: uv run client.py <MCP 服务器脚本路径 (例如 server.py)>")       
       sys.exit(1)   

 client = MCPClient()   
  try:  
        # stdio 连接方式       
         # await client.connect_to_server(server_script_path=sys.argv[1])       
          # sse 连接方式   
               await client.connect_to_sse_server(server_url=sys.argv[1])        
               print("\n连接到服务器...")                      

  response = await client.session.list_prompts()        
  response1 = await client.session.list_tools()        
  response2 = await client.session.list_resources()        
  print("response", response)        
  print("response1", response1)        
  print("response2", response2)           
   finally:   
        try:         
           await client.cleanup()     
              except Exception as e:        
                  print(f"清理错误: {e}")

img

4、MCP的工作原理

4.1 MCP架构

MCP采用的是C/S结构,一个MCP host应用可以链接多个MCP servers。

img

  • Host(主机):例如cursor、cline,负责接收你的提问并与模型交互。
  • Client(客户端):运行在Host内,mcp client 与 mcp server保持 1:1 连接,当用户在交互界面输入问题时,模型来决定使用1个或者多个工具,通过client来调用server执行具体操作。
  • Server(服务):在这个例子中,文件系统 MCP Server 会被调用。它负责执行实际的文件扫描操作,访问你的桌面目录,并返回找到的文档列表。

img

4.2 json-rpc

在我们用inspector调试我们的mcp-server时,请求参数里会有jsonrpc字段,在mcp中 client 和 server 之间的传输均采用了JSON-RPC 2.0 来交换消息。

img

主要特点包括:

  1. 简单易用: 相比于其他 XML-RPC 协议,JSON-RPC 使用 JSON 格式更容易理解和处理,因为 JSON 是一种人类可读的文本格式,同时被多种编程语言广泛支持。
  2. 轻量级: JSON-RPC 没有复杂的格式和规则,是一种轻量级的协议,非常适合嵌入式系统和网络环境不理想的情况下使用。
  3. 无状态: JSON-RPC 是无状态的协议,每次请求都是独立的,不依赖于之前的通信。
  4. 语言中立: 不限于某一种编程语言,被各种编程语言广泛支持。
  5. 支持批处理: JSON-RPC 还支持批处理模式,即在一个请求中发送多个 RPC 调用,以提高效率。

那么,如何系统的去学习大模型LLM?

作为一名从业五年的资深大模型算法工程师,我经常会收到一些评论和私信,我是小白,学习大模型该从哪里入手呢?我自学没有方向怎么办?这个地方我不会啊。如果你也有类似的经历,一定要继续看下去!这些问题啊,也不是三言两语啊就能讲明白的。

所以我综合了大模型的所有知识点,给大家带来一套全网最全最细的大模型零基础教程。在做这套教程之前呢,我就曾放空大脑,以一个大模型小白的角度去重新解析它,采用基础知识和实战项目相结合的教学方式,历时3个月,终于完成了这样的课程,让你真正体会到什么是每一秒都在疯狂输出知识点。

由于篇幅有限,⚡️ 朋友们如果有需要全套 《2025全新制作的大模型全套资料》,扫码获取~
在这里插入图片描述

👉大模型学习指南+路线汇总👈

我们这套大模型资料呢,会从基础篇、进阶篇和项目实战篇等三大方面来讲解。
在这里插入图片描述
在这里插入图片描述

👉①.基础篇👈

基础篇里面包括了Python快速入门、AI开发环境搭建及提示词工程,带你学习大模型核心原理、prompt使用技巧、Transformer架构和预训练、SFT、RLHF等一些基础概念,用最易懂的方式带你入门大模型。
在这里插入图片描述

👉②.进阶篇👈

接下来是进阶篇,你将掌握RAG、Agent、Langchain、大模型微调和私有化部署,学习如何构建外挂知识库并和自己的企业相结合,学习如何使用langchain框架提高开发效率和代码质量、学习如何选择合适的基座模型并进行数据集的收集预处理以及具体的模型微调等等。
在这里插入图片描述

👉③.实战篇👈

实战篇会手把手带着大家练习企业级的落地项目(已脱敏),比如RAG医疗问答系统、Agent智能电商客服系统、数字人项目实战、教育行业智能助教等等,从而帮助大家更好的应对大模型时代的挑战。
在这里插入图片描述

👉④.福利篇👈

最后呢,会给大家一个小福利,课程视频中的所有素材,有搭建AI开发环境资料包,还有学习计划表,几十上百G素材、电子书和课件等等,只要你能想到的素材,我这里几乎都有。我已经全部上传到优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费
在这里插入图片描述
相信我,这套大模型系统教程将会是全网最齐全 最易懂的小白专用课!!

### MCP芯片的工作原理 微处理器控制单元(Microcontroller Processing Unit, 简称MCP)是一种集成了多种外设功能的单片机,其设计目标是为了实现特定应用中的高效处理能力。以下是关于MCP芯片工作原理的具体描述: #### 1. 架构概述 MCP通常基于精简指令集计算(RISC)架构,能够快速执行基本操作命令。例如,在飞思卡尔MC9S08系列中,MCP的核心CPU具备高效的运算能力和较低的功耗特性[^1]。 #### 2. 存储器结构 MCP内部集成了一定容量的闪存和RAM,用于存储程序代码以及运行期间的数据缓存。对于副门控制器使用的MC9S08SG08芯片而言,尽管其存储器空间较小,但仍能满足嵌入式系统的典型需求。 #### 3. 输入/输出接口 MCP通过丰富的I/O端口与其他硬件设备交互。这些端口支持多路复用模式,允许开发者灵活配置GPIO、串行通信协议等功能。具体来说,MC9S08SG08提供了多达20个引脚来满足不同的连接需求。 #### 4. 定时与计数功能 内置定时器模块使得MCP可以精确测量时间间隔或者生成周期性的触发信号。这种特性广泛应用于电机驱动、PWM波形产生等领域。在引用材料提到的例子中,该类定时器被成功部署于汽车门窗升降机构之中。 #### 5. 模拟数字转换 (ADC) 为了采集外部模拟量并将其转化为数字形式供后续算法分析,许多型号的MCP都配备了高性能的模数转换电路。比如文中提及的产品就拥有专门针对车窗位置检测优化过的AD采样通道。 #### 6. 通讯协议支持 现代MCP普遍兼容主流工业标准总线技术如UART,SPI,I²C,LIN等,从而简化了复杂网络环境下节点间的信息交换过程。特别是LIN通信模块的存在让MC9S08SG08非常适合充当辅助角色参与到整车电气管理系统当中去。 ```python # 示例代码展示如何初始化一个简单的MCP ADC读取流程 def initialize_adc(mcp_instance): mcp_instance.set_mode('adc') # 设置为ADC模式 mcp_instance.configure_channel(0) # 配置第一个输入通道 def read_analog_value(): value = mcp.read() # 执行一次转换获取数值 return value # 返回结果给调用方 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值