课程首页 › Module 6 · 协议与工程:MCP / Agent 协议 / 可信赖 / Context / Memory › L11

L11 MCP 协议:Agent 工具调用的"USB-C 接口"

课程目标:理解 MCP(Model Context Protocol)协议的原理与价值,能用 Python 实现一个最小的 MCP Server 和 Client。


一、一个让所有 Agent 开发者头疼的问题#

想象你是一个 Agent 框架作者(比如 LangChain 的工程师)。用户的需求五花八门:

每个需求你都要:

  1. 写一套工具适配代码(Tool Adapter)

  2. 处理不同数据源的身份认证

  3. 适配不同的传输协议(HTTP / WebSocket / gRPC)

  4. 写一份文档告诉用户怎么用

结果:LangChain 已经有 2000+ 个工具集成,但用户的新需求永远比这多。你永远在追赶用户需求。

有没有一种方式,让工具提供者自己实现一套标准接口,然后任何 Agent 都能"即插即用"?

MCP 就是为了解决这个问题的。


二、用一个比喻:MCP = Agent 世界的 USB-C#

把你的电脑想象成 Agent(LLM):

MCP 就是 Agent 世界的 USB-C:

这是 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 能暴露三种能力:

原语含义类比示例
ToolsLLM 可调用的函数(带参数)电脑的 USB 设备query_database(sql)、send_slack_message(channel, text)
ResourcesLLM 可读取的数据源(只读)电脑的文件系统读取 GitHub Issue 内容、读取本地 PDF
Prompts预设的提示词模板电脑的快捷指令"代码审查模板"、"周报生成模板"

注意区别:

两种传输方式#

传输适用场景通信方式
stdio本地进程(同台机器)标准输入输出
SSE / HTTP远程服务器(跨网络)Server-Sent Events 或 Streamable HTTP

四、和 L4 Tool Use 的关系#

你可能会问:MCP 和 L4 讲的 OpenAI Function Calling 有什么区别?

维度L4 Tool UseMCP
定义者OpenAI(单一公司)Anthropic 开源协议(多方采纳)
协议范围单次 LLM 调用的工具参数格式完整 Client-Server 通信协议
工具发现用户手动告诉 LLM"你有这些工具"Client 自动从 Server 发现
状态管理无状态(每次调用独立)有状态(Server 可保持连接、会话)
生态仅 OpenAI 系OpenAI、Google、Microsoft 都支持
适用规模小项目(几个工具)大规模生态(成百上千工具)

一句话:

类比:


五、动手实现:写一个 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', ...]

这段代码做了什么?

关键观察: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())

这段代码做了什么?

这就是 MCP 的威力:你的 LangGraph Agent 不需要任何改动,就能调用任何 MCP Server 暴露的工具。


八、MCP 生态全景#

截至 2026 年初,MCP 生态已经相当丰富:

官方 MCP Server(Anthropic 维护)#

第三方 MCP Server#

支持 MCP 的 Client#

行业趋势: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 smolagentssmolagents 正在集成 MCP(2025 年路线图)
L4 Tool Use 深入MCP 是 Tool Use 的标准化演进
L5 LangGraphLangGraph 通过 langchain-mcp-adapters 集成 MCP
L6 多 AgentMCP 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

打开浏览器后你能:

步骤 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 循环的进化版本:

主要参考:


十四、Sources#


💬 有疑问? 试试问我:"MCP 和 L4 的 OpenAI Function Calling 我应该选哪个?"、"生产环境部署 MCP Server 要注意什么?"、"MCP 生态什么时候能成熟?"——我会用代码或比喻为你解答。

自测 · 检验是否真的掌握了

1. MCP 相比单次对话中的工具调用参数格式,最核心的差别在于?

L4 的 Tool Use 解决的只是「一次 LLM 调用里怎么传工具参数」,而 MCP 用 JSON-RPC 定义了完整的 Client-Server 通信协议,Client 可以通过 list_tools 自动发现服务端能力,无需硬编码。工具数量、调用次数都不改变工具的本质,数据库访问权限也不会因为用了 MCP 而自动放开。

2. 关于 MCP 的三大原语,下列说法正确的是?

三大原语的分界是「做事」「读信息」「给预设指令」:Tools 是模型可调用的函数,往往带副作用;Resources 是只读数据源;Prompts 是用户主动触发的提示词模板。三者都通过同一套 Server 暴露给 Client,传输方式也不因原语类型而不同。

3. 按课程给出的 MCP 适用边界,下列判断最合理的是?

课程明确指出 MCP 适合工具数量较多、或工具提供方与 Agent 开发方分属不同团队、需要跨组织复用的场景;小项目只有两三个工具时直接用 L4 的 Tool Use 更简单。工具数量是参考而非硬阈值,安全上还要验证 Server 来源并限制权限,而 MCP 恰恰要求提供方实现 Server 端。