手把手教你用 Python 和 FastAPI 搭建第一个 MCP 服务器
目录
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() 装饰器自动完成了三件事:
- 提取元数据:读取函数名、文档字符串(作为工具描述)和参数类型。
- 生成 Schema:将 Python 类型转换为 JSON Schema,供 AI 理解参数要求。
- 注册路由:将该函数暴露为 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 的支持非常友好。
-
打开 Cursor 设置,找到 MCP 选项卡。
-
点击 Add New MCP Server。
-
选择 HTTP 类型(如果你运行的是 uvicorn 服务)。
-
在配置框中输入服务器名称(如
Local Weather)和 URL 地址:{ "mcpServers": { "local-weather": { "url": "http://127.0.0.1:8000/mcp" } } }注意:具体 URL 路径取决于
fastapi-mcp的默认挂载点,通常是/mcp或/sse。 -
保存后,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 直接操作你代码的乐趣吧。
更多推荐

所有评论(0)