从 0 到 1:用 Python 开发 MCP 工具,让 AI 智能体拥有 “超能力”

【个人主页:玄同765

大语言模型(LLM)开发工程师中国传媒大学·数字媒体技术(智能交互与游戏设计)

**深耕领域:**大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调

**技术栈:**Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️

**工程能力:**专注模型工程化部署、知识库构建与优化,擅长全流程解决方案

专栏传送门: LLM大模型开发 项目实战指南Python 从真零基础到纯文本 LLM 全栈实战​​​​​从零学 SQL + 大模型应用落地大模型开发小白专属:从 0 入门 Linux&Shell

「让AI交互更智能,让技术落地更高效」

欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!

在 AI 智能体时代,工具调用能力 是衡量智能体 "智商" 的核心标准 ------ 一个只会聊天的智能体价值有限,但能读取文档、操作数据库、调用 API 的智能体,才能真正成为开发者的 "全能助手"。而MCP(Model Context Protocol) 就是让智能体与外部工具顺畅沟通的 "通用语言"。

如果你之前用过mcp-docx-reader这类工具,肯定好奇它是怎么实现的。本文将从MCP 核心概念Python 开发实战智能体集成三个维度,带你亲手开发一个 MCP 工具,让你的 AI 智能体拥有读取 PDF 文档的 "超能力"。


一、先搞懂:什么是 MCP?

1. MCP 的本质:智能体与工具的 "通信协议"

MCP 是一套标准化的 AI 智能体 - 工具交互协议,它定义了智能体如何调用工具、工具如何返回结果的规范。简单来说:

  • 智能体是 "用户",它通过 MCP 发送调用请求;
  • MCP 工具是 "服务端",它接收请求、执行逻辑、返回结果;
  • 协议本身是 "通信规则",确保不同厂商的智能体和工具能无缝对接。

2. MCP 的核心优势

相比直接写 API 接口,MCP 的优势在于:

  • 跨平台兼容:支持 Trae IDE、LangChain Agent、LLaMAIndex 等主流智能体平台;
  • 标准化格式:无需为每个智能体平台单独适配,一次开发多平台可用;
  • 内置元数据:工具可返回参数描述、示例,智能体能自动理解工具功能;
  • 错误处理规范:统一的错误格式,智能体能优雅处理异常。

3. MCP 的核心协议结构

MCP 基于 HTTP/JSON 通信,核心分为请求格式响应格式

请求格式(智能体→工具)
复制代码
{
  "tool_name": "pdf_reader", // 要调用的工具名称
  "parameters": { // 工具所需参数
    "file_path": "./document.pdf",
    "page_range": [1, 10]
  }
}
响应格式(工具→智能体)
复制代码
{
  "result": { // 执行成功时返回的结果
    "text": "文档第1-10页的内容...",
    "page_count": 10
  },
  "error": null // 执行失败时返回错误信息
}

二、环境准备:Python 开发 MCP 的必备依赖

开发 MCP 工具需要以下环境和依赖:

  1. Python 版本:≥3.10(支持异步语法和新特性);
  2. Web 框架:FastAPI(异步优先,自动生成 OpenAPI 文档,适合写 MCP 接口);
  3. 数据校验:Pydantic(定义请求响应模型,自动校验参数);
  4. PDF 解析:PyPDF2 或 pdfplumber(用于实现 PDF 读取功能);
  5. 运行服务器:Uvicorn(FastAPI 的官方 ASGI 服务器)。

安装命令:

复制代码
pip install fastapi pydantic uvicorn pdfplumber

三、实战 1:写第一个 MCP 服务器 ------ 计算器工具

先从最简单的计算器工具入手,熟悉 MCP 的开发流程:

1. 项目结构

复制代码
mcp-calculator/
├── main.py          # 主程序,包含MCP服务器和工具逻辑
└── requirements.txt # 依赖清单

2. 编写 MCP 服务器代码

复制代码
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any

# 1. 初始化FastAPI应用
app = FastAPI(title="MCP计算器工具", version="1.0.0")

# 2. 定义MCP请求模型(智能体发送的请求格式)
class MCPRequest(BaseModel):
    tool_name: str = Field(..., description="要调用的工具名称")
    parameters: Dict[str, Any] = Field(..., description="工具所需参数")

# 3. 定义MCP响应模型(工具返回的结果格式)
class MCPResponse(BaseModel):
    result: Optional[Dict[str, Any]] = Field(None, description="执行成功的结果")
    error: Optional[str] = Field(None, description="执行失败的错误信息")

