Function Tools
Function tools let you expose ordinary Python functions to an agent without running a separate MCP server.
They are local Python tools, distinct from MCP tools loaded from servers=[...].
When to use function tools
Use function tools when:
- the logic already lives in your Python application
- you want a lightweight tool without packaging an MCP server
- a tool is specific to one app or one agent
Use MCP tools when you need server-based discovery, reuse across processes, remote access, or the wider MCP ecosystem.
Global tools with @fast.tool
@fast.tool registers a local Python function tool globally for the application.
Agents that support local function tools receive these global tools unless they declare their own function_tools.
import asyncio
from fast_agent import FastAgent
fast = FastAgent("Function Tools Example")
@fast.tool
def get_weather(city: str) -> str:
"""Return the current weather for a city."""
return f"Sunny in {city}"
@fast.tool(name="add", description="Add two numbers together")
def add_numbers(a: int, b: int) -> int:
return a + b
@fast.agent(instruction="You are a helpful assistant with access to tools.")
async def main() -> None:
async with fast.run() as agent:
await agent.interactive()
if __name__ == "__main__":
asyncio.run(main())
Agent-scoped tools with @agent.tool
Use @agent.tool when a tool should only be available to one agent.
import asyncio
from fast_agent import FastAgent
fast = FastAgent("Tool Scoping Example")
@fast.agent(
name="writer",
instruction="You are a writing assistant with translation and summarization tools.",
default=True,
)
async def writer() -> None:
pass
@fast.agent(
name="analyst",
instruction="You analyse text. You can only count words.",
)
async def analyst() -> None:
pass
@writer.tool
def translate(text: str, language: str) -> str:
"""Translate text to the given language."""
return f"[{language}] {text}"
@writer.tool
def summarize(text: str) -> str:
"""Produce a one-line summary."""
return f"Summary: {text[:80]}..."
@analyst.tool(name="word_count", description="Count words in text")
def count_words(text: str) -> int:
"""Count the number of words in text."""
return len(text.split())
In this example:
writerseestranslateandsummarizeanalystseesword_count- neither agent receives tools scoped to the other
function_tools= in decorators
You can also configure local Python function tools directly:
def add(a: int, b: int) -> int:
return a + b
@fast.agent(
name="calculator",
instruction="You can add numbers.",
function_tools=[add],
)
async def calculator() -> None:
pass
The function_tools list may contain:
- Python callables
- string specs like
"tools.py:helper_name"
Scoping and inheritance rules
Function tool inheritance is intentionally simple:
- If an agent does not declare
function_tools, it receives global@fast.tooltools - If an agent uses
@agent.tool, those scoped tools become its explicit tool set - If an agent uses
function_tools=[...], only those tools are used - If an agent uses
function_tools=[], it opts out of global function tools entirely
This means global tools are a fallback, not something that is merged into every agent automatically.
Naming and descriptions
By default:
- tool name = Python function name
- tool description = function docstring
You can override these with name= and description=:
@fast.tool(name="sum_numbers", description="Add two integers together")
def add(a: int, b: int) -> int:
return a + b
The same applies to @agent.tool(...).
Reusing helpers across agents
Agent-scoped registrations keep metadata local to each registration. That means the same helper can be reused with different names or descriptions for different agents:
@fast.agent(name="support", instruction="Help support users.")
async def support() -> None:
pass
@fast.agent(name="billing", instruction="Help billing users.")
async def billing() -> None:
pass
def lookup_customer(customer_id: str) -> str:
"""Fetch customer details."""
return f"customer:{customer_id}"
support.tool(name="support_lookup", description="Lookup a support customer")(lookup_customer)
billing.tool(name="billing_lookup", description="Lookup a billing customer")(lookup_customer)
Sync and async functions
Both sync and async Python functions are supported:
@fast.tool
def sync_tool(value: int) -> int:
return value * 2
@fast.tool
async def async_tool(value: int) -> int:
return value * 2
Supported agent types
@agent.tool is available on:
@fast.agent(...)- supported
@fast.custom(...)agents whose constructor acceptstools=...
@agent.tool is not available on workflow decorators such as:
@fast.chain(...)@fast.router(...)@fast.parallel(...)@fast.orchestrator(...)@fast.maker(...)
For custom agents, function_tools= only works when the custom class accepts a tools=... constructor argument. Otherwise, fast-agent raises a configuration error.
Function tools vs MCP tools
These parameters do different things:
servers=[...]connects an agent to MCP serverstools={...}filters MCP tools by server nameresources={...}filters MCP resources by server nameprompts={...}filters MCP prompts by server namefunction_tools=[...]adds local Python function tools
So tools= and function_tools= are related, but they configure different tool sources.
Examples
Runnable examples in the main repository: