--- title: Tool Transformation sidebarTitle: Tool Transformation description: Modify tool schemas - rename, reshape arguments, and customize behavior icon: wrench tag: NEW --- import { VersionBadge } from '/snippets/version-badge.mdx' Tool transformation lets you modify tool schemas - renaming tools, changing descriptions, adjusting tags, and reshaping argument schemas. FastMCP provides two mechanisms that share the same configuration options but differ in timing. **Deferred transformation** with `ToolTransform` applies modifications when tools flow through a transform chain. Use this for tools from mounted servers, proxies, or other providers where you don't control the source directly. **Immediate transformation** with `Tool.from_tool()` creates a modified tool object right away. Use this when you have direct access to a tool and want to transform it before registration. ## ToolTransform The `ToolTransform` class is a transform that modifies tools as they flow through a provider. Provide a dictionary mapping original tool names to their transformation configuration. ```python from fastmcp import FastMCP from fastmcp.server.transforms import ToolTransform from fastmcp.tools.tool_transform import ToolTransformConfig mcp = FastMCP("Server") @mcp.tool def verbose_internal_data_fetcher(query: str) -> str: """Fetches data from the internal database.""" return f"Results for: {query}" # Rename the tool to something simpler mcp.add_transform(ToolTransform({ "verbose_internal_data_fetcher": ToolTransformConfig( name="search", description="Search the database.", ) })) # Clients see "search" with the cleaner description ``` `ToolTransform` is useful when you want to modify tools from mounted or proxied servers without changing the original source. ## Tool.from_tool() Use `Tool.from_tool()` when you have the tool object and want to create a transformed version for registration. ```python from fastmcp import FastMCP from fastmcp.tools import Tool, tool from fastmcp.tools.tool_transform import ArgTransform # Create a tool without registering it @tool def search(q: str, limit: int = 10) -> list[str]: """Search for items.""" return [f"Result {i} for {q}" for i in range(limit)] # Transform it before registration better_search = Tool.from_tool( search, name="find_items", description="Find items matching your search query.", transform_args={ "q": ArgTransform( name="query", description="The search terms to look for.", ), }, ) mcp = FastMCP("Server") mcp.add_tool(better_search) ``` The standalone `@tool` decorator (from `fastmcp.tools`) creates a Tool object without registering it to any server. This separates creation from registration, letting you transform tools before deciding where they go. ## Modification Options Both mechanisms support the same modifications. **Tool-level options:** | Option | Description | |--------|-------------| | `name` | New name for the tool | | `description` | New description | | `title` | Human-readable title | | `tags` | Set of tags for categorization | | `annotations` | MCP ToolAnnotations | | `meta` | Custom metadata dictionary | **Argument-level options** (via `ArgTransform` or `ArgTransformConfig`): | Option | Description | |--------|-------------| | `name` | Rename the argument | | `description` | New description for the argument | | `default` | New default value | | `default_factory` | Callable that generates a default (requires `hide=True`) | | `hide` | Remove from client-visible schema | | `required` | Make an optional argument required | | `type` | Change the argument's type | | `examples` | Example values for the argument | ## Hiding Arguments Hide arguments to simplify the interface or inject values the client shouldn't control. ```python from fastmcp.tools.tool_transform import ArgTransform # Hide with a constant value transform_args = { "api_key": ArgTransform(hide=True, default="secret-key"), } # Hide with a dynamic value import uuid transform_args = { "request_id": ArgTransform(hide=True, default_factory=lambda: str(uuid.uuid4())), } ``` Hidden arguments disappear from the tool's schema. The client never sees them, but the underlying function receives the configured value. `default_factory` requires `hide=True`. Visible arguments need static defaults that can be represented in JSON Schema. ## Renaming Arguments Rename arguments to make them more intuitive for LLMs or match your API conventions. ```python from fastmcp.tools import Tool, tool from fastmcp.tools.tool_transform import ArgTransform @tool def search(q: str, n: int = 10) -> list[str]: """Search for items.""" return [] better_search = Tool.from_tool( search, transform_args={ "q": ArgTransform(name="query", description="Search terms"), "n": ArgTransform(name="max_results", description="Maximum results to return"), }, ) ``` ## Custom Transform Functions For advanced scenarios, provide a `transform_fn` that intercepts tool execution. The function can validate inputs, modify outputs, or add custom logic while still calling the original tool via `forward()`. ```python from fastmcp import FastMCP from fastmcp.tools import Tool, tool from fastmcp.tools.tool_transform import forward, ArgTransform @tool def divide(a: float, b: float) -> float: """Divide a by b.""" return a / b async def safe_divide(numerator: float, denominator: float) -> float: if denominator == 0: raise ValueError("Cannot divide by zero") return await forward(numerator=numerator, denominator=denominator) safe_division = Tool.from_tool( divide, name="safe_divide", transform_fn=safe_divide, transform_args={ "a": ArgTransform(name="numerator"), "b": ArgTransform(name="denominator"), }, ) mcp = FastMCP("Server") mcp.add_tool(safe_division) ``` The `forward()` function handles argument mapping automatically. Call it with the transformed argument names, and it maps them back to the original function's parameters. For direct access to the original function without mapping, use `forward_raw()` with the original parameter names.