MCP Python SDK: @app.tool() decorator

@app.tool() is a Python decorator provided by the MCP Python SDK (specifically through FastMCP) that automatically registers a plain Python function as a remotely callable MCP tool. When you decorate a function with @app.tool(), the framework automatically extracts the function name, parameter types, and docstring to generate the protocol interface information, making the function available for LLMs to call via the MCP protocol.

CN: @app.tool() 是 MCP Python SDK(通过 FastMCP 提供)的一个 Python 装饰器,它会自动将一个普通的 Python 函数注册为一个可远程调用的 MCP 工具。当你用 @app.tool() 装饰一个函数时,框架会自动提取函数名、参数类型和文档字符串,生成协议接口信息,使该函数可以通过 MCP 协议被 LLM 调用。

Suppose you’re building an AI assistant for data engineering. You want the assistant to be able to run SQL queries on your data warehouse. Without @app.tool(), you’d have to write complex JSON-RPC handlers, manually parse incoming requests, validate parameters, execute the query, format the response, and handle errors. With @app.tool(), you just write:

假设你在为数据工程构建一个 AI 助手。你希望助手能对你的数据仓库执行 SQL 查询。没有 @app.tool(),你需要编写复杂的 JSON-RPC 处理器、手动解析传入请求、验证参数、执行查询、格式化响应并处理错误。有了 @app.tool(),你只需写:

@app.tool()
def run_sql_query(sql: str, database: str = "default") -> dict:
    """Execute a SQL query on the specified database and return results."""
    # Your SQL execution logic here
    return {"rows": [...], "row_count": 42}

The simplest form is decorating a synchronous function with @app.tool(). The framework uses the function name as the tool name, the docstring as the tool description, and the type hints as the input schema.

CN: 最简单的形式是用 @app.tool() 装饰一个同步函数。框架使用函数名作为工具名,docstring 作为工具描述,类型提示作为输入 schema。

Decorator parameter

装饰器参数

@app.tool() accepts several keyword arguments to customize the tool:

参数说明
name覆盖导出的 MCP 工具名称(默认使用函数名)
title客户端的简短显示标签
description人类可读的描述(省略时使用函数 docstring)
annotationsMCP 元数据的 ToolAnnotations 对象
icons客户端渲染用的图标
meta传递给 FastMCP 的任意元数据
structured_output设为 True 表示返回结构化 JSON

Code Implement

Envirment

# 安装 MCP Python SDK
pip install mcp httpx pydantic

MCP Server

# calculator_server.py
"""
A simple MCP Server that exposes calculator tools.
一个暴露计算器工具的简单 MCP Server。
"""

# 导入 FastMCP —— MCP Python SDK 的高层框架
# Import FastMCP - the high-level framework from MCP Python SDK
from mcp.server.fastmcp import FastMCP

# 创建 MCP 服务实例,命名服务标识
# Create MCP server instance with a service identifier
mcp = FastMCP("calculator_mcp")  # 服务名遵循 {service}_mcp 命名规范[reference:32]


# ============================================================
# 工具 1: 加法 —— 最基础的 @mcp.tool() 用法
# Tool 1: Addition - the most basic @mcp.tool() usage
# ============================================================
@mcp.tool()  # 装饰器自动将函数注册为 MCP 工具[reference:33]
def add(a: float, b: float) -> float:
    """
    Add two numbers together.
    将两个数相加。
    
    这个 docstring 会被自动提取为工具的 description,
    LLM 通过它理解工具的用途。[reference:34]
    """
    result = a + b
    return result  # 返回值会自动序列化为 JSON-RPC 响应[reference:35]


# ============================================================
# 工具 2: 带自定义名称和描述的加法
# Tool 2: Addition with custom name and description
# ============================================================
@mcp.tool(
    name="calculate_sum",           # 覆盖默认的函数名作为工具名[reference:36]
    description="Calculate the sum of two floating-point numbers",  # 覆盖 docstring
    annotations={"title": "Sum Calculator"}  # 客户端的显示标签[reference:37]
)
def add_with_custom_name(x: float, y: float) -> float:
    """This docstring is overridden by the description parameter above."""
    return x + y


# ============================================================
# 工具 3: 减法 —— 使用 Pydantic 模型做输入验证
# Tool 3: Subtraction - using Pydantic model for input validation
# ============================================================
from pydantic import BaseModel, Field

