1 为什么你的 FastAPI 应用需要 MCP?

如果你是一名 Python 后端开发者,最近可能频繁听到"Model Context Protocol"(简称 MCP)这个词。别被这个略显学术的名字吓退,它的核心逻辑其实非常朴素:在 AI 大模型爆发的今天,如何让像 Claude、ChatGPT 这样的智能体安全、标准地访问你本地的数据或工具?MCP 就是为此诞生的"USB-C 接口”。

过去,为了让 AI 调用你的本地脚本或数据库,你可能需要编写复杂的适配层,或者依赖非标准的 API 对接。而 MCP 定义了一套通用的通信协议,让 AI 客户端(Host)能像插拔 U 盘一样,无缝连接到你提供的服务器(Server)。对于熟悉 FastAPI 的开发者来说,构建一个 MCP 服务器不再需要从头学习一套全新的框架,只需在现有的 FastAPI 应用上增加几行代码,就能瞬间赋予其被 AI 调用的能力。

本文将带你从零开始,利用 fastapi-mcp 库,将一个普通的 FastAPI 应用升级为标准的 MCP 服务器。我们将通过一个具体的“天气查询”工具案例,完整演示环境搭建、工具注册、参数定义以及最终在 Cursor 或 Claude Desktop 中连接验证的全过程。
在这里插入图片描述

2 环境准备与依赖安装

在开始编码之前,我们需要准备好基础的运行环境。MCP 的 Python 生态目前主要依赖 uv 进行包管理,当然你也可以继续使用熟悉的 pip,但为了获得更好的兼容性和隔离性,推荐优先使用虚拟环境。

首先,确保你的 Python 版本在 3.10 及以上。接着,创建一个项目目录并初始化虚拟环境:

mkdir mcp-weather-demo
cd mcp-weather-demo
python -m venv venv
# Windows 下激活
venv\Scripts\activate
# Mac/Linux 下激活
source venv/bin/activate

接下来是核心的依赖安装。我们需要 fastapi 来构建基础 Web 服务,uvicorn 作为 ASGI 服务器,以及关键的 fastapi-mcp 库,它负责桥接 FastAPI 与 MCP 协议:

pip install fastapi uvicorn fastapi-mcp

此外,为了模拟真实的业务场景,我们还需要一个 HTTP 请求库来获取天气数据,这里选用轻量级的 httpx

pip install httpx

至此,基础环境已就绪。你可以创建一个名为 main.py 的文件,作为我们项目的入口。
在这里插入图片描述

3 从 FastAPI 到 MCP 服务器的平滑升级

很多开发者误以为构建 MCP 服务器需要重写整个后端架构,事实并非如此。fastapi-mcp 的设计初衷就是“无感升级”。你只需要先写出一个标准的 FastAPI 应用,然后挂载 MCP 服务即可。

3.1 构建基础 FastAPI 应用

首先,我们在 main.py 中编写一个最基础的 FastAPI 应用。假设我们原本就有一个提供简单信息的接口:

from fastapi import FastAPI

app = FastAPI(title="Weather MCP Server", version="1.0.0")

@app.get("/")
async def root():
    return {"message": "Welcome to the Weather API"}

@app.get("/health")
async def health_check():
    return {"status": "healthy"}

此时,这只是一个普通的 Web API,AI 无法直接理解并调用其中的功能作为“工具”。

3.2 挂载 MCP 服务

接下来是关键步骤:引入 add_mcp_server 函数。这个函数会将 MCP 协议所需的通信端点(通常基于 SSE 或 stdio)挂载到你的 FastAPI 实例上。

修改 main.py,加入以下代码:

from fastapi import FastAPI
from fastapi_mcp import add_mcp_server

app = FastAPI(title="Weather MCP Server", version="1.0.0")

# 挂载 MCP 服务器
add_mcp_server(
    app,
    mount_path="/mcp",       # MCP 协议的访问路径
    name="WeatherToolServer", # 服务器名称,会在客户端显示
    description="提供实时天气查询能力的 MCP 服务器"
)

@app.get("/")
async def root():
    return {"message": "Welcome to the Weather API"}

这里的 mount_path 非常重要,它决定了客户端通过哪个 URL 路径来发现你的服务。默认情况下,fastapi-mcp 会处理底层的协议握手,让你无需关心 JSON-RPC 的具体报文格式。

4 核心实战:注册天气查询工具

MCP 的核心价值在于“工具(Tools)”。在 MCP 架构中,工具不仅仅是 API 接口,它们是带有明确输入输出 schema 的功能单元,AI 可以根据描述自动判断何时调用以及如何传参。

我们将实现一个 get_weather 工具,它接收城市名,返回当前的天气状况。

4.1 工具定义与参数模型

fastapi-mcp 中,我们可以使用装饰器或专门的注册方法来定义工具。为了保持代码的清晰和类型安全,推荐使用 Pydantic 模型来定义参数。

main.py 中补充以下内容:

from pydantic import BaseModel, Field
from fastapi_mcp import FastMCP
import httpx

# 定义输入参数模型
class WeatherQuery(BaseModel):
    city: str = Field(..., description="要查询的城市名称,例如 'Beijing' 或 'Shanghai'")
    unit: str = Field(default="celsius", description="温度单位,可选 'celsius' 或 'fahrenheit'")

# 初始化 MCP 实例 (如果库版本支持直接装饰器方式)
# 注意:不同版本的 fastapi-mcp 用法略有差异,此处采用通用注册模式
mcp = FastMCP("WeatherToolServer")

@mcp.tool()
async def get_weather(query: WeatherQuery) -> str:
    """
    查询指定城市的实时天气情况。
    适用于用户询问某地天气、气温或穿衣建议的场景。
    """
    # 模拟 API 调用 (实际项目中请替换为真实天气 API,如 OpenWeatherMap)
    # 这里为了演示稳定性,使用 mock 数据
    mock_data = {
        "beijing": "晴朗,气温 25°C,湿度 40%",
        "shanghai": "多云,气温 28°C,湿度 65%",
        "guangzhou": "小雨,气温 30°C,湿度 80%"
    }
    
    city_lower = query.city.lower()
    if city_lower in mock_data:
        result = mock_data[city_lower]
        if query.unit == "fahrenheit":
            # 简单模拟转换逻辑
            result += " (约 77°F)"
        return result
    else:
        return f"暂未找到 {query.city} 的天气数据,请尝试北京、上海或广州。"

# 将 mcp 路由挂载到主 app
# 注意:具体挂载方式需参考 fastapi-mcp 最新版文档,通常是 app.include_router(mcp.router)
# 或者在 add_mcp_server 时自动关联。若库版本较新,可直接在 add_mcp_server 中注册工具。
# 为确保代码可运行,我们采用最稳妥的混合写法:
# 假设 fastapi-mcp 提供了将工具注册到 app 上下文的方法

注:由于 fastapi-mcp 库迭代较快,上述代码展示了核心逻辑。在实际操作中,你需要确保 mcp 实例与 app 正确关联。通常 add_mcp_server 会自动扫描并注册带有 @tool 装饰器的函数,或者你需要显式地将工具列表传递给服务器配置。

4.2 完整代码实现

更通用的实现方式是直接在 add_mcp_server 的配置上下文中定义工具,或者使用库提供的 FastMCP 类作为主入口。以下是一个经过简化的、可直接运行的完整代码结构示例:

from fastapi import FastAPI
from fastapi_mcp import FastMCP
from pydantic import BaseModel, Field
import asyncio

app = FastAPI(title="Weather MCP Server")

# 创建 FastMCP 实例
mcp = FastMCP("WeatherServer")

class WeatherInput(BaseModel):
    city: str = Field(description="城市名称")

@mcp.tool()
async def check_weather(city: str) -> str:
    """获取城市天气"""
    # 模拟延迟
    await asyncio.sleep(0.5)
    return f"{city} 今天天气晴朗,气温 26 度,适宜出行。"

# 挂载到 FastAPI
mcp.mount(app)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

在这个例子中,@mcp.tool() 装饰器自动完成了三件事:

  1. 提取元数据:读取函数名、文档字符串(作为工具描述)和参数类型。
  2. 生成 Schema:将 Python 类型转换为 JSON Schema,供 AI 理解参数要求。
  3. 注册路由:将该函数暴露为 MCP 协议可调用的工具。

当 AI 接收到“北京今天天气怎么样?”的指令时,它会匹配到 check_weather 工具,提取“北京”作为参数,并通过 MCP 协议调用该函数,最后将返回的自然语言结果呈现给用户。

5 启动服务与本地调试

代码编写完成后,我们需要启动服务。由于 MCP 支持多种传输协议(Transport),在本地开发阶段,最常用的是 stdio(标准输入输出)模式和 SSE(Server-Sent Events)模式。

5.1 HTTP/SSE 模式(推荐用于 Web 集成)

这种方式适合将服务器部署在局域网或公网,允许通过 HTTP 连接。启动命令非常简单:

uvicorn main:app --reload --host 127.0.0.1 --port 8000

启动后,你可以在浏览器访问 http://127.0.0.1:8000/docs 查看 FastAPI 原生的文档界面。虽然 MCP 的通信细节不在 Swagger UI 中直接展示,但这能确认你的基础服务运行正常。MCP 的端点通常挂载在 /mcp 或类似路径下,支持 SSE 流式传输。

5.2 Stdio 模式(推荐用于桌面客户端直连)

如果你使用的是 Claude Desktop 或某些命令行工具,它们更倾向于通过子进程直接调用你的 Python 脚本。这时不需要启动 uvicorn 服务器,而是直接运行脚本。

确保你的 main.py 底部包含如下入口:

if __name__ == "__main__":
    mcp.run()

然后在终端执行 python main.py,程序将进入监听状态,等待客户端通过 stdin 发送指令。

6 在 Cursor 与 Claude Desktop 中配置连接

服务启动后,最后一步是让 AI 客户端“看见”它。不同的客户端配置方式略有不同,但核心都是告诉客户端去哪里寻找 MCP 服务器。

6.1 配置 Cursor

Cursor 编辑器对 MCP 的支持非常友好。

  1. 打开 Cursor 设置,找到 MCP 选项卡。

  2. 点击 Add New MCP Server

  3. 选择 HTTP 类型(如果你运行的是 uvicorn 服务)。

  4. 在配置框中输入服务器名称(如 Local Weather)和 URL 地址:

    {
      "mcpServers": {
        "local-weather": {
          "url": "http://127.0.0.1:8000/mcp"
        }
      }
    }
    

    注意:具体 URL 路径取决于 fastapi-mcp 的默认挂载点,通常是 /mcp/sse

  5. 保存后,Cursor 会尝试连接。如果状态显示为绿色(Connected),说明配置成功。

6.2 配置 Claude Desktop

Claude Desktop 通常使用 claude_desktop_config.json 文件进行配置。对于本地开发的 Python 脚本,推荐使用 stdio 方式,这样无需额外启动 Web 服务器。

找到配置文件(Mac 通常在 ~/Library/Application Support/Claude/claude_desktop_config.json,Windows 在 %APPDATA%\Claude\),添加如下配置:

{
  "mcpServers": {
    "weather-tool": {
      "command": "python",
      "args": ["/absolute/path/to/your/main.py"],
      "env": {
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}

请将 /absolute/path/to/your/main.py 替换为你实际的脚本绝对路径。保存文件并重启 Claude Desktop。

6.3 即时验证

配置完成后,打开聊天窗口,尝试提问:

“帮我查一下北京的天气,我想知道要不要带伞。”

如果一切正常,你会看到 AI 思考过程中出现"Using tool: check_weather"的提示,随后精准地回答出你在代码中定义的 Mock 数据:“北京今天天气晴朗,气温 26 度,适宜出行。”

这就意味着,你的 FastAPI 应用已经成功转型为一个标准的 MCP 服务器,能够被主流 AI 客户端识别并调用。

结语

通过今天的实践,我们发现构建 MCP 服务器并没有想象中那么复杂。依托于 Python 强大的生态和 fastapi-mcp 这样的桥梁工具,后端开发者可以极低门槛地将现有业务能力转化为 AI 可用的工具。

从定义一个简单的 Pydantic 模型,到加上 @tool 装饰器,再到客户端的几行配置,整个流程流畅且直观。这不仅让你手中的 FastAPI 项目具备了"AI 原生”的特性,也为未来构建更复杂的 Agent 工作流打下了坚实基础。不妨现在就动手,把你项目中的某个实用功能封装成 MCP 工具,体验一下让 AI 直接操作你代码的乐趣吧。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