MCP 协议从 0 到 1 实战路径图:给 AI Agent 装上"万能接口",3 步实现工具调用(完整代码)

10 阅读6分钟

声明:本文所有代码仅供学习参考,不构成任何投资建议。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())

代码解析:

  1. @server.list_resources():声明可用资源
  2. @server.read_resource():读取资源内容
  3. @server.list_tools():声明可用工具
  4. @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}")
    # ...

总结

通过本文的实战,你完成了:

  1. ✅ 理解 MCP 协议的三个核心抽象(Resources/Tools/Prompts)
  2. ✅ 从零搭建 MCP Server 和 Client
  3. ✅ 实现股票数据查询工具
  4. ✅ 与 LangChain 集成
  5. ✅ 掌握生产环境最佳实践

MCP 协议的价值:

  • 对开发者:一次实现,多处复用
  • 对企业:降低 AI 集成成本
  • 对生态:促进工具和数据的标准化

下一步学习:

  • 实现自定义 MCP Server(连接你的数据库)
  • 探索 MCP 的 HTTP 传输模式
  • 研究 Anthropic 官方 MCP 文档

互动话题:

  • 你的项目中有哪些数据源适合用 MCP 协议封装?
  • 你觉得 MCP 协议最大的痛点是什么?
  • 欢迎在评论区分享你的 MCP 实战经验!

代码获取: 完整代码已上传 GitHub:github.com/your-repo/m…

风险提示:本文代码仅供学习参考,不构成任何投资建议。实盘交易请谨慎评估风险。

#AI #Agent #MCP 协议 #LangChain #大模型 #工具调用 #2026 技术趋势