Discover and execute server-side tools with the FastMCP client.
New in version:2.0.0
Tools are executable functions exposed by MCP servers. The FastMCP client provides methods to discover available tools and execute them with arguments.
Execute a tool using call_tool() with the tool name and arguments:
Copy
async with client: # Simple tool call 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 (int) or {"result": 8} for primitive types # Access traditional content blocks print(result.content[0].text) # "8" (TextContent)
Tool execution returns a CallToolResult object with both structured and traditional content. FastMCP’s standout feature is the .data property, which doesn’t just provide raw JSON but actually hydrates complete Python objects including complex types like datetimes, UUIDs, and custom classes.
FastMCP exclusive: Fully hydrated Python objects with complex type support (datetimes, UUIDs, custom classes). Goes beyond JSON to provide complete object reconstruction from output schemas.
For tools without output schemas or when deserialization fails, .data will be None:
Copy
async with client: result = await client.call_tool("legacy_tool", {"param": "value"}) if result.data is not None: # Structured output available and successfully deserialized print(f"Structured: {result.data}") else: # No structured output or deserialization failed - use content blocks for content in result.content: if hasattr(content, 'text'): print(f"Text result: {content.text}") elif hasattr(content, 'data'): print(f"Binary data: {len(content.data)} bytes")
FastMCP servers automatically wrap non-object results (like int, str, bool) in a {"result": value} structure to create valid structured outputs. FastMCP clients understand this convention and automatically unwrap the value in .data for convenience, so you get the original primitive value instead of a wrapper object.
Copy
async with client: result = await client.call_tool("calculate_sum", {"a": 5, "b": 3}) # FastMCP client automatically unwraps for convenience print(result.data) # 8 (int) - the original value # Raw structured content shows the server-side wrapping print(result.structured_content) # {"result": 8} # Other MCP clients would need to manually access ["result"] # value = result.structured_content["result"] # Not needed with FastMCP!
For complete control, use call_tool_mcp() which returns the raw MCP protocol object:
Copy
async with client: result = await client.call_tool_mcp("potentially_failing_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()
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).