TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

FastMCP 工具(tools)怎么定义:参数、返回值与错误

讲清 FastMCP 工具怎么定义:参数类型与默认值、校验模式、docstring 描述、返回值与结构化输出,以及 ToolError 怎样给模型可行动的错误提示。

这篇适合谁,读完能做到什么

适合已经能跑起 FastMCP 服务器、想把自己的函数做成工具的读者。读完你应该能写出参数类型清楚、描述完整的工具,知道返回值会以什么形式交给客户端,并能让错误信息对模型有用,同时不把内部细节暴露出去。

工具是什么

在 FastMCP 中,工具就是通过 MCP 协议暴露给大模型调用的 Python 函数。它让模型能访问训练数据之外的外部系统、执行代码、读取数据[1]。模型调用工具时,会按工具的 schema 发送参数;FastMCP 用函数签名校验这些参数,执行函数,再把结果交还给模型[1]。

用 @mcp.tool 定义工具

在函数上加上 @mcp.tool,就能把它注册为工具[1]:

from fastmcp import FastMCP

mcp = FastMCP(name="CalculatorServer")

@mcp.tool
def add(a: int, b: int) -> int:
    """Adds two integer numbers together."""
    return a + b

注册时,FastMCP 用函数名作为工具名,并从 docstring 中读取工具描述[1]。输入 schema 由参数和类型标注生成,参数校验和错误报告也由 FastMCP 负责[1]。

参数怎么写

类型标注

FastMCP 用标准的 Python 类型标注决定参数的类型[1]。下面是 analyze_text 的例子[1]:

@mcp.tool
def analyze_text(
    text: str,
    max_tokens: int = 100,
    language: str | None = None
) -> dict:
    """Analyze the provided text."""
    # Implementation...

常见类型都可以直接用,包括 int、float、str、bool、list[str]、dict[str, int]、Literal、Enum、Path、UUID,以及 Pydantic 模型[1]。有几个地方要特别注意:

  • bytes 参数接收的是原始字符串,不会自动做 base64 解码。如果传入的是 base64 数据,应当声明为 str,再用 base64.b64decode() 手动解码[1]。
  • 枚举参数:客户端发送的是值,例如 "red",而不是名字 "RED";函数收到的是枚举成员[1]。
  • 字符串会自动转换成 Path 和 UUID 对象[1]。
  • Pydantic 模型必须以 JSON 对象(dict)的形式传入,不能是字符串化的 JSON[1]。

必填和可选

没有默认值的参数是必填的,有默认值的参数是可选的[1]。

校验模式

默认情况下,FastMCP 使用 Pydantic 的宽松校验,会把兼容的输入转换成声明的类型,例如把字符串 "10" 转为整数。这对经常发送字符串的 LLM 客户端更友好[1]。如果想严格一些,可以这样开启:FastMCP("StrictServer", strict_input_validation=True),开启后 "10" 这类转换会被拒绝[1]。

用 docstring 写描述

FastMCP 能解析 Google、NumPy 和 Sphinx 三种风格的 docstring,提取工具描述和每个参数的描述[1]。如果参数已经用 Annotated 或 Field(description=...) 写了描述,则以它为准,docstring 作为补充[1]。

返回值

FastMCP 工具的返回值有两种形式:传统的内容块(content blocks),以及结构化输出(structured output)。加上返回类型标注后,还会生成输出 schema[1][2]。

  • 返回 str 时,以 TextContent 发送[1]。
  • 返回 bytes 时,能按 UTF-8 解码就解码,否则做 base64 编码,同样以 TextContent 发送。如果想把二进制数据作为带 MIME 类型的嵌入资源发送,应当返回 File[1]。

结构化输出是 2025-06-18 版 MCP 规范引入的:它是随传统内容一起发送的一个 JSON 对象[2]。FastMCP 的自动规则如下[1]:

  • 对象类结果(dict、Pydantic 模型、dataclass)总是会生成结构化内容。
  • 非对象结果(int、str、list)只有在存在输出 schema 时才会生成结构化内容。
  • 所有结果都会生成传统内容块,以保证兼容性。

