MCP Model‑Context‑Protocol协议调研
MCP(Model Context Protocol)是一套开放协议,用来统一大型语言模型与外部工具、数据源之间的通信方式。
它相当于给 AI Agent 装了一个标准 USB 接口:模型通过这个接口调用搜索、数据库、文件系统等能力,而不是为每个工具单独写一套对接逻辑。
本文面向刚接触 Agent 开发的读者,带你理解 MCP 的核心概念,并跑通一个最小示例,验证多工具协同的基本流程。
MCP 到底解决了什么问题
在没有 MCP 的时候,开发者要让 AI 调用某个工具,通常需要在代码里写死该工具的 API 地址、鉴权方式和返回格式。
每接入一个新工具,就要重新实现一遍。
Agent 的工具越多,代码越杂乱,维护成本直线上升。
MCP 的解决思路是把“工具能力”抽象成标准化的服务。
服务端暴露一个接口,客户端负责发现和调用,大模型只需要理解:某次请求需要调用哪个工具,参数是什么,结果如何拼进上下文。
这样工具提供商只需实现一次 MCP 服务,就可以被多个 Agent 复用。
核心概念:Server、Client 与工具
MCP 架构里有三个角色:
- MCP Server:负责提供具体工具,比如“查询天气”“读取文件”。它把工具能力封装成标准接口。
- MCP Client:负责连接 Server,把工具注册信息转发给大模型,并在模型决定调用时发起请求。
- 工具(Tool):Server 上每个可被调用的能力,通常包含名称、描述、输入参数 schema 和实际执行函数。
这套设计的关键在于:大模型本身不直接执行工具,它只是通过 Client 发出调用指令。
工具执行完的结果再返回给模型,让模型继续生成回答。
为什么 Agent 特别需要 MCP
Agent 的核心是“计划 → 调用工具 → 根据结果继续行动”。
如果工具接入五花八门,Agent 的决策逻辑就会被大量适配代码拖累。
MCP 的优势恰好体现在三处:
- 统一接口:所有工具都遵循同一套标准,模型只需学会一种调用方式。
- 动态发现:Client 启动时能从 Server 拉取工具列表,无需预先硬编码每个工具的细节。
- 安全可控:工具执行权限集中在 Server 端,模型只能按 schema 传参,不能越权执行任意代码。
有一个结论值得先记住:MCP 不是让所有工具变成同一个工具,而是让所有工具用同一种方式被模型理解和调用。
零基础体验:跑通最小 MCP 示例
下面我们用一个 Python 示例,亲手实现一个简单的 MCP Server 和 Client。
这里只演示协议通信逻辑,不依赖真实的大模型。
准备条件
- 安装 Python 3.8 或更高版本。
- 安装官方 Python SDK,建议在虚拟环境中执行:
pip install mcp
如果你是在国内网络环境,可以临时使用镜像源:
pip install mcp -i https://pypi.tuna.tsinghua.edu.cn/simple
编写一个最简单的 MCP Server
创建一个文件 server.py,内容如下:
from mcp.server import Server, stdio_server
from mcp.types import Tool, TextContent
app = Server("demo-server")
@app.list_tools()
async def list_tools():
return [
Tool(
name="add",
description="两个整数相加",
inputSchema={
"type": "object",
"properties": {
"a": {"type": "integer"},
"b": {"type": "integer"}
},
"required": ["a", "b"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "add":
result = arguments["a"] + arguments["b"]
return [TextContent(type="text", text=str(result))]
raise ValueError(f"未知工具: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
这段代码定义了一个名为 add 的工具,功能是两数相加。list_tools 告诉客户端“我有哪些工具”,call_tool 负责实际执行。
编写 MCP Client 进行调用
创建 client.py:
import asyncio
from mcp.client.stdio import stdio_client
from mcp.client.session import ClientSession
async def main():
async with stdio_client("python server.py") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print("发现工具:", [t.name for t in tools])
result = await session.call_tool("add", {"a": 3, "b": 5})
print("add(3,5) 结果:", result[0].text)
if __name__ == "__main__":
asyncio.run(main())
运行客户端:
python client.py
预期输出类似:
发现工具: ['add']
add(3,5) 结果: 8
如果看到这个结果,说明你已成功打通从 Client 到 Server 的完整链路。
这个最小的链路就是 Agent 多工具协同的地基:模型决定调用哪个工具,Client 负责传输,Server 执行并返回结果。
避坑说明与高频疑问
在跑这个示例时,有几个容易踩的坑值得提前说:
- SDK 版本差异:MCP 仍在快速演进,不同版本 API 可能有变化。如果代码报错,建议先检查
pip show mcp的版本,再看官方示例是否更新。 - 异步环境依赖:确保 Python 环境里有
asyncio,并且在 Jupyter 等交互式环境里运行时,可能需要额外配置事件循环。 - 不要混淆角色:这里的 Client 不是最终用户,而是连接模型和工具的中间层。你未来接入真实 Agent 时,模型往往充当“决策者”,Client 负责把决策变成工具调用。
有人会问:MCP 和普通 API 有什么区别?
普通 API 是“人写给程序调用的接口”,MCP 是“模型通过 Client 动态发现并调用的接口”,侧重点在标准化和自动化。
还有人问:多工具协同会不会很慢?
MCP 的通信开销不大,真正的性能瓶颈通常在工具自身的耗时,比如网络请求或数据库查询。
最后建议:如果你准备在自己的项目里使用 MCP,先从小工具开始,不要一开始就追求接入几十个服务。
跑通一个工具后,再逐步增加,并始终以官方文档和实际运行结果为准,因为协议版本还在快速迭代中。
本文的代码只是一个可验证的最小起点,理解它,你就抓住了 Agent 多工具协同的核心。