# 4. 实现计算器工具逻辑
def calculate(operation: str, num1: float, num2: float) -> float:
    """计算器核心逻辑:支持加减乘除"""
    if operation == "add":
        return num1 + num2
    elif operation == "subtract":
        return num1 - num2
    elif operation == "multiply":
        return num1 * num2
    elif operation == "divide":
        if num2 == 0:
            raise ValueError("除数不能为0")
        return num1 / num2
    else:
        raise ValueError(f"不支持的操作:{operation}")

# 5. 定义MCP接口(智能体调用的入口)
@app.post("/mcp", response_model=MCPResponse)
async def handle_mcp_request(request: MCPRequest) -> MCPResponse:
    try:
        # 校验工具名称
        if request.tool_name != "calculator":
            return MCPResponse(error=f"不支持的工具:{request.tool_name}")
        
        # 提取并校验参数
        operation = request.parameters.get("operation")
        num1 = request.parameters.get("num1")
        num2 = request.parameters.get("num2")
        
        if not all([operation, num1, num2]):
            return MCPResponse(error="缺少必要参数:operation、num1、num2")
        
        # 执行计算
        result = calculate(operation, float(num1), float(num2))
        return MCPResponse(result={"result": result, "operation": operation})
    
    except Exception as e:
        return MCPResponse(error=f"执行失败:{str(e)}")

# 6. 启动服务器
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

3. 测试 MCP 服务器

启动服务器后,用 curl 命令测试:

复制代码
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
  "tool_name": "calculator",
  "parameters": {
    "operation": "add",
    "num1": 10,
    "num2": 20
  }
}'

预期响应:

复制代码
{
  "result": {"result": 30.0, "operation": "add"},
  "error": null
}

四、实战 2:进阶 MCP 工具 ------PDF 文档读取器

现在升级到更实用的场景:开发一个能读取 PDF 文档的 MCP 工具,类似之前的mcp-docx-reader

1. 扩展代码:添加 PDF 读取功能

main.py中添加以下代码:

复制代码
import pdfplumber

# 4.2 实现PDF读取工具逻辑
def read_pdf(file_path: str, page_range: Optional[list] = None) -> Dict[str, Any]:
    """读取PDF文档内容,支持指定页码范围"""
    with pdfplumber.open(file_path) as pdf:
        total_pages = len(pdf.pages)
        # 处理页码范围,默认读取全部
        if page_range:
            start, end = page_range
            start = max(1, start)
            end = min(total_pages, end)
            pages = pdf.pages[start-1:end]  # pdfplumber页码从0开始
        else:
            pages = pdf.pages
            start, end = 1, total_pages
        
        # 提取每页文本
        text = ""
        for page in pages:
            text += page.extract_text() or ""
        
        return {
            "text": text.strip(),
            "page_count": len(pages),
            "total_pages": total_pages,
            "page_range": [start, end]
        }

# 5.1 扩展MCP接口,支持多工具
@app.post("/mcp", response_model=MCPResponse)
async def handle_mcp_request(request: MCPRequest) -> MCPResponse:
    try:
        # 计算器工具
        if request.tool_name == "calculator":
            operation = request.parameters.get("operation")
            num1 = request.parameters.get("num1")
            num2 = request.parameters.get("num2")
            
            if not all([operation, num1, num2]):
                return MCPResponse(error="缺少必要参数:operation、num1、num2")
            
            result = calculate(operation, float(num1), float(num2))
            return MCPResponse(result={"result": result, "operation": operation})
        
        # PDF读取工具
        elif request.tool_name == "pdf_reader":
            file_path = request.parameters.get("file_path")
            page_range = request.parameters.get("page_range")
            
            if not file_path:
                return MCPResponse(error="缺少必要参数:file_path")
            
            result = read_pdf(file_path, page_range)
            return MCPResponse(result=result)
        
        # 未知工具
        else:
            return MCPResponse(error=f"不支持的工具:{request.tool_name}")
    
    except Exception as e:
        return MCPResponse(error=f"执行失败:{str(e)}")

2. 测试 PDF 读取功能

复制代码
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
  "tool_name": "pdf_reader",
  "parameters": {
    "file_path": "./test.pdf",
    "page_range": [1, 5]
  }
}'

预期响应:

复制代码
{
  "result": {
    "text": "PDF第1-5页的内容...",
    "page_count": 5,
    "total_pages": 20,
    "page_range": [1, 5]
  },
  "error": null
}

五、集成到 Trae IDE:让智能体调用你的 MCP 工具

开发完成后,将 MCP 服务器集成到 Trae IDE,让智能体可以直接调用:

1. 启动 MCP 服务器

确保你的 MCP 服务器在本地运行(uvicorn main:app --host 0.0.0.0 --port 8000)。

