告别重复代码!FastMCP工具装饰器的高级方法封装指南

【免费下载链接】fastmcp The fast, Pythonic way to build Model Context Protocol servers 🚀 【免费下载链接】fastmcp 项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp

你是否还在为Python类方法与FastMCP装饰器的兼容性问题头疼?是否遇到过self参数暴露给LLM导致的调用失败?本文将通过3种实用模式+5个代码示例,带你掌握方法级别装饰的最佳实践,让工具封装既优雅又安全。

装饰器困境:为什么直接装饰会失败?

FastMCP的@tool@resource等装饰器会将函数转换为特定对象(如Tool实例),而非保留原函数引用。直接装饰类方法会导致两个严重问题:

  1. 方法不可调用:装饰后方法变为Tool对象,导致obj.method()调用失败
  2. 参数暴露异常self/cls参数被错误暴露给LLM,引发工具调用错误
**错误示范**:直接装饰实例方法 ```python from fastmcp import FastMCP mcp = FastMCP()

class Calculator: @mcp.tool # 错误:直接装饰实例方法 def add(self, x: int, y: int) -> int: return x + y

calc = Calculator() calc.add(1, 2) # 运行时错误:add是Tool对象而非函数

</Warning>

官方文档详细说明了这一限制:[docs/patterns/decorating-methods.mdx](https://link.gitcode.com/i/ea3aac04f4cf7cbe9e75cb302baa5394)。解决之道在于采用"先定义后注册"的装饰模式。

## 实例方法:动态绑定的正确姿势

实例方法需要先创建对象实例,再通过实例引用注册工具,确保`self`参数被正确绑定:

<Check>
**正确示范**:实例方法注册模式
```python
from fastmcp import FastMCP
mcp = FastMCP()

class DatabaseClient:
    def __init__(self, conn_str: str):
        self.connection = create_db_connection(conn_str)
        
    def query(self, sql: str) -> dict:
        """执行SQL查询并返回结果"""
        return self.connection.execute(sql).fetchall()

# 关键步骤:创建实例后注册方法
db_client = DatabaseClient("sqlite:///data.db")
mcp.tool(db_client.query)  # 注册绑定后的实例方法

此模式优势在于:

  • self参数被自动隐藏,LLM仅需提供sql参数
  • 实例化时可注入依赖(如数据库连接)
  • 支持多实例注册不同配置的工具

类方法:装饰器顺序与延迟注册

类方法装饰需特别注意装饰器顺序,错误顺序会导致难以调试的问题:

**错误示范**:错误的装饰器顺序 ```python class DataParser: @classmethod @mcp.tool # 危险:@classmethod在前会隐藏错误 def from_json(cls, data: str) -> "DataParser": return cls(**json.loads(data))
@mcp.tool
@classmethod  # 正确顺序但仍不推荐
def from_csv(cls, data: str) -> "DataParser":
    return cls(** csv.DictReader(data.splitlines()))
</Warning>

正确做法是采用延迟注册模式:

<Check>
**推荐方案**:类方法延迟注册
```python
class DataParser:
    @classmethod
    def from_json(cls, data: str) -> "DataParser":
        return cls(**json.loads(data))
        
    @classmethod
    def from_csv(cls, data: str) -> "DataParser":
        return cls(** csv.DictReader(data.splitlines()))

# 类定义后统一注册
mcp.tool(DataParser.from_json)
mcp.tool(DataParser.from_csv)

这种方式确保:

  • cls参数被正确绑定
  • 支持继承场景下的方法重写
  • 注册逻辑与类定义分离,便于维护

静态方法:看似可行的陷阱

静态方法虽然可以直接装饰,但会失去方法的可调用性,官方文档明确不推荐:

**不推荐做法**:直接装饰静态方法 ```python class StringUtils: @mcp.tool @staticmethod def to_uppercase(text: str) -> str: return text.upper()

问题:无法通过类调用原始方法

StringUtils.to_uppercase("test") # 返回Tool对象而非字符串

</Warning>

<Check>
**替代方案**:显式注册静态方法
```python
class StringUtils:
    @staticmethod
    def to_uppercase(text: str) -> str:
        return text.upper()

# 保持方法可调用性
mcp.tool(StringUtils.to_uppercase)

高级模式:初始化时自动注册

对于复杂组件,可在__init__中实现自动注册,将工具封装与注册逻辑内聚:

from fastmcp import FastMCP

class FileProcessor:
    def __init__(self, mcp: FastMCP, base_dir: str = "data/"):
        self.base_dir = base_dir
        # 初始化时自动注册所有工具方法
        self._register_tools(mcp)
        
    def read_file(self, filename: str) -> str:
        with open(f"{self.base_dir}/{filename}") as f:
            return f.read()
            
    def write_file(self, filename: str, content: str) -> None:
        with open(f"{self.base_dir}/{filename}", "w") as f:
            f.write(content)
            
    def _register_tools(self, mcp: FastMCP):
        mcp.tool(self.read_file)
        mcp.tool(self.write_file)

# 使用时自动完成注册
processor = FileProcessor(mcp, "documents/")

该模式在examples/config_server.py中有实际应用,特别适合:

  • 多工具组件封装
  • 需要依赖注入的场景
  • 模块化工具集管理

方法装饰决策指南

选择合适的装饰模式可参考以下决策树:

mermaid

通过本文介绍的模式,你可以:

  • 避免90%的装饰器使用错误
  • 保持类方法的OOP封装优势
  • 实现工具注册与业务逻辑分离

完整装饰器使用规范可参考官方文档:docs/patterns/decorating-methods.mdx,更多实际案例可查看examples/smart_home/中的设备控制类实现。

【免费下载链接】fastmcp The fast, Pythonic way to build Model Context Protocol servers 🚀 【免费下载链接】fastmcp 项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