FastMCP入门指南:快速构建你的第一个AI助手工具服务器
1. 项目概述为什么选择 FastMCP 作为你的第一个 MCP 服务器如果你正在探索如何让 AI 助手比如 Claude、Cursor 等更深入地“理解”和“操作”你手头的工具、数据或服务那么 MCPModel Context Protocol就是你绕不开的技术栈。简单来说MCP 定义了一套标准协议让 AI 助手能够安全、可控地调用外部工具和资源而MCP 服务器就是实现这些具体功能的“后端服务”。那么为什么第一个 MCP 服务器项目要从 FastMCP 开始我自己的体会是它完美解决了“从零到一”的启动难题。市面上虽然有官方的 SDK但对于新手尤其是想快速验证一个想法、构建一个原型时那些 SDK 的抽象层级有时偏高配置也略显繁琐。FastMCP 则像它的名字一样追求“快”。它用 Python 的现代异步框架 FastAPI 作为基础提供了高度封装的装饰器让你能用最少的代码把一个普通的 Python 函数“暴露”成 AI 助手可以调用的工具。你不需要从零开始理解 MCP 协议底层的 WebSocket 握手、消息格式序列化FastMCP 把这些都封装好了你只需要关注核心逻辑“我这个工具要做什么输入什么输出什么。”举个例子你想让 AI 助手帮你查询当前服务器的 CPU 使用率。如果没有 MCP你只能手动执行top命令然后复制粘贴结果。有了 MCP你可以告诉助手“帮我看看系统负载。” 助手就会自动调用你写好的 MCP 服务器里的get_cpu_usage工具并把结果以结构化的方式返回给你。FastMCP 让编写这个get_cpu_usage工具的过程变得异常简单。这个项目适合谁我认为有三类人一是对 AI 智能体Agent开发感兴趣的开发者想亲手打造 AI 的“手和脚”二是希望提升日常开发效率的工程师通过定制工具让 AI 助手成为你的超级副驾三是任何想了解现代 AI 应用如何与外部系统交互的学习者。通过构建一个 FastMCP 服务器你不仅能掌握 MCP 的核心概念更能获得一个可立即投入使用的、能极大提升你与 AI 协作效率的实用工具。2. 核心概念与 FastMCP 设计哲学在动手写代码之前我们需要统一一下“语言”。理解 MCP 和 FastMCP 的几个核心概念能让你在后续开发中知其然更知其所以然遇到问题时也能快速定位。2.1 MCP 协议的核心三要素MCP 协议主要围绕三个核心资源进行交互你可以把它们想象成一套标准的“操作菜单”工具Tools这是最常用、最核心的部分。一个工具就是一个 AI 助手可以执行的函数或操作。每个工具必须有明确的名称、描述、输入参数定义JSON Schema。例如一个名为search_web的工具描述是“在互联网上搜索信息”输入参数可能包括query搜索关键词和limit结果数量。当 AI 助手认为需要调用这个工具时它会按照定义好的格式发送请求。资源Resources资源代表 AI 助手可以读取的静态或动态内容比如一个文件、一个数据库查询的结果页面、一个 API 返回的 JSON 数据。资源通过 URI 来标识并且可以声明其 MIME 类型如text/plain,application/json。AI 助手可以通过“读取”资源来获取上下文信息而无需调用一个“动作”。例如你可以提供一个file:///etc/hosts资源让助手读取你系统的 hosts 文件内容。提示词模板Prompts这是一组预定义的、参数化的文本模板。AI 助手可以获取这些模板并填入具体的参数快速生成符合特定场景的指令或问题。例如一个“代码审查”提示词模板可以接受code和language参数生成一段结构化的代码审查请求。这有助于标准化 AI 助手的交互模式。FastMCP 的设计哲学就是让开发者能够以最直观、最 Pythonic 的方式去定义这三样东西。它不强迫你去学习一套新的领域特定语言DSL而是让你用熟悉的 Python 类型提示和装饰器来完成一切。2.2 FastMCP 的“快”体现在哪里我总结为四个字约定优于配置。极简的工具定义使用mcp.tool()装饰器。你只需要像写普通异步函数一样写你的逻辑用pydantic模型来定义输入参数的类型和验证规则FastMCP 会自动帮你处理工具注册、Schema 生成、请求解析和响应封装。你几乎感觉不到协议层的存在。内置的协议处理FastMCP 基于 FastAPI天然支持异步和高性能。它内部实现了 MCP 协议要求的 SSEServer-Sent Events或 WebSocket 传输层以及标准的initialize,tools/list,tools/call等协议消息的处理。你不需要手动拼接任何 JSON-RPC 格式的消息。开箱即用的资源与提示词通过mcp.resource()和mcp.prompt()装饰器你可以用函数的形式动态定义资源和提示词逻辑清晰管理方便。便捷的依赖注入得益于 FastAPI 的依赖注入系统你可以轻松地在工具函数中注入数据库连接、配置对象、外部 API 客户端等使得代码结构非常整洁易于测试。用一个简单的类比如果你要造一辆车原始的 MCP SDK 给了你发动机、轮胎、方向盘的详细图纸和标准接口协议。而 FastMCP 直接给了你一个已经装好了发动机和底盘的车架你只需要把座椅业务逻辑装上去喷上漆配置参数就能直接上路了。它大幅降低了认知负担和初始开发成本。3. 开发环境搭建与项目初始化工欲善其事必先利其器。一个清晰的开发环境能避免很多后期依赖冲突的“坑”。下面是我推荐的设置流程兼顾了隔离性、可复现性和开发便利性。3.1 创建并激活独立的 Python 虚拟环境无论你使用venv,conda还是pipenv隔离环境是第一步。这里以最通用的venv为例。# 1. 为项目创建一个新目录 mkdir my-first-mcp-server cd my-first-mcp-server # 2. 创建虚拟环境假设使用 Python 3.10 python -m venv .venv # 3. 激活虚拟环境 # 在 Linux/macOS 上 source .venv/bin/activate # 在 Windows 上PowerShell # .venv\Scripts\Activate.ps1 # 在 Windows 上CMD # .venv\Scripts\activate.bat激活后你的命令行提示符前通常会显示(.venv)表示你已进入该虚拟环境。3.2 安装 FastMCP 及其核心依赖FastMCP 的核心依赖是fastapi和pydantic。通常使用pip安装。# 安装 fastmcp。它会自动拉取 fastapi, pydantic, uvicorn 等依赖。 pip install fastmcp # 为了更好的开发体验建议也安装一些辅助工具 pip install httpx # 用于在工具函数中调用外部API pip install python-dotenv # 用于管理环境变量注意务必在虚拟环境激活的状态下执行安装命令。安装完成后可以通过pip list查看已安装的包确认fastmcp在列表中。3.3 初始化项目结构一个清晰的项目结构有助于长期维护。我建议采用如下结构my-first-mcp-server/ ├── .env # 环境变量文件可选用于存储密钥等 ├── .gitignore # Git忽略文件 ├── pyproject.toml # 项目依赖和配置现代Python项目推荐 ├── src/ # 源代码目录 │ └── mcp_server/ # 我们的MCP服务器包 │ ├── __init__.py │ ├── main.py # 服务器主入口和工具定义 │ ├── tools/ # 工具模块目录可选用于分类 │ │ ├── __init__.py │ │ ├── system_tools.py │ │ └── web_tools.py │ └── config.py # 配置文件 └── README.md你可以先创建最精简的版本开始mkdir -p src/mcp_server touch src/mcp_server/__init__.py touch src/mcp_server/main.py现在打开src/mcp_server/main.py我们就可以开始编写第一个 MCP 服务器了。4. 编写你的第一个 FastMCP 服务器让我们从一个经典的“Hello World”开始但我们会给它加上一点实用的色彩让它成为一个真正有用的工具。4.1 基础骨架导入与服务器实例创建在main.py中首先导入必要的模块并创建 FastMCP 应用实例。# src/mcp_server/main.py from typing import Any import fastmcp import asyncio # 创建 FastMCP 应用实例。 # name 参数是你的服务器名称会显示在 AI 助手的工具列表中。 app fastmcp.FastMCP(My First MCP Server, version0.1.0)这个app对象就是你整个服务器的核心所有工具、资源、提示词的注册都将通过它来完成。4.2 定义第一个工具获取系统时间一个工具本质上就是一个异步函数。我们使用app.tool()装饰器来声明它。app.tool() async def get_current_time(timezone: str UTC) - str: 获取指定时区的当前时间。 Args: timezone: 时区名称例如 Asia/Shanghai, America/New_York。默认为 UTC。 Returns: 格式化后的当前时间字符串。 from datetime import datetime import pytz # 需要额外安装pip install pytz try: tz pytz.timezone(timezone) now datetime.now(tz) # 返回一个对人类和AI都友好的格式 return now.strftime(f%Y-%m-%d %H:%M:%S [%Z] (Timezone: {timezone})) except pytz.exceptions.UnknownTimeZoneError: return f错误未知的时区 {timezone}。请提供有效的时区名称如 UTC, Asia/Shanghai。代码解读与注意事项装饰器app.tool()这是最关键的一步。它告诉 FastMCP“这个函数是一个可供 AI 调用的工具。” FastMCP 会自动分析函数的签名函数名、参数、返回类型注解来生成符合 MCP 协议的工具定义JSON Schema。函数文档字符串Docstring这部分极其重要AI 助手如 Claude主要依靠这个描述来理解工具的用途、参数含义和返回值。描述应清晰、准确。Args和Returns部分使用 reStructuredText 或 Google 风格能帮助 AI 更好地解析。参数类型提示timezone: str UTC。类型提示str帮助 FastMCP 生成正确的 Schema。默认值 UTC让参数成为可选项使工具更易用。异步函数使用async def。虽然这个简单工具没有进行 I/O 操作但保持异步是 MCP 服务器的良好实践以便未来轻松集成需要等待的如网络请求、数据库查询工具。错误处理我们捕获了pytz.exceptions.UnknownTimeZoneError异常并返回一个友好的错误信息。在 MCP 工具中永远不要抛出未处理的异常这会导致调用失败并向 AI 返回难以理解的错误。应该总是返回一个结构化的错误信息字符串。实操心得工具函数的命名和描述要站在 AI 和用户的角度思考。get_current_time就比fetch_time更直观。描述中明确写出参数示例如Asia/Shanghai能显著提高 AI 调用工具时的准确率。4.3 定义第二个工具执行简单的计算让我们再添加一个稍微复杂点的工具展示如何处理结构化输入。from pydantic import BaseModel from typing import List, Optional # 使用 Pydantic 模型定义复杂输入 class CalculationInput(BaseModel): 计算操作的输入参数 operation: str Field(..., description运算类型支持 add, subtract, multiply, divide) numbers: List[float] Field(..., description参与运算的数字列表) precision: Optional[int] Field(2, description结果的小数点精度默认为2) app.tool() async def calculate(input_data: CalculationInput) - dict[str, Any]: 执行基本的算术运算。 支持加法、减法、乘法和除法。 result None op input_data.operation.lower() nums input_data.numbers try: if op add: result sum(nums) elif op subtract: if len(nums) ! 2: return {error: 减法运算需要且仅需要两个数字。} result nums[0] - nums[1] elif op multiply: product 1 for n in nums: product * n result product elif op divide: if len(nums) ! 2: return {error: 除法运算需要且仅需要两个数字。} if nums[1] 0: return {error: 除数不能为零。} result nums[0] / nums[1] else: return {error: f不支持的运算类型 {op}。请使用 add, subtract, multiply, 或 divide。} # 格式化结果 if input_data.precision is not None: result round(result, input_data.precision) return { operation: op, numbers: nums, result: result, formatted: f{result:.{input_data.precision}f} if input_data.precision else str(result) } except Exception as e: # 捕获其他意外错误 return {error: f计算过程中发生错误{str(e)}}为什么使用 Pydantic 模型结构化验证Pydantic 会自动验证输入数据是否符合CalculationInput模型的定义。例如如果客户端传来的operation不是字符串或者numbers不是数字列表在工具函数被执行前就会报错FastMCP 会返回标准的验证错误信息。这比在函数内部写一堆if判断要优雅和健壮得多。清晰的 Schema 生成FastMCP 结合 Pydantic 模型能生成非常详细、准确的 JSON Schema。AI 助手看到这个 Schema就能精确知道它需要提供什么样的数据。代码自文档化Field中的description参数会直接体现在工具 Schema 的描述里是给 AI 看的绝佳文档。4.4 运行你的 MCP 服务器现在我们需要让服务器跑起来。在main.py文件末尾添加以下代码# src/mcp_server/main.py 文件末尾 if __name__ __main__: # 使用 uvicorn 运行 FastMCP 应用。 # FastMCP 应用本身也是一个标准的 FastAPI 应用。 import uvicorn uvicorn.run( app, host0.0.0.0, # 监听所有网络接口 port8000, # 服务端口 log_levelinfo )然后在项目根目录下运行# 确保在虚拟环境中 python -m src.mcp_server.main如果一切顺利你会看到类似下面的输出表明你的第一个 MCP 服务器已经在http://0.0.0.0:8000上运行起来了INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRLC to quit)5. 连接与测试让 AI 助手使用你的工具服务器跑起来了但怎么用呢MCP 服务器通常不是通过浏览器直接访问的而是需要被 AI 助手客户端如 Claude Desktop、Cursor Agent 等连接。这里我们介绍两种测试方法使用官方测试客户端和模拟手动调用。5.1 使用 MCP 官方测试客户端推荐Anthropic 提供了一个命令行测试工具mcp-cli可以方便地发现和调用工具。# 首先在全局或另一个虚拟环境中安装 mcp-cli pip install mcp-cli # 假设你的服务器运行在本地 8000 端口使用 SSE 传输FastMCP 默认 mcp dev http://localhost:8000/sse运行后mcp-cli会连接到你的服务器列出所有可用的工具。你可以进入一个交互式会话输入自然语言如 “What time is it in Shanghai?”它会自动调用对应的get_current_time工具并返回结果。这是最接近真实 AI 助手行为的测试方式。5.2 模拟手动 HTTP 调用用于调试虽然 MCP 协议通常基于 SSE 或 WebSocket但 FastMCP 也暴露了标准的 HTTP 端点用于调试。你可以用curl或httpx来测试工具列表和调用。获取工具列表curl -X POST http://localhost:8000/tools/list \ -H Content-Type: application/json \ -d {}这会返回一个 JSON包含你定义的所有工具的详细 Schema。调用特定工具curl -X POST http://localhost:8000/tools/call \ -H Content-Type: application/json \ -d { name: get_current_time, arguments: { timezone: Asia/Shanghai } }响应会包含content字段里面就是工具返回的字符串结果。排查技巧实录如果调用失败首先检查服务器日志看是否有 Python 异常。最常见的错误是参数格式不匹配。确保arguments里的 JSON 对象完全符合工具 Schema 的要求。使用mcp-cli的--verbose标志可以输出更详细的通信日志对于调试协议层面的问题非常有帮助。6. 进阶功能与最佳实践当你掌握了基础工具的定义后可以探索 FastMCP 更强大的功能来构建更复杂、更实用的服务器。6.1 动态资源与提示词除了工具资源Resources和提示词Prompts也是 MCP 协议的重要部分。动态资源示例提供一个实时更新的配置文件内容。app.resource(config://app/settings) async def get_app_settings() - str: 获取当前应用程序的运行时配置。 这是一个动态资源每次读取都可能返回更新后的内容。 import json # 假设我们从某个地方环境变量、数据库、文件动态加载配置 config { environment: development, log_level: INFO, features: [tool_a, tool_b] } # 返回纯文本但结构化为 JSON 字符串便于 AI 解析 return json.dumps(config, indent2) # 资源可以通过 URI 来引用。AI 助手可以请求读取 config://app/settings 来获取这些配置信息。提示词模板示例创建一个代码审查的模板。app.prompt() async def code_review_prompt(code_snippet: str, language: str python) - str: 生成一个用于代码审查的提示词模板。 Args: code_snippet: 需要审查的代码片段。 language: 代码的编程语言。 return f请对以下 {language} 代码进行审查{code_snippet}请从以下方面提供反馈 1. **代码风格**是否符合该语言的通用规范如 PEP 8 for Python 2. **潜在错误**是否有语法错误、逻辑错误或潜在的运行时异常 3. **性能优化**是否有可以优化的地方如时间复杂度、空间复杂度 4. **安全性**是否存在安全隐患如注入、硬编码密钥 5. **改进建议**提供具体的、可操作的改进建议或重写代码。 请以清晰的结构化格式如列表回复。AI 助手可以获取这个模板然后填入用户提供的code_snippet和language参数快速生成一个高质量的代码审查请求。6.2 依赖注入管理共享状态在真实的项目中你的工具可能需要访问数据库连接、HTTP 客户端、配置管理器等共享对象。FastMCP 继承自 FastAPI支持强大的依赖注入系统。from fastapi import Depends import httpx # 1. 创建一个依赖项用于获取共享的 HTTP 客户端 async def get_http_client() - httpx.AsyncClient: # 这里可以实现连接池、重试逻辑等 async with httpx.AsyncClient(timeout30.0) as client: yield client # 2. 在工具中使用这个依赖项 app.tool() async def fetch_webpage_title( url: str, client: httpx.AsyncClient Depends(get_http_client) # 注入 ) - str: 获取给定网页的标题Title。 Args: url: 网页的 URL。 try: response await client.get(url) response.raise_for_status() # 简单的 HTML 标题提取生产环境建议用 BeautifulSoup import re match re.search(rtitle(.*?)/title, response.text, re.IGNORECASE) if match: return match.group(1).strip() else: return 未找到页面标题。 except httpx.RequestError as e: return f请求失败{str(e)} except Exception as e: return f处理页面时出错{str(e)}通过Dependsfetch_webpage_title工具自动获得了一个配置好的httpx.AsyncClient实例。这种方式保证了资源如 HTTP 连接的正确生命周期管理和复用也使得单元测试更容易你可以轻松地注入一个 Mock 客户端。6.3 错误处理与日志记录健壮的生产级服务器必须有良好的错误处理和日志。集中式错误处理你可以利用 FastAPI 的异常处理器。from fastapi import FastAPI, HTTPException from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse # app 是 FastMCP 实例它也是 FastAPI 实例 app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): 处理 Pydantic 参数验证错误 return JSONResponse( status_code422, content{detail: exc.errors(), message: 输入参数验证失败} ) app.exception_handler(Exception) async def general_exception_handler(request, exc): 处理其他未捕获的异常 # 记录到日志 app.logger.error(f未处理的异常: {exc}, exc_infoTrue) return JSONResponse( status_code500, content{message: 服务器内部错误请稍后重试。} )结构化日志在工具函数内部进行关键步骤的日志记录。import logging logger logging.getLogger(__name__) app.tool() async def complex_operation(param: str) - str: logger.info(f开始执行 complex_operation参数: {param}) # ... 业务逻辑 ... if some_condition: logger.warning(遇到了非预期条件但流程继续。) # ... 更多逻辑 ... logger.info(complex_operation 执行成功。) return 结果配置好日志后例如输出到文件并设置INFO级别你就能清晰地追踪每个工具的调用情况便于后期监控和问题排查。7. 部署与集成让工具真正用起来开发测试完成后你需要将 MCP 服务器部署起来并配置你的 AI 助手客户端来连接它。7.1 部署选项FastMCP 应用是一个标准的 FastAPI 应用因此所有支持 ASGI 的部署方式都适用。本地开发/测试如上所述直接使用uvicorn.run。适合快速迭代。生产环境部署方案 A使用 Uvicorn 配合进程管理器使用uvicorn作为 ASGI 服务器搭配gunicornwith uvicorn workers或supervisord/systemd进行进程管理。这是非常经典的部署方式。# 使用 gunicorn 启动适用于多核机器 gunicorn src.mcp_server.main:app -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000方案 B使用容器化部署将应用打包成 Docker 镜像使用 Docker Compose 或 Kubernetes 部署。这提供了最好的环境一致性和可扩展性。# Dockerfile 示例 FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [uvicorn, src.mcp_server.main:app, --host, 0.0.0.0, --port, 8000]方案 C平台即服务部署到云平台如 Railway, Fly.io, Google Cloud Run 等。这些平台简化了运维适合中小型项目。7.2 集成到 AI 助手客户端不同的 AI 助手客户端配置 MCP 服务器的方式不同。这里以Claude Desktop为例找到 Claude Desktop 的配置文件位置。macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json编辑该 JSON 文件在mcpServers部分添加你的服务器配置。{ mcpServers: { my-first-server: { command: uvicorn, args: [ src.mcp_server.main:app, --host, 0.0.0.0, --port, 8000 ], env: { PYTHONPATH: /path/to/your/project } } } }更安全的配置推荐对于生产环境或你不想手动启动服务器的情况可以将服务器部署为一个常驻服务如 systemd 服务或容器然后在配置中通过command: npx, args: [-y, mcp-client-http, http://localhost:8000/sse]等方式通过一个轻量级 HTTP 客户端桥接器来连接。或者如果服务器提供了稳定的 HTTP/SSE 端点可以直接配置其 URL。保存配置文件并重启 Claude Desktop。重启后在和 Claude 的对话中你应该能看到一个新出现的“工具”图标点击后能发现你定义的get_current_time和calculate等工具。现在你可以直接对 Claude 说“用上海时区看看现在几点” 它就会自动调用你的工具并返回结果了。7.3 性能优化与安全考量性能异步化确保所有涉及 I/O网络、磁盘、数据库的操作都使用异步库如httpx,aiofiles,asyncpg避免阻塞事件循环。连接池对于数据库、Redis 等外部服务使用连接池并确保在应用生命周期内复用。超时设置为所有外部调用设置合理的超时避免一个缓慢的工具拖垮整个服务器。安全输入验证永远不要信任客户端输入Pydantic 提供了基础的类型和范围验证。对于更复杂的逻辑如文件路径、命令参数必须在工具函数内部进行严格的校验和净化防止路径遍历、命令注入等攻击。权限控制MCP 协议本身不包含身份验证。如果你的工具涉及敏感操作需要在服务器层面实现认证和授权。一种常见模式是通过环境变量传递一个共享密钥或者在客户端配置中指定服务器在初始化连接时进行验证这需要自定义 MCP 服务器逻辑。更复杂的情况可以考虑在反向代理如 Nginx层做认证。网络隔离确保 MCP 服务器只监听在必要的网络接口上如127.0.0.1而非0.0.0.0特别是当它运行在个人电脑上时。使用防火墙规则限制访问来源。构建你的第一个 FastMCP 服务器就像是为你的 AI 助手打造了一把专属的瑞士军刀。从简单的查询工具开始逐步扩展到能操作你日常工作流中所有重要环节的自动化套件这个过程本身就充满了创造力和成就感。最关键的是FastMCP 极大地降低了实现这一切的门槛让你能专注于工具本身的价值而非协议的复杂性。现在就从get_current_time开始动手打造你的第一个 AI 可调用工具吧。