2. 配置 Trae IDE 的 MCP 服务器

  1. 打开 Trae IDE,进入「智能体」面板→「⚙️ 配置」→「MCP 服务器配置」;

  2. 点击「添加自定义服务器」,输入以下配置:

    {
    "mcpServers": {
    "my-mcp-tools": {
    "command": "python",
    "args": [
    "/path/to/main.py"
    ]
    }
    }
    }

或者直接连接已运行的服务器:

复制代码
{
  "mcpServers": {
    "my-mcp-tools": {
      "url": "http://localhost:8000/mcp"
    }
  }
}

3. 智能体调用测试

在 Trae IDE 的智能体聊天窗口输入:

复制代码
帮我读取本地的test.pdf文档第1-5页的内容,用你会的工具完成。

智能体将自动调用你的pdf_reader工具,返回 PDF 内容。


六、进阶优化:让 MCP 工具更专业

1. 异步处理:提升并发性能

将 PDF 读取逻辑改为异步(需要使用支持异步的 PDF 库,如aiofiles配合pdfplumber):

复制代码
import aiofiles

async def read_pdf_async(file_path: str, page_range: Optional[list] = None) -> Dict[str, Any]:
    async with aiofiles.open(file_path, mode='rb') as f:
        pdf_data = await f.read()
        with pdfplumber.open(pdf_data) as pdf:
            # 后续逻辑同同步版本...

2. 日志记录:便于排查问题

添加日志功能,记录工具调用情况:

复制代码
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 在工具逻辑中添加日志
logger.info(f"调用计算器工具:operation={operation}, num1={num1}, num2={num2}")

3. 权限控制:限制非法调用

添加 API 密钥验证,确保只有授权的智能体可以调用:

复制代码
from fastapi import Header, HTTPException

async def verify_api_key(api_key: Optional[str] = Header(None)):
    if api_key != "your-secret-key":
        raise HTTPException(status_code=401, detail="无效的API密钥")

# 在接口中添加依赖
@app.post("/mcp", response_model=MCPResponse, dependencies=[Depends(verify_api_key)])

七、发布自己的 MCP 工具:让其他人一键安装

如果想让其他人使用你的 MCP 工具,可以用uv打包,实现一键安装:

1. 创建pyproject.toml

复制代码
[project]
name = "mcp-pdf-reader"
version = "1.0.0"
dependencies = [
  "fastapi>=0.100.0",
  "pydantic>=2.0.0",
  "uvicorn>=0.23.0",
  "pdfplumber>=0.10.0"
]

[project.scripts]
mcp-pdf-reader = "main:run"

2. 在main.py中添加启动函数

复制代码
def run():
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

if __name__ == "__main__":
    run()

3. 发布到 PyPI 或 GitHub

其他人可以通过以下命令一键安装并启动:

复制代码
# 从PyPI安装
pip install mcp-pdf-reader
mcp-pdf-reader

# 从GitHub安装
uvx --from git+https://github.com/yourname/mcp-pdf-reader mcp_pdf_reader

八、总结与展望

MCP 协议为 AI 智能体和外部工具搭建了标准化的桥梁,用 Python 开发 MCP 工具门槛低、灵活度高,能快速扩展智能体的能力边界。通过本文的实战,你已经掌握了:

  • MCP 协议的核心概念和规范;
  • 用 FastAPI+Pydantic 开发 MCP 服务器的流程;
  • 从简单计算器到实用 PDF 阅读器的工具开发;
  • 集成到 Trae IDE 并发布自己的 MCP 工具。

未来,MCP 生态会越来越完善,你可以开发更多实用工具:

  • 数据库操作工具:让智能体执行 SQL 查询;
  • API 调用工具:让智能体调用外部 API 获取数据;
  • 代码生成工具:让智能体生成并运行代码;
  • 多模态工具:让智能体处理图片、音频等非文本数据。

现在,动手开发你的第一个 MCP 工具,让 AI 智能体真正成为你的 "全能助手" 吧!

相关推荐
啊森要自信6 小时前
CANN ops-cv:AI 硬件端视觉算法推理训练的算子性能调优与实战应用详解
人工智能·算法·cann
要加油哦~6 小时前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能
czy87874756 小时前
深入了解 C++ 中的 `std::bind` 函数
开发语言·c++
新缸中之脑6 小时前
用RedisVL构建长期记忆
人工智能
消失的旧时光-19436 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed
yq1982043011566 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
一个public的class6 小时前
你在浏览器输入一个网址,到底发生了什么?
java·开发语言·javascript
J_Xiong01176 小时前
【Agents篇】07:Agent 的行动模块——工具使用与具身执行
人工智能·ai agent
Jinkxs6 小时前
Gradle - 与Groovy/Kotlin DSL对比 构建脚本语言选择指南
android·开发语言·kotlin