L11 MCP 协议:Agent 工具调用的"USB-C 接口"
课程目标:理解 MCP(Model Context Protocol)协议的原理与价值,能用 Python 实现一个最小的 MCP Server 和 Client。
一、一个让所有 Agent 开发者头疼的问题#
想象你是一个 Agent 框架作者(比如 LangChain 的工程师)。用户的需求五花八门:
"我的 Agent 要能查 PostgreSQL 数据库"
"我的 Agent 要能读 GitHub Issues"
"我的 Agent 要能控制 Slack 消息"
"我的 Agent 要能操作浏览器"
"我的 Agent 要能调内部 ERP 系统"
每个需求你都要:
写一套工具适配代码(Tool Adapter)
处理不同数据源的身份认证
适配不同的传输协议(HTTP / WebSocket / gRPC)
写一份文档告诉用户怎么用
结果:LangChain 已经有 2000+ 个工具集成,但用户的新需求永远比这多。你永远在追赶用户需求。
有没有一种方式,让工具提供者自己实现一套标准接口,然后任何 Agent 都能"即插即用"?
MCP 就是为了解决这个问题的。
二、用一个比喻:MCP = Agent 世界的 USB-C#
把你的电脑想象成 Agent(LLM):
显示器、键盘、鼠标、硬盘、网线——每个外设都有自己的接口(HDMI、USB-A、3.5mm 音频、RJ45)
你买每个外设都要确认"我的电脑有这个口吗"
2015 年之前:MacBook 一个 USB-A 口都没有,新买的 U 盘插不进去 → 骂 Apple
2015 年之后:USB-C 统一天下 → 一个口插所有设备
MCP 就是 Agent 世界的 USB-C:
之前:每个工具都有自己独特的接口,Agent 框架要为每个工具写适配器
之后:工具提供方按 MCP 协议实现,所有兼容 MCP 的 Agent 都能直接调用
这是 Agent 工程化的转折点——从"每个工具都要适配"变成"一次实现,到处运行"。
三、MCP 是什么?#
MCP(Model Context Protocol) 是 Anthropic 在 2024 年 11 月开源的协议。它定义了一套 标准化的 JSON-RPC 2.0 消息格式,让 LLM 应用(MCP Client)能调用外部工具(MCP Server)。
核心架构:
┌─────────────────┐ JSON-RPC 2.0 ┌─────────────────┐
│ MCP Host │ ◄──────────────────────────► │ MCP Server │
│ (Claude │ stdio / SSE / HTTP │ (工具提供者) │
│ Desktop, │ │ │
│ Cursor, │ │ 暴露: │
│ 自定义Agent) │ │ - Tools │
│ │ │ - Resources │
│ 内嵌 MCP Client│ │ - Prompts │
└─────────────────┘ └─────────────────┘
三大核心原语(Primitives)#
MCP Server 能暴露三种能力:
| 原语 | 含义 | 类比 | 示例 |
|---|---|---|---|
| Tools | LLM 可调用的函数(带参数) | 电脑的 USB 设备 | query_database(sql)、send_slack_message(channel, text) |
| Resources | LLM 可读取的数据源(只读) | 电脑的文件系统 | 读取 GitHub Issue 内容、读取本地 PDF |
| Prompts | 预设的提示词模板 | 电脑的快捷指令 | "代码审查模板"、"周报生成模板" |
注意区别:
Tools = 让 Agent "做事"(有副作用)
Resources = 让 Agent "读信息"(无副作用)
Prompts = 给 Agent "预设指令"(用户主动触发)
两种传输方式#
| 传输 | 适用场景 | 通信方式 |
|---|---|---|
| stdio | 本地进程(同台机器) | 标准输入输出 |
| SSE / HTTP | 远程服务器(跨网络) | Server-Sent Events 或 Streamable HTTP |
四、和 L4 Tool Use 的关系#
你可能会问:MCP 和 L4 讲的 OpenAI Function Calling 有什么区别?
| 维度 | L4 Tool Use | MCP |
|---|---|---|
| 定义者 | OpenAI(单一公司) | Anthropic 开源协议(多方采纳) |
| 协议范围 | 单次 LLM 调用的工具参数格式 | 完整 Client-Server 通信协议 |
| 工具发现 | 用户手动告诉 LLM"你有这些工具" | Client 自动从 Server 发现 |
| 状态管理 | 无状态(每次调用独立) | 有状态(Server 可保持连接、会话) |
| 生态 | 仅 OpenAI 系 | OpenAI、Google、Microsoft 都支持 |
| 适用规模 | 小项目(几个工具) | 大规模生态(成百上千工具) |
一句话:
L4 Tool Use 是"一次对话里怎么调工具"
MCP 是"长期来看工具和 Agent 怎么标准化协作"
类比:
L4 Tool Use 像 RPC(远程过程调用)—— 解决"一次调用怎么传参"
MCP 像 HTTP—— 解决"所有客户端和服务端怎么标准化通信"
五、动手实现:写一个 MCP Server(30 行)#
我们写一个最小的 MCP Server,把本地文件系统暴露成 Resources。这是 Anthropic 官方 quickstart 的简化版:
安装#
pip install mcp
完整代码(mcp_filesystem_server.py)#
from mcp.server.fastmcp import FastMCP
import os
# ============ 创建 MCP Server ============
mcp = FastMCP("FileSystem Server")
# ============ 暴露 Tool:列目录 ============
@mcp.tool()
def list_directory(path: str = ".") -> list[str]:
"""列出指定目录下的文件和文件夹。
Args:
path: 要列出的目录路径,默认为当前目录
"""
try:
return os.listdir(path)
except Exception as e:
return [f"错误: {e}"]
# ============ 暴露 Tool:读文件 ============
@mcp.tool()
def read_file(path: str) -> str:
"""读取文件内容。
Args:
path: 文件路径
"""
try:
with open(path, "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
return f"错误: {e}"
# ============ 暴露 Resource:当前目录信息 ============
@mcp.resource("fs://current-dir")
def get_current_dir() -> str:
"""提供当前工作目录的信息"""
return f"当前目录: {os.getcwd()}\n包含文件: {os.listdir('.')}"
# ============ 暴露 Prompt:代码审查模板 ============
@mcp.prompt()
def code_review_prompt(code: str) -> str:
"""生成代码审查的 prompt 模板"""
return f"""请审查以下代码,重点关注:
1. 潜在的 bug
2. 性能问题
3. 安全风险
4. 代码风格
代码:
```python
{code}
请给出具体的改进建议。"""
============ 启动 Server ============#
if name == "main": mcp.run() # 默认用 stdio 传输
**这段代码做了什么?**
- 创建了一个名为 "FileSystem Server" 的 MCP Server
- 暴露了 2 个 Tools(`list_directory`、`read_file`)
- 暴露了 1 个 Resource(`fs://current-dir`)
- 暴露了 1 个 Prompt(`code_review_prompt`)
- 启动后用 stdio 监听,等待 Client 连接
---
## 六、动手实现:写一个 MCP Client 调用 Server
MCP Client 通常内嵌在 Agent 框架里(如 Claude Desktop)。我们写一个最小 Client 演示怎么调用上面的 Server:
### 完整代码(mcp_client_demo.py)
```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
# ============ 1. 启动 Server 子进程并连接 ============
server_params = StdioServerParameters(
command="python",
args=["mcp_filesystem_server.py"] # 启动上面写的 Server
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# ============ 2. 初始化连接 ============
await session.initialize()
# ============ 3. 发现 Server 暴露的能力 ============
tools = await session.list_tools()
print("Server 暴露的工具:")
for tool in tools.tools:
print(f" - {tool.name}: {tool.description}")
resources = await session.list_resources()
print("\nServer 暴露的资源:")
for resource in resources.resources:
print(f" - {resource.uri}: {resource.name}")
# ============ 4. 调用 Tool ============
result = await session.call_tool("list_directory", arguments={"path": "."})
print(f"\n列目录结果: {result.content}")
# ============ 5. 读取 Resource ============
resource_result = await session.read_resource("fs://current-dir")
print(f"\n当前目录信息: {resource_result.contents[0].text}")
if __name__ == "__main__":
asyncio.run(main())
运行结果#
Server 暴露的工具:
- list_directory: 列出指定目录下的文件和文件夹。
- read_file: 读取文件内容。
Server 暴露的资源:
- fs://current-dir: 当前目录信息
列目录结果: ['mcp_filesystem_server.py', 'mcp_client_demo.py', ...]
当前目录信息: 当前目录: /Users/xxx/project
包含文件: ['mcp_filesystem_server.py', ...]
这段代码做了什么?
启动上面写的 Server 作为子进程(stdio 方式)
Client 连接 Server,发现它暴露的所有能力
调用
list_directory工具列出当前目录读取
fs://current-dir资源获取信息
关键观察:Client 不需要硬编码 Server 有哪些工具——它通过 list_tools() 自动发现。这就是 MCP 相比 L4 Tool Use 的核心优势:解耦 + 标准化。
七、把 MCP 接到 LangGraph Agent#
最有价值的实战是让现有 Agent 框架支持 MCP。LangGraph 通过 langchain-mcp-adapters 库实现:
pip install langchain-mcp-adapters
用 LangGraph 调用 MCP Server 的完整代码#
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode
from langchain_openai import ChatOpenAI
from langchain_mcp_adapters.tools import load_mcp_tools
# ============ 1. 连接 MCP Server 并加载工具 ============
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import asyncio
async def create_agent():
server_params = StdioServerParameters(
command="python",
args=["mcp_filesystem_server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# 把 MCP Server 的工具转成 LangChain 工具
tools = await load_mcp_tools(session)
# ============ 2. 创建 LangGraph Agent ============
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)
def should_continue(state: MessagesState):
last = state["messages"][-1]
if last.tool_calls:
return "tools"
return END
graph_builder = StateGraph(MessagesState)
graph_builder.add_node("agent", lambda s: {"messages": [llm.invoke(s["messages"])]})
graph_builder.add_node("tools", ToolNode(tools))
graph_builder.add_edge(START, "agent")
graph_builder.add_conditional_edges("agent", should_continue)
graph_builder.add_edge("tools", "agent")
return graph_builder.compile()
# ============ 3. 运行 Agent ============
async def main():
agent = await create_agent()
result = await agent.ainvoke({
"messages": [{"role": "user", "content": "当前目录下有哪些 Python 文件?"}]
})
print(result["messages"][-1].content)
asyncio.run(main())
这段代码做了什么?
用
langchain-mcp-adapters把 MCP Server 的工具自动转成 LangChain 工具把这些工具接入 LangGraph Agent(L5 学过的状态图)
Agent 问"当前目录下有哪些 Python 文件"——它会自动调用 MCP Server 的
list_directory工具
这就是 MCP 的威力:你的 LangGraph Agent 不需要任何改动,就能调用任何 MCP Server 暴露的工具。
八、MCP 生态全景#
截至 2026 年初,MCP 生态已经相当丰富:
官方 MCP Server(Anthropic 维护)#
Filesystem Server:读写本地文件
GitHub Server:管理 Issues、PR、代码搜索
PostgreSQL Server:查询数据库
Slack Server:发送消息、管理频道
Google Drive Server:读写云端文档
Puppeteer Server:浏览器自动化
第三方 MCP Server#
Notion Server:操作 Notion 页面
Linear Server:管理项目任务
Figma Server:操作 Figma 设计稿
Stripe Server:处理支付
AWS Server:管理云资源
支持 MCP 的 Client#
Claude Desktop(官方)
Cursor(代码编辑器)
Zed(代码编辑器)
Continue(VS Code 插件)
自定义 LangChain / LangGraph / smolagents Agent(通过适配器)
行业趋势:OpenAI、Google DeepMind、Microsoft 都在 2025 年宣布支持 MCP。这意味着 MCP 正在成为事实标准——学它就是学未来。
九、MCP 的限制与批评#
MCP 不是银弹。了解它的限制能帮你做出更好的工程决策。
限制 1:性能开销#
MCP 通过 JSON-RPC 通信,比直接函数调用慢 5-10 毫秒。对于高频调用场景(如每秒上千次),需要批量调用或换直接 API。
限制 2:复杂度#
简单项目用 MCP 是过度工程化。如果你的 Agent 只有 2-3 个工具,直接用 L4 的 Tool Use 就够了。MCP 适合工具数量 ≥ 10 个 或工具提供方与 Agent 开发方是不同团队的场景。
限制 3:安全边界模糊#
MCP Server 默认可以执行任意代码。如果 Server 来自不可信来源,恶意 Server 可能读取你的文件、发送你的数据。生产环境必须验证 Server 来源 + 限制权限。
限制 4:协议仍在演进#
2024 年 11 月发布、2025 年快速迭代。Streamable HTTP 等新传输还在规范化中。早期采用者可能面临兼容性变化。
十、和 L1-L6 的连接#
| 课程 | 在 MCP 体系中的位置 |
|---|---|
| L1 Agent 是什么 | MCP 让"Agent 调用外部工具"这件事标准化 |
| L2 ReAct 循环 | MCP Server 是 ReAct 循环中的 Action 执行者 |
| L3 smolagents | smolagents 正在集成 MCP(2025 年路线图) |
| L4 Tool Use 深入 | MCP 是 Tool Use 的标准化演进 |
| L5 LangGraph | LangGraph 通过 langchain-mcp-adapters 集成 MCP |
| L6 多 Agent | MCP Server 可被多个 Agent 共享,是多 Agent 协作的基础设施 |
完整心智模型:MCP 把"工具调用"从 L4 的"LLM + 函数"升级成"LLM + Client + Server"三层架构,让工具生态可以独立演进。
十一、动手时间:60 分钟亲手实现#
请你按顺序完成以下三步:
步骤 1:跑通官方 MCP Server(15 分钟)#
# 安装官方 Filesystem MCP Server
pip install mcp
# 启动 Server(stdio 模式)
python -c "
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('Demo')
@mcp.tool()
def hello(name: str) -> str:
'''Say hello to someone'''
return f'Hello, {name}!'
mcp.run()
"
步骤 2:用 MCP Inspector 调试(20 分钟)#
Anthropic 提供了一个可视化调试工具 MCP Inspector:
npx @modelcontextprotocol/inspector python mcp_filesystem_server.py
打开浏览器后你能:
看到 Server 暴露的所有 Tools / Resources / Prompts
直接调用工具,看返回结果
检查 JSON-RPC 消息的格式
步骤 3:把 MCP 接到你自己的 Agent(25 分钟)#
把第七节的 LangGraph + MCP 代码跑通,观察你的 LangGraph Agent 是怎么自动发现 MCP Server 的工具的。
📋 步骤 1 可能的坑(点击展开)
坑 1:mcp 包找不到 → 确认 Python ≥ 3.10,pip install --upgrade mcp
坑 2:stdio_client 卡住 → Server 必须用 stdio 模式(mcp.run() 默认就是 stdio)。如果加了日志输出到 stdout,会污染 JSON-RPC 消息。所有日志必须输出到 stderr。
坑 3:load_mcp_tools 失败 → 确认 MCP Server 已经 initialize() 过,否则 list_tools 会返回空。
坑 4:MCP Inspector 启动失败 → 需要 Node.js 18+。如果 npx 失败,试试 npm install -g @modelcontextprotocol/inspector。
十二、小结#
| 知识点 | 一句话回顾 |
|---|---|
| MCP 是什么 | Anthropic 2024 年开源的 Agent 工具调用标准化协议 |
| 核心比喻 | MCP = Agent 世界的 USB-C,一次实现到处运行 |
| 三大原语 | Tools(做事)/ Resources(读数据)/ Prompts(模板) |
| 两种传输 | stdio(本地进程)/ SSE 或 Streamable HTTP(远程) |
| 与 L4 区别 | L4 是"一次调用的格式",MCP 是"长期生态的标准" |
| 生态 | OpenAI、Google、Microsoft 都已支持,正在成为事实标准 |
| 限制 | 性能开销、复杂度、安全边界、协议仍在演进 |
十三、Read next#
下一节 L7 Planning 高级模式,我们深入 Agent 的"思考能力"——ReAct 循环的进化版本:
Plan-and-Execute:先想清楚整个计划,再逐步执行
ReWOO:把推理和观察分离,省 token
Reflexion:让 Agent 自我反思、自我改进
主要参考:
MCP 官方文档 — Anthropic 官方协议说明
Agentic MCP — 微软课程对 MCP 的介绍
Hugging Face MCP Course — 配套 MCP 实战课程
十四、Sources#
src-001 — Microsoft AI Agents for Beginners · T1 · Agentic MCP
MCP 官方文档 · T1 · modelcontextprotocol.io
Hugging Face MCP Course · T1 · mcp-course
💬 有疑问? 试试问我:"MCP 和 L4 的 OpenAI Function Calling 我应该选哪个?"、"生产环境部署 MCP Server 要注意什么?"、"MCP 生态什么时候能成熟?"——我会用代码或比喻为你解答。
1. MCP 相比单次对话中的工具调用参数格式,最核心的差别在于?
2. 关于 MCP 的三大原语,下列说法正确的是?
3. 按课程给出的 MCP 适用边界,下列判断最合理的是?