要说最近在大模型和智能体领域什么东西最需要学习,那必须是MCP(Model Context Protocol)了。陆续看了不少关于MCP的文章,知识拼图也差不多全了,但是还是不太放心,觉得应该系统性地学习一遍,所以把MCP整个官网内容都看了一遍。同时,只看理论还是不够,必须要使用代码实践一下。所以本篇主要包括两个方面:
-
全面系统整理MCP的知识体系,包括概念、核心组件、架构;
-
拿一个实际案例,来看看其概念和组件是如何使用的。
大模型要发挥作用,例如在智能体应用中,除了直接调用大模型当大脑进行规划,还需要使用外部知识库、数据源或者工具完成大模型自身无法完成的任务。例如要获取当天某个城市的天气预报,大模型没有这个实时的知识,只能调用天气预报API。
MCP的作用,就是在大模型与外部工具之间的制定通讯协议标准。回顾一下MCP出现前,业界解决这个问题的典型方法:Function Calling。
1. Function Calling回顾
图1. Function Calling步骤,来源[1]
对应上图,Application为一个应用程序,结合获取天气信息为例,Function Calling的步骤如下:
1. 应用程序问大模型今天某个城市的天气情况,提示词例如“请问今天北京的天气情况”,同时告诉大模型可用的工具有哪些,每个工具的名称、功能描述、需传入的参数。工具集合中包含可获取天气预报的接口,初学者可能会问既然已经知道天气预报接口了,直接调用不就行了?实际情况是应用程序告诉大模型一堆可用的工具,让大模型去思考和查找用什么接口,工具多了应用程序不知道、也不用操心用哪个工具;
2. 大模型根据收到的提示词和可用工具集合,决定使用哪个或哪些工具、以及对应的参数,本例中工具名可能叫get_weather(), 参数=“北京”;
3. 大模型把需要调用的工具和参数告诉应用程序;
4. 应用程序根据收到的信息,使用需要的参数调用对应的工具;
5. 应用程序把工具调用获得的结果加上之前的提示词一起给大模型,工具调用结果类似{'temperature':'15度', 'wind':'东南风1级'};
6. 大模型融合提示词和工具调用结果的输入,计算输出最终结果,例如“北京今天温度15度,东南风1级”。
Function Calling的局限在于各家大模型会根据不同的functions名、功能描述、参数训练自己的模型,调用方式也不同,虽然逻辑一样,但实现方式各自为阵,比如OpenAI和Google Gemini就不一样。应用程序方如果切换不同大模型,需要做适配,很麻烦,这就迫切需要一个统一的协议,于是有了MCP。
2. MCP基本介绍
MCP是Anthropic于2024年11月发布的协议,最全面的介绍莫过于MCP官网的全部内容,以及MCP的源代码可以帮助理解,但这些内容过多,这里抽取核心内容再加上自己理解整理。
2.1 定义和总览
MCP官方定义:MCP是一个开放协议,旨在标准化应用程序向大语言模型(LLM)提供上下文的方式。你可以将MCP视为AI应用的USB-C接口,正如USB-C为设备连接各类外设和配件提供了标准化方式,MCP则为AI模型连接不同数据源和工具提供了标准化接口。
图2应该是全网见得最多、也是最形象的对MCP的解释,就像USB-C接口,把不同数据源和工具通过标准化接口和AI大模型相连。
图2. MCP形象解释,来源[2]
2.2 主要架构和组件
MCP架构如下来自官网的图3,其实图2已经有了清楚的展示。
图3. MCP架构,来源[3]
主要组件如下:
-
Hosts:希望通过MCP访问数据的应用程序,例如Claude Desktop、集成开发环境(IDE)、AI工具、或者其他使用AI的系统。
-
Clients:与服务器保持1:1连接的协议客户端,在Host上。
-
Servers:通过标准化MCP提供特定功能的轻量级程序服务端。
-
Local Data Sources:MCP服务器可安全访问的文件、数据库及服务。
-
Remote Services:MCP服务器可连接的互联网外部系统(例如通过API访问)。
2.3 支持的传输类型(Transport Types)
官方文档中有不少概念,包括Resources、Prompts、Tools、Sampling、Roots、Transports,为了实用起见且不干扰主线,我们不面面俱到,重点说下MCP中的数据传输类型,包括:
2.3.1 Standard Input/Output (stdio)
用于标准输入输出,特别是本地任务,比如client和server都在同一台机器上,典型的包括:
-
构建命令行工具
-
实现本地集成
-
需要简单的过程通信
-
使用shell脚本
过程如下:
图4. stdio过程,来源MCP协议文档
2.3.2 Streamable HTTP
之前是HTTP+SSE transport方式,其中HTTP就是常见的HTTP方式,SSE是Server-Sent Events,即服务端向客户端推送消息方式。最新(2025.3.26)文档改为了Streamable HTTP,服务端进程提供可处理多个客户端连接,支持HTTP POST和GET方法。服务器可以选择性地使用服务器发送事件(SSE)来流式传输多个服务器消息。
3. MCP处理逻辑
本节是重点,通过MCP python SDK聊天机器人样例项目代码[5],理解MCP+大模型是如何从应用请求(例如查询天气)开始,到最终得到输出的主要逻辑。本节参考了资料[4]。
核心逻辑和Function Calling思路类似,包括:
-
大模型决定使用哪个或哪些工具,不过这些工具是在服务端的
-
使用工具确定后,执行这些工具,把结果和之前的请求输入大模型得到最终输出
3.1 用Prompt让大模型决定工具的选择
先获取所有server中所有的工具列表:
然后通过提示词让大模型根据用户的提问决定使用哪个工具:
server端定义了每个工具的名称、描述和参数:
3.2 执行工具并把结果重新输入大模型
如果不需要工具,直接让大模型根据问题输出答案,否则才执行工具。其中,self.process_llm_response(llm_response)根据server端定义的工具名称和参数执行:
server端execute_tool定义如下:
工具类Tool定义了工具的属性和格式化方法:
至于client和server端如何通信的,就是MCP SDK根据MCP协议实现的。
4. 如何构建MCP server
官方给的步骤是准备好提示词,让大模型给你创建!原话是“用大模型比如Claude”,实际上目前应该只有Anthropic公司自己的Claude大模型才最懂如何创建MCP Server,因为别人家的模型估计还没用MCP知识训练过。
创建主要包含以下步骤:
-
准备MCP资料,让Claude懂得MCP
-
准备提示词,告诉Claude你的MCP server需要的功能
-
执行使用Claude创建MCP Server
-
测试和debug
5. 动手实践
由于MCP的样例和文档都是以Anthropic公司自己的Claude模型为基础来讲的,比如上面MCP server的创建。国内要使用Claude并不方便,包括网络和账号申请等,所以现实点我们还是实践下如何使用国内模型,特别是DeepSeek来试试。
本节使用了资料[6]源码,在同一台机器上通过stdio方式实现MCP client和server端,调用外部天气预报接口实现天气问询,在Windows上实验。
5.1 环境搭建
以前都是使用conda创建虚拟环境,每次安装内容多、安装时间长、占用空间大,此次听说新的uv工具创建python虚拟环境、管理依赖包安装速度巨快、占用空间小,果断尝试下。
使用powershell安装uv,当然还有其他方式:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
指定python版本创建虚拟环境:
uv venv --python 3.11
安装依赖包包括mcp,真的是巨快:
本实验需要调用DeepSeek大模型,天气预报调用https://api.openweathermap.org的接口,所以需要分别注册两者网站并创建API key,具体步骤略,openweathermap网站的key在server.py中使用。
在项目.env中配置好DeepSeek相关信息:
BASE_URL=https://api.deepseek.com MODEL=deepseek-chat OPENAI_API_KEY="你的deepseek api key"
5.2 准备代码
server.py代码如下,通过MCP SDK中的FastMCP初始化服务,定义了query_weather()工具,实际调用openweather接口,然后通过format_weather()格式化输出。
import json import httpx from typing import Any from mcp.server.fastmcp import FastMCP # 初始化 MCP 服务器 mcp = FastMCP("WeatherServer") # OpenWeather API 配置 OPENWEATHER_API_BASE = "https://api.openweathermap.org/data/2.5/weather" API_KEY = "xxxxxx" # 请替换为你自己的 OpenWeather API Key USER_AGENT = "weather-app/1.0" async def fetch_weather(city: str) -> dict[str, Any] | None: """ 从 OpenWeather API 获取天气信息。 :param city: 城市名称(需使用英文,如 Beijing) :return: 天气数据字典;若出错返回包含 error 信息的字典 """ params = { "q": city, "appid": API_KEY, "units": "metric", "lang": "zh_cn" } headers = {"User-Agent": USER_AGENT} async with httpx.AsyncClient() as client: try: response = await client.get(OPENWEATHER_API_BASE, params=params, headers=headers, timeout=30.0) response.raise_for_status() return response.json() # 返回字典类型 except httpx.HTTPStatusError as e: return {"error": f"HTTP 错误: {e.response.status_code}"} except Exception as e: return {"error": f"请求失败: {str(e)}"} def format_weather(data: dict[str, Any] | str) -> str: """ 将天气数据格式化为易读文本。 :param data: 天气数据(可以是字典或 JSON 字符串) :return: 格式化后的天气信息字符串 """ # 如果传入的是字符串,则先转换为字典 if isinstance(data, str): try: data = json.loads(data) except Exception as e: return f"无法解析天气数据: {e}" # 如果数据中包含错误信息,直接返回错误提示 if "error" in data: return f"⚠️ {data['error']}" # 提取数据时做容错处理 city = data.get("name", "未知") country = data.get("sys", {}).get("country", "未知") temp = data.get("main", {}).get("temp", "N/A") humidity = data.get("main", {}).get("humidity", "N/A") wind_speed = data.get("wind", {}).get("speed", "N/A") # weather 可能为空列表,因此用 [0] 前先提供默认字典 weather_list = data.get("weather", [{}]) description = weather_list[0].get("description", "未知") return ( f"🌍 {city}, {country}\n" f"🌡 温度: {temp}°C\n" f"💧 湿度: {humidity}%\n" f"🌬 风速: {wind_speed} m/s\n" f"🌤 天气: {description}\n" ) @mcp.tool() async def query_weather(city: str) -> str: """ 输入指定城市的英文名称,返回今日天气查询结果。 :param city: 城市名称(需使用英文) :return: 格式化后的天气信息 """ data = await fetch_weather(city) return format_weather(data) if __name__ == "__main__": # 以标准 I/O 方式运行 MCP 服务器 mcp.run(transport='stdio')
client.py如下,通过stdio方式和server通信,调用DeepSeek使用OpenAI API方式,决定使用那种tool采用Function Calling方式,在self.client.chat.completions.create()中把可用的工具集传递进去,后面的逻辑和3.2类似:
import asyncio import os import json from typing import Optional from contextlib import AsyncExitStack from openai import OpenAI from dotenv import load_dotenv from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client # 加载 .env 文件,确保 API Key 受到保护 load_dotenv() class MCPClient: def __init__(self): """初始化 MCP 客户端""" self.exit_stack = AsyncExitStack() self.openai_api_key = os.getenv( "OPENAI_API_KEY2") # 读取 OpenAI API Key self.base_url = os.getenv("BASE_URL") # 读取 BASE YRL self.model = os.getenv("MODEL") # 读取 model if not self.openai_api_key: raise ValueError( "❌ 未找到 OpenAI API Key,请在 .env 文件中设置 OPENAI_API_KEY") self.client = OpenAI(api_key=self.openai_api_key, base_url=self.base_url) # 创建OpenAI client self.session: Optional[ClientSession] = None self.exit_stack = AsyncExitStack() async def connect_to_server(self, server_script_path: str): """连接到 MCP 服务器并列出可用工具""" is_python = server_script_path.endswith('.py') is_js = server_script_path.endswith('.js') if not (is_python or is_js): raise ValueError("服务器脚本必须是 .py 或 .js 文件") command = "python" if is_python else "node" server_params = StdioServerParameters( command=command, args=[server_script_path], env=None ) # 启动 MCP 服务器并建立通信 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() # 列出 MCP 服务器上的工具 response = await self.session.list_tools() tools = response.tools print("\n已连接到服务器,支持以下工具:", [tool.name for tool in tools]) async def process_query(self, query: str) -> str: """ 使用大模型处理查询并调用可用的 MCP 工具 (Function Calling) """ messages = [{"role": "user", "content": query}] response = await self.session.list_tools() available_tools = [{ "type": "function", "function": { "name": tool.name, "description": tool.description, "input_schema": tool.inputSchema } } for tool in response.tools] print(available_tools) response = self.client.chat.completions.create( model=self.model, messages=messages, tools=available_tools ) # 处理返回的内容 content = response.choices[0] print(f'response choice={content}') if content.finish_reason == "tool_calls": # 如何是需要使用工具,就解析工具 tool_call = content.message.tool_calls[0] tool_name = tool_call.function.name tool_args = json.loads(tool_call.function.arguments) # 执行工具 result = await self.session.call_tool(tool_name, tool_args) print( f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n") # 将模型返回的调用哪个工具数据和工具执行完成后的数据都存入messages中 messages.append(content.message.model_dump()) messages.append({ "role": "tool", "content": result.content[0].text, "tool_call_id": tool_call.id, }) # 将上面的结果再返回给大模型用于生产最终的结果 response = self.client.chat.completions.create( model=self.model, messages=messages, ) return response.choices[0].message.content return content.message.content async def chat_loop(self): """运行交互式聊天循环""" print("\n🤖 MCP 客户端已启动!输入 'quit' 退出") while True: try: query = input("\n你: ").strip() if query.lower() == 'quit': break response = await self.process_query( query) # 发送用户输入到 OpenAI API print(f"\n🤖 OpenAI: {response}") except Exception as e: print(f"\n⚠️ 发生错误: {str(e)}") async def cleanup(self): """清理资源""" await self.exit_stack.aclose() async def main(): if len(sys.argv) < 2: print("Usage: python client.py <path_to_server_script>") sys.exit(1) client = MCPClient() try: await client.connect_to_server(sys.argv[1]) await client.chat_loop() finally: await client.cleanup() if __name__ == "__main__": import sys asyncio.run(main())
5.3 运行看效果
执行命令:python client.py server.py
先问一个天气问题,大模型能识别到然后调用外部工具:
问一个和天气无关的问题,它会直接调用大模型输出:
本文理论和实践到此结束。
关于MCP的趋势和后续发展情况,我自己认为实际就是Function Calling的进阶版,但是由于提升了一个层次和高度,且业界确实需要一个统一的协议标准,而且它是开源的,后面会迅速发展,也会促进agent的发展速度。这不OpenAI已经开始拥抱了,其他厂商还会远吗?
一、大模型风口已至:月薪30K+的AI岗正在批量诞生
2025年大模型应用呈现爆发式增长,根据工信部最新数据:
国内大模型相关岗位缺口达47万
初级工程师平均薪资28K(数据来源:BOSS直聘报告)
70%企业存在"能用模型不会调优"的痛点
真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!
二、如何学习大模型 AI ?
🔥AI取代的不是人类,而是不会用AI的人!麦肯锡最新报告显示:掌握AI工具的从业者生产效率提升47%,薪资溢价达34%!🚀
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
1️⃣ 提示词工程:把ChatGPT从玩具变成生产工具
2️⃣ RAG系统:让大模型精准输出行业知识
3️⃣ 智能体开发:用AutoGPT打造24小时数字员工
📦熬了三个大夜整理的《AI进化工具包》送你:
✔️ 大厂内部LLM落地手册(含58个真实案例)
✔️ 提示词设计模板库(覆盖12大应用场景)
✔️ 私藏学习路径图(0基础到项目实战仅需90天)
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
* 大模型 AI 能干什么?
* 大模型是怎样获得「智能」的?
* 用好 AI 的核心心法
* 大模型应用业务架构
* 大模型应用技术架构
* 代码示例:向 GPT-3.5 灌入新知识
* 提示工程的意义和核心思想
* Prompt 典型构成
* 指令调优方法论
* 思维链和思维树
* Prompt 攻击和防范
* …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
* 为什么要做 RAG
* 搭建一个简单的 ChatPDF
* 检索的基础概念
* 什么是向量表示(Embeddings)
* 向量数据库与向量检索
* 基于向量检索的 RAG
* 搭建 RAG 系统的扩展知识
* 混合检索与 RAG-Fusion 简介
* 向量模型本地部署
* …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
* 为什么要做 RAG
* 什么是模型
* 什么是模型训练
* 求解器 & 损失函数简介
* 小实验2:手写一个简单的神经网络并训练它
* 什么是训练/预训练/微调/轻量化微调
* Transformer结构简介
* 轻量化微调
* 实验数据集的构建
* …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
* 硬件选型
* 带你了解全球大模型
* 使用国产大模型服务
* 搭建 OpenAI 代理
* 热身:基于阿里云 PAI 部署 Stable Diffusion
* 在本地计算机运行大模型
* 大模型的私有化部署
* 基于 vLLM 部署大模型
* 案例:如何优雅地在阿里云私有部署开源大模型
* 部署一套开源 LLM 项目
* 内容安全
* 互联网信息服务算法备案
* …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】