# 定义 Pydantic 输入模型 —— 自动生成输入 Schema[reference:38]
# Define Pydantic input model - auto-generates input schema
class SubtractInput(BaseModel):
    """Input model for subtraction operation."""
    a: float = Field(..., description="First number (minuend)", gt=-1e6, lt=1e6)
    b: float = Field(..., description="Second number (subtrahend)", gt=-1e6, lt=1e6)

@mcp.tool()
def subtract(input: SubtractInput) -> float:
    """
    Subtract two numbers: a - b.
    两个数相减:a - b。
    
    使用 Pydantic 模型作为输入参数,框架会自动:
    1. 生成 JSON Schema 描述输入格式
    2. 在调用时自动校验参数[reference:39]
    """
    return input.a - input.b


# ============================================================
# 工具 4: 乘法 —— 返回结构化输出
# Tool 4: Multiplication - with structured output
# ============================================================
from typing import Dict, Any

@mcp.tool(
    structured_output=True  # 提示返回的是结构化 JSON[reference:40]
)
def multiply(a: float, b: float) -> Dict[str, Any]:
    """
    Multiply two numbers and return detailed result.
    两个数相乘并返回详细结果。
    """
    product = a * b
    return {
        "operation": "multiply",
        "a": a,
        "b": b,
        "result": product,
        "formatted": f"{a} × {b} = {product}"
    }


# ============================================================
# 工具 5: 除法 —— 带错误处理
# Tool 5: Division - with error handling
# ============================================================
@mcp.tool()
def divide(a: float, b: float) -> Dict[str, Any]:
    """
    Divide a by b. Returns error if b is zero.
    a 除以 b。如果 b 为零则返回错误。
    """
    # 业务逻辑中的错误处理
    # Error handling in business logic
    if b == 0:
        return {
            "success": False,
            "error": "Division by zero is not allowed",
            "message": "除数不能为零"
        }
    
    result = a / b
    return {
        "success": True,
        "quotient": result,
        "remainder": a % b if b != 0 else None
    }


# ============================================================
# 工具 6: 异步工具 —— 调用外部 API
# Tool 6: Async tool - calling external API
# ============================================================
import httpx
from typing import Optional

@mcp.tool()  # 对于快速异步操作,可以用 @mcp.tool() + async
async def get_exchange_rate(
    from_currency: str,
    to_currency: str,
    amount: Optional[float] = 1.0
) -> Dict[str, Any]:
    """
    Get the exchange rate between two currencies.
    获取两种货币之间的汇率。
    
    异步函数可以直接 await 其他异步 API[reference:41]
    """
    # 实际生产环境应使用真实的汇率 API
    # In production, use a real exchange rate API
    url = f"https://api.exchangerate-api.com/v4/latest/{from_currency.upper()}"
    
    async with httpx.AsyncClient(timeout=10.0) as client:
        response = await client.get(url)
        response.raise_for_status()
        data = response.json()
    
    rate = data.get("rates", {}).get(to_currency.upper(), 0)
    converted = amount * rate
    
    return {
        "from": from_currency.upper(),
        "to": to_currency.upper(),
        "rate": rate,
        "amount": amount,
        "converted": converted
    }


# ============================================================
# 服务启动
# Service startup
# ============================================================
if __name__ == "__main__":
    # 启动 MCP 服务,默认使用 stdio 管道通信[reference:42]
    # Start MCP server, default uses stdio pipe communication
    mcp.run()

Key Takeaways

要点ENCN
@mcp.tool() 自动注册函数为 MCP 工具@mcp.tool() automatically registers a function as an MCP tool@mcp.tool() 自动将函数注册为 MCP 工具
函数名 → 工具名,docstring → 描述,类型提示 → 输入 SchemaFunction name → tool name, docstring → description, type hints → input schema函数名→工具名,docstring→描述,类型提示→输入 Schema
使用 Pydantic 模型实现自动输入验证Use Pydantic models for automatic input validation用 Pydantic 模型实现自动输入验证
structured_output=True 提示返回 JSONstructured_output=True hints the return is JSONstructured_output=True 提示返回 JSON
装饰器在导入时验证函数签名The decorator validates function signature at import time装饰器在导入时验证函数签名
同步工具用 @mcp.tool(),异步用 @mcp.tool() + asyncUse @mcp.tool() for sync, @mcp.tool() + async for async同步用 @mcp.tool(),异步用 @mcp.tool() + async
服务命名规范:{service}_mcpServer naming convention: {service}_mcp服务命名规范:{service}_mcp
启动服务:mcp.run()Start server: mcp.run()启动服务:mcp.run()