FastMCP: Defining Tools
Relevant source files
The following files were used as context for generating this wiki page:In the FastMCP framework, "tools" are Python functions exposed to an MCP client, allowing for remote execution. The framework automates the process of tool discovery, input validation, execution, and result serialization. This is primarily managed through the FastMCP application class and its @tool decorator.
The system is designed to introspect Python function signatures, including type hints and docstrings, to generate a schema that clients can use to understand and correctly call the tool. The ToolManager class is the core component responsible for managing the lifecycle of these tools, from registration to execution.
Core Components
The tool definition system revolves around three main components: FastMCP, ToolManager, and the Tool object.
This diagram shows that the FastMCP class uses a ToolManager instance to manage a collection of Tool objects.
Sources: tests/server/fastmcp/test_server.py:161-166, tests/server/fastmcp/test_tool_manager.py:15-28
FastMCP Class
The FastMCP class is the main entry point for creating a server. It provides the @mcp.tool() decorator to register functions as tools. It instantiates and holds a reference to a ToolManager to handle all tool-related operations.
Sources: tests/server/fastmcp/test_server.py:20-23
ToolManager Class
This class is responsible for the registration, storage, retrieval, and execution of tools. When a tool is added, the ToolManager creates a Tool instance, introspecting the function to generate its schema. When a client calls a tool, the ToolManager finds the tool, validates the arguments, executes the function, and handles the result.
Sources: tests/server/fastmcp/test_tool_manager.py:15-28, tests/server/fastmcp/test_tool_manager.py:203-211
Defining a Tool
The primary way to define a tool is by using the @mcp.tool() decorator on a Python function.
Basic Definition
The framework automatically uses the function's name as the tool name and its docstring as the description. Function parameters and their type hints are used to generate the input schema.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP()
@mcp.tool()
def sum(x: int, y: int) -> int:
"""Add two numbers."""
return x + y
Sources: tests/server/fastmcp/test_server.py:161-166, tests/server/fastmcp/test_tool_manager.py:22-33
The decorator must be called with parentheses, i.e., @mcp.tool(). Using it as @mcp.tool will result in a TypeError.
Sources: tests/server/fastmcp/test_server.py:168-174
Tool Registration Flow
The following diagram illustrates the process when a function is decorated with @mcp.tool().
Customizing Tool Metadata
You can override the default metadata by passing arguments to the decorator.
| Parameter | Type | Description |
|---|---|---|
name | str | Overrides the function name as the tool's name. Required for lambda functions. |
description | str | Overrides the function's docstring as the tool's description. |
title | str | A user-friendly display name for the tool. |
annotations | ToolAnnotations | Additional metadata, such as readOnlyHint. |
Sources: tests/server/fastmcp/test_title.py:18-30, tests/server/fastmcp/test_tool_manager.py:410-423, tests/server/fastmcp/test_tool_manager.py:141-143
Title Precedence
The display name for a tool is determined with the following precedence:
- The
titleargument in the decorator. - The
titlefield within theToolAnnotationsobject. - The tool's
name(i.e., the function name).
Sources: tests/server/fastmcp/test_title.py:141-156
Parameter Descriptions
To add descriptions for individual parameters, use pydantic.Field.
from pydantic import Field
from mcp.server.fastmcp import FastMCP
mcp = FastMCP()
@mcp.tool()
def greet(
name: str = Field(description="The name to greet"),
title: str = Field(description="Optional title", default=""),
) -> str:
"""A greeting tool"""
return f"Hello {title} {name}"
These descriptions will be included in the tool's inputSchema.
Sources: tests/server/fastmcp/test_parameter_descriptions.py:10-27
Tool Execution
When a client calls a tool, the server performs a series of steps to execute the function and return a result.
Execution Sequence Diagram
This diagram shows the interaction between a client and a FastMCP server during a tool call.
Error Handling
If an exception is raised inside a tool function, FastMCP catches it and returns a ToolResult with isError set to True. The error message and traceback are included in the TextContent of the response.
# Tool that will raise an exception
def error_tool_fn() -> None:
raise ValueError("Test error")
mcp.add_tool(error_tool_fn)
When error_tool_fn is called, the client receives a response indicating an error occurred, with "Test error" in the content.
Sources: tests/server/fastmcp/test_server.py:255-263
Advanced Features
Structured Output
Tools can return complex data types, and FastMCP will automatically serialize them.
| Return Type | structuredContent | content (Text) |
|---|---|---|
pydantic.BaseModel | The model serialized to a dict. | JSON representation of the model. |
dataclass | The dataclass serialized to a dict. | JSON representation of the dataclass. |
dict | The dictionary itself. | JSON representation of the dict. |
list | An object with a "result" key containing the list. | JSON representation of the list. |
Primitive (e.g., int, str) | An object with a "result" key containing the value. | String representation of the value. |
Image or Audio | None | An ImageContent or AudioContent block. |
Sources: tests/server/fastmcp/test_server.py:530-551, tests/server/fastmcp/test_tool_manager.py:491-503, tests/server/fastmcp/test_server.py:350-366
Context Injection
A tool can request a Context object by including it as a type-hinted parameter. This object provides access to the underlying server session, allowing the tool to perform actions like logging. The framework automatically detects and injects this object during the call; it is not part of the tool's public-facing input schema.
from mcp.server.fastmcp import Context
from mcp.server.session import ServerSession
@mcp.tool()
async def logging_tool(msg: str, ctx: Context[ServerSession, None]) -> str:
await ctx.info(f"Executing tool for message: {msg}")
return f"Logged messages for {msg}"
The ToolManager identifies the ctx parameter as the context argument and supplies it at runtime.
Sources: tests/server/fastmcp/test_server.py:910-918, tests/server/fastmcp/test_tool_manager.py:348-361, tests/server/fastmcp/test_server.py:953-990
Multimedia Content
The framework provides Image and Audio helper classes. When a tool returns an instance of one of these classes, FastMCP reads the specified file, base64-encodes its content, and determines the correct MIME type, packaging it into an ImageContent or AudioContent block.
from mcp.server.fastmcp.utilities.types import Image
@mcp.tool()
def get_image(path: str) -> Image:
# The Image class handles file reading and encoding
return Image(path)
This simplifies returning binary data from tools. The MIME type is inferred from the file extension.
Sources: tests/server/fastmcp/test_server.py:350-366, tests/server/fastmcp/test_server.py:368-384, tests/server/fastmcp/test_server.py:408-426
Summary
FastMCP provides a powerful and developer-friendly way to expose Python functions as tools. By leveraging decorators and type hints, it minimizes boilerplate code and automates schema generation, validation, and data serialization. Key features like structured output, context injection, and built-in multimedia handling enable the creation of robust and versatile tool servers.