声明:本文所有代码仅供学习参考,不构成任何投资建议。AI Agent 开发需遵守相关平台使用规范。
引言:为什么你的 AI Agent 还在"各自为战"?
2026 年,AI Agent 开发面临一个尴尬局面:每个 Agent 都要重新实现工具调用、数据连接、权限管理... 就像每个 APP 都要自己实现 USB 驱动一样低效。
痛点场景:
- 想让 Claude 访问你的数据库?写个专用接口
- 想让 Agent 读取本地文件?再写个文件服务
- 想切换大模型?代码全部重写
MCP(Model Context Protocol)协议就是为了解决这个问题而生——它像 USB-C 接口一样,让 AI Agent 可以"即插即用"任意数据源和工具。
本文带你从 0 到 1 实战 MCP 协议,用 3 步实现一个完整的 MCP Client + Server,让你的 Agent 具备连接任意数据源的能力。
一、MCP 协议核心概念:3 个关键抽象
MCP 协议定义了三个核心概念,理解它们就理解了 80% 的 MCP:
| 概念 | 作用 | 生活化比喻 |
|---|---|---|
| Resources | 提供只读数据(如文件、数据库记录) | "图书馆的书"——可以读,不能改 |
| Tools | 提供可执行操作(如搜索、计算) | "厨房的电器"——可以操作产生变化 |
| Prompts | 预定义的交互模板 | "菜谱"——指导如何完成任务 |
协议架构:
┌─────────────┐ ┌─────────────┐
│ MCP Client │ ←────→ │ MCP Server │
│ (你的 Agent)│ JSON │ (数据/工具) │
│ │ RPC │ │
└─────────────┘ └─────────────┘
↑ ↑
LLM API 数据源/工具
关键特性:
- 传输层:支持 stdio(进程间通信)和 HTTP(远程调用)
- 协议层:JSON-RPC 2.0 标准
- 安全层:权限控制 + 资源隔离
二、实战路径图:3 步构建 MCP 应用
步骤 1:环境准备与项目结构
创建项目目录:
mkdir mcp-practice && cd mcp-practice
mkdir -p mcp-server mcp-client
touch requirements.txt
安装依赖(requirements.txt):
# MCP SDK(官方 Python 实现)
mcp>=1.0.0
# HTTP 服务器(如果用 HTTP 传输)
uvicorn>=0.27.0
fastapi>=0.109.0
# 工具调用
httpx>=0.26.0
项目结构:
mcp-practice/
├── mcp-server/
│ ├── __init__.py
│ ├── server.py # MCP Server 主逻辑
│ └── tools/ # 工具实现
│ ├── database.py
│ └── filesystem.py
├── mcp-client/
│ ├── __init__.py
│ ├── client.py # MCP Client 主逻辑
│ └── llm_bridge.py # 与大模型桥接
└── requirements.txt
步骤 2:实现 MCP Server(提供数据/工具)
完整代码:mcp-server/server.py
#!/usr/bin/env python3
"""
MCP Server 示例:提供股票数据查询工具
功能:
1. 提供资源:股票基本信息
2. 提供工具:查询实时股价、历史 K 线
"""
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Resource, Tool, TextContent
import asyncio
import json
# 创建 Server 实例
server = Server("stock-data-server")
# 模拟股票数据(实际应连接真实 API)
STOCK_DATA = {
"000001.SZ": {"name": "平安银行", "price": 12.34, "change": 0.05},
"600519.SS": {"name": "贵州茅台", "price": 1789.50, "change": -0.02},
"00700.HK": {"name": "腾讯控股", "price": 380.20, "change": 0.015},
}
@server.list_resources()
async def list_resources() -> list[Resource]:
"""列出可用资源:A 股/港股股票数据"""
return [
Resource(
uri="stock://list",
name="股票列表",
description="所有可用股票行情数据",
mimeType="application/json",
)
]
@server.read_resource()
async def read_resource(uri: str) -> str:
"""读取资源:获取股票列表"""
if uri == "stock://list":
return json.dumps(STOCK_DATA, ensure_ascii=False, indent=2)
raise ValueError(f"未知资源:{uri}")
@server.list_tools()
async def list_tools() -> list[Tool]:
"""列出可用工具"""
return [
Tool(
name="get_stock_price",
description="获取单只股票实时价格",
inputSchema={
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "股票代码,如 000001.SZ",
}
},
"required": ["symbol"],
},
),
Tool(
name="get_stock_history",
description="获取股票历史 K 线数据",
inputSchema={
"type": "object",
"properties": {
"symbol": {"type": "string"},
"days": {"type": "integer", "description": "天数"},
},
"required": ["symbol", "days"],
},
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""工具调用处理"""
if name == "get_stock_price":
symbol = arguments.get("symbol")
if symbol not in STOCK_DATA:
return [TextContent(type="text", text=f"未找到股票:{symbol}")]
data = STOCK_DATA[symbol]
return [TextContent(
type="text",
text=f"{data['name']}({symbol}): ¥{data['price']} ({data['change']*100:+.2f}%)"
)]
elif name == "get_stock_history":
# 模拟历史数据
symbol = arguments.get("symbol")
days = arguments.get("days", 5)
return [TextContent(
type="text",
text=f"{symbol} 过去{days}天历史数据(模拟):[开盘,收盘,最高,最低]..."
)]
return [TextContent(type="text", text=f"未知工具:{name}")]
async def main():
"""启动服务器"""
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options(),
)
if __name__ == "__main__":
asyncio.run(main())
代码解析:
@server.list_resources():声明可用资源@server.read_resource():读取资源内容@server.list_tools():声明可用工具@server.call_tool():处理工具调用
步骤 3:实现 MCP Client(连接 LLM)
完整代码:mcp-client/client.py
#!/usr/bin/env python3
"""
MCP Client 示例:连接 MCP Server 并调用工具
"""
import asyncio
import json
from mcp.client import Client
from mcp.client.stdio import stdio_client
async def run_client():
"""客户端主逻辑"""
# 启动子进程运行 Server
async with stdio_client(["python", "mcp-server/server.py"]) as (read, write):
client = Client()
await client.initialize(read, write)
# 列出可用工具
tools = await client.list_tools()
print("可用工具:", [t.name for t in tools])
# 调用工具
result = await client.call_tool("get_stock_price", {"symbol": "000001.SZ"})
print("调用结果:", result)
# 列出资源
resources = await client.list_resources()
print("可用资源:", [r.name for r in resources])
# 读取资源
content = await client.read_resource("stock://list")
print("资源内容:", content)
if __name__ == "__main__":
asyncio.run(run_client())
三、进阶实战:与 LangChain 集成
mcp-client/langchain_bridge.py
from langchain.tools import Tool as LangChainTool
from mcp.client import Client
def create_mcp_tool(client: Client, tool_name: str, tool_def: dict) -> LangChainTool:
"""将 MCP 工具转换为 LangChain 工具"""
def tool_func(arguments: str) -> str:
"""工具执行函数"""
args = json.loads(arguments)
result = asyncio.run(client.call_tool(tool_name, args))
return result[0].text
return LangChainTool(
name=tool_name,
description=tool_def.get("description", ""),
func=tool_func,
)
# 使用示例
async def main():
async with stdio_client(["python", "mcp-server/server.py"]) as (read, write):
client = Client()
await client.initialize(read, write)
# 获取工具定义
tools = await client.list_tools()
# 转换为 LangChain 工具
langchain_tools = []
for tool in tools:
lc_tool = create_mcp_tool(client, tool.name, tool)
langchain_tools.append(lc_tool)
# 现在可以在 LangChain Agent 中使用
print(f"已创建 {len(langchain_tools)} 个 LangChain 工具")
四、完整工作流演示
场景:让 AI Agent 自动分析股票行情
# 1. 启动 MCP Server(提供股票数据)
# python mcp-server/server.py
# 2. 启动 MCP Client(连接 LLM)
# python mcp-client/llm_bridge.py
# 3. LLM 对话示例
"""
用户:帮我看看贵州茅台今天的价格
Agent:(调用 MCP 工具 get_stock_price)
Agent:贵州茅台 (600519.SS): ¥1789.50 (-2.00%)
用户:过去 5 天走势如何?
Agent:(调用 MCP 工具 get_stock_history)
Agent:过去 5 天数据:[1780, 1795, 1789, 1802, 1789]...
"""
五、错误示范 vs 正确写法
| 错误写法 | 正确写法 | 原因 |
|---|---|---|
| 直接在 Agent 代码中硬编码 API | 通过 MCP Server 抽象数据源 | 解耦,便于切换数据源 |
| 每个工具单独实现权限控制 | 统一在 MCP Server 层处理权限 | 集中管理,避免遗漏 |
| 用 HTTP 轮询获取数据 | 使用 MCP 的流式传输 | 减少延迟,节省资源 |
| 忽略错误处理 | 完整的异常捕获和重试机制 | 生产环境必备 |
六、生产环境建议
1. 安全配置
# 限制可访问的资源路径
ALLOWED_PATHS = ["/data/stocks", "/data/funds"]
# 权限验证
async def verify_permission(uri: str, user_id: str) -> bool:
if uri not in ALLOWED_PATHS:
return False
# 检查用户权限...
return True
2. 性能优化
- 使用连接池管理数据库连接
- 对频繁查询的数据做缓存(Redis)
- 异步并发处理多个请求
3. 监控告警
import logging
from prometheus_client import Counter
TOOL_CALLS = Counter('mcp_tool_calls_total', 'Total tool calls')
@server.call_tool()
async def call_tool(name: str, arguments: dict):
TOOL_CALLS.inc()
logging.info(f"Tool called: {name}")
# ...
总结
通过本文的实战,你完成了:
- ✅ 理解 MCP 协议的三个核心抽象(Resources/Tools/Prompts)
- ✅ 从零搭建 MCP Server 和 Client
- ✅ 实现股票数据查询工具
- ✅ 与 LangChain 集成
- ✅ 掌握生产环境最佳实践
MCP 协议的价值:
- 对开发者:一次实现,多处复用
- 对企业:降低 AI 集成成本
- 对生态:促进工具和数据的标准化
下一步学习:
- 实现自定义 MCP Server(连接你的数据库)
- 探索 MCP 的 HTTP 传输模式
- 研究 Anthropic 官方 MCP 文档
互动话题:
- 你的项目中有哪些数据源适合用 MCP 协议封装?
- 你觉得 MCP 协议最大的痛点是什么?
- 欢迎在评论区分享你的 MCP 实战经验!
代码获取: 完整代码已上传 GitHub:github.com/your-repo/m…
风险提示:本文代码仅供学习参考,不构成任何投资建议。实盘交易请谨慎评估风险。
#AI #Agent #MCP 协议 #LangChain #大模型 #工具调用 #2026 技术趋势