---
schema: rendered-html/v1
title: "Calling Tools - FastMCP"
source_url: https://gofastmcp.com/clients/tools
generated_at: 2026-06-11T19:37:12.088993+00:00
---




[FastMCP home page![light logo](images/gofastmcp__com__clients__tools__wordmark.avif)![dark logo](images/gofastmcp__com__clients__tools__wordmark-white.avif)](gofastmcp__com.md)







Operations

Calling Tools

















  - [Tools](/clients/tools)
  - [Resources](gofastmcp__com__clients__resources.md)
  - [Prompts](gofastmcp__com__clients__prompts.md)
  - [Sampling](gofastmcp__com__clients__sampling.md)
  - [Elicitation](gofastmcp__com__clients__elicitation.md)
  - [Tasks

    NEW](gofastmcp__com__clients__tasks.md)
  - [Progress](gofastmcp__com__clients__progress.md)
  - [Logging](gofastmcp__com__clients__logging.md)
  - [Roots](gofastmcp__com__clients__roots.md)
  - [Notifications](gofastmcp__com__clients__notifications.md)






- [Basic Execution](#basic-execution)
- [Execution Options](#execution-options)
- [Structured Results](#structured-results)
- [Error Handling](#error-handling)
- [Sending Metadata](#sending-metadata)
- [Raw Protocol Access](#raw-protocol-access)

Operations

# Calling Tools


Execute server-side tools and handle structured results.


New in version `2.0.0`
Use this when you need to execute server-side functions and process their results.
Tools are executable functions exposed by MCP servers. The client’s `call_tool()` method executes a tool by name with arguments and returns structured results.

## [​](#basic-execution) Basic Execution

async with client:
    result = await client.call_tool("add", {"a": 5, "b": 3})
    # result -> CallToolResult with structured and unstructured data

    # Access structured data (automatically deserialized)
    print(result.data)  # 8

    # Access traditional content blocks
    print(result.content[0].text)  # "8"

Arguments are passed as a dictionary. For multi-server clients, tool names are automatically prefixed with the server name (e.g., `weather_get_forecast` for a tool named `get_forecast` on the `weather` server).

## [​](#execution-options) Execution Options

The `call_tool()` method supports timeout control and progress monitoring:

async with client:
    # With timeout (aborts if execution takes longer than 2 seconds)
    result = await client.call_tool(
        "long_running_task",
        {"param": "value"},
        timeout=2.0

    # With progress handler
    result = await client.call_tool(
        "long_running_task",
        {"param": "value"},
        progress_handler=my_progress_handler

## [​](#structured-results) Structured Results

New in version `2.10.0`
Tool execution returns a `CallToolResult` object. The `.data` property provides fully hydrated Python objects including complex types like datetimes and UUIDs, reconstructed from the server’s output schema.

from datetime import datetime
from uuid import UUID

async with client:
    result = await client.call_tool("get_weather", {"city": "London"})

    # FastMCP reconstructs complete Python objects
    weather = result.data
    print(f"Temperature: {weather.temperature}C at {weather.timestamp}")

    # Complex types are properly deserialized
    assert isinstance(weather.timestamp, datetime)
    assert isinstance(weather.station_id, UUID)

    # Raw structured JSON is also available
    print(f"Raw JSON: {result.structured_content}")

## CallToolResult Properties

[​](#param-data)

.data

Any

Fully hydrated Python objects with complex type support (datetimes, UUIDs, custom classes). FastMCP exclusive.

[​](#param-content)

.content

list[mcp.types.ContentBlock]

Standard MCP content blocks (`TextContent`, `ImageContent`, `AudioContent`, etc.).

[​](#param-structured-content)

.structured\_content

dict[str, Any] | None

Standard MCP structured JSON data as sent by the server.

[​](#param-is-error)

.is\_error

bool

Boolean indicating if the tool execution failed.

For tools without output schemas or when deserialization fails, `.data` will be `None`. Fall back to content blocks in that case:

async with client:
    result = await client.call_tool("legacy_tool", {"param": "value"})

    if result.data is not None:
        print(f"Structured: {result.data}")
    else:
        for content in result.content:
            if hasattr(content, 'text'):
                print(f"Text result: {content.text}")

FastMCP servers automatically wrap primitive results (like `int`, `str`, `bool`) in a `{"result": value}` structure. FastMCP clients automatically unwrap this, so you get the original value in `.data`.

## [​](#error-handling) Error Handling

By default, `call_tool()` raises a `ToolError` if the tool execution fails:

from fastmcp.exceptions import ToolError

async with client:
    try:
        result = await client.call_tool("potentially_failing_tool", {"param": "value"})
        print("Tool succeeded:", result.data)
    except ToolError as e:
        print(f"Tool failed: {e}")

To handle errors manually instead of catching exceptions, disable automatic error raising:

async with client:
    result = await client.call_tool(
        "potentially_failing_tool",
        {"param": "value"},
        raise_on_error=False

    if result.is_error:
        print(f"Tool failed: {result.content[0].text}")
    else:
        print(f"Tool succeeded: {result.data}")

## [​](#sending-metadata) Sending Metadata

New in version `2.13.1`
The `meta` parameter sends ancillary information alongside tool calls for observability, debugging, or client identification:

async with client:
    result = await client.call_tool(
        name="send_email",
        arguments={
            "to": "user@example.com",
            "subject": "Hello",
            "body": "Welcome!"
        },
        meta={
            "trace_id": "abc-123",
            "request_source": "mobile_app"

See [Client Metadata](gofastmcp__com__servers__context.md) to learn how servers access this data.

## [​](#raw-protocol-access) Raw Protocol Access

For complete control, use `call_tool_mcp()` which returns the raw MCP protocol object:

async with client:
    result = await client.call_tool_mcp("my_tool", {"param": "value"})
    # result -> mcp.types.CallToolResult

    if result.isError:
        print(f"Tool failed: {result.content}")
    else:
        print(f"Tool succeeded: {result.content}")
        # Note: No automatic deserialization with call_tool_mcp()

[fastmcp-remote

Previous](gofastmcp__com__clients__fastmcp-remote.md)[Reading Resources

Next](gofastmcp__com__clients__resources.md)






