@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) |
annotations | MCP 元数据的 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()