对于 int、str、bool 这类基本类型,FastMCP 会把结果包在结构化输出的 "result" 键下[1]。

输出 schema 同样是 2025-06-18 版规范引入的。工具一旦声明了输出 schema,就必须返回与之匹配的结构化输出;FastMCP 会根据返回类型标注生成这个 schema[1][2]。

用 ToolResult 完全控制返回

如果需要同时控制内容、结构化数据和元数据,可以返回 ToolResult 对象[1]:

from fastmcp.tools import ToolResult
from mcp.types import TextContent

@mcp.tool
def advanced_tool() -> ToolResult:
    """Tool with full control over output."""
    return ToolResult(
        content=[TextContent(type="text", text="Human-readable summary")],
        structured_content={"data": "value", "count": 42},
        meta={"execution_time_ms": 145}
    )

ToolResult 至少要提供 content 和 structured_content 中的一个[1]。

错误处理

ToolError 用来给模型一条它能据此行动的消息。它也适用于预期内的业务错误,例如日期范围不合法、实体 ID 不存在,并不只是服务器故障时才用[1]。

FastMCP 的异常类分四种。ToolError 表示工具无法完成操作;ValidationError 表示参数或返回值校验失败;AuthorizationError 表示访问被拒绝;NotFoundError 表示组件查找失败,例如工具、资源或提示不存在[1]。

默认的错误处理下,ToolError、ValidationError 和 AuthorizationError 如果抵达 tools/call 处理器,会变成一个 isError: true 的工具结果。它是描述调用失败的 JSON-RPC 结果,不同于带数字错误码的 JSON-RPC 错误[1]。

如果不想把内部异常细节暴露出去,可以设置 mask_error_details=True。开启后,工具执行中的普通异常会被屏蔽;ToolError 和 ValidationError 仍保留原消息,所以这些消息必须能安全地发给调用方[1]。下面的例子只把日期范围错误作为可行动的提示返回,其他内部错误被屏蔽[1]:

import logging
from datetime import date

from fastmcp import FastMCP
from fastmcp.exceptions import ToolError

mcp = FastMCP("DateTools", mask_error_details=True)


@mcp.tool
def count_days(start_date: date, end_date: date) -> int:
    """Count the days in a date range."""
    if start_date >= end_date:
        raise ToolError(
            "start_date must be before end_date. Please correct the date range.",
            log_level=logging.WARNING,
        )
    return (end_date - start_date).days

ToolError 的 log_level 参数控制它在工具执行日志中的级别,默认是 logging.ERROR[1]。ValidationError 在工具执行时以 WARNING 级别记录,日志里不包含参数值、校验位置和校验器消息,因为这些内容可能含有客户端的私有数据[1]。

限制

  • 带 *args 或 **kwargs 的函数不能作为工具,因为 FastMCP 必须为 MCP 协议生成完整的参数 schema[1]。
  • Pydantic 模型参数不接受字符串化的 JSON,bytes 参数不会自动解码 base64[1]。
  • 错误消息要人工确认是否安全。开启 mask_error_details=True 后,只有普通异常会被屏蔽,显式抛出的 ToolError 和 ValidationError 原样返回[1]。

下一步

想看参数元数据、超时、组件可见性等更多细节,可以接着读 FastMCP 工具文档的全文[1]。

本文改编自 FastMCP 官方文档中的工具(Tools)页面[1],并参考了 MCP 规范中关于结构化内容和输出 schema 的说明[2],原文以 Apache-2.0 许可证发布。

来源

  1. 1
    FastMCP ToolsFastMCP docs (Apache-2.0)
  2. 2

引用本页: FastMCP 工具(tools)怎么定义:参数、返回值与错误. TellWorld, https://www.tellworld.net/zh/practice/practice-fastmcp-tools. 更新于 2026-11-14

相关动态