# Adding Tools URL: /concepts/tools/adding-tools Define your tool function and register it with tambo. Tools are asynchronous functions that take in a single argument and return a single value. ```tsx //define the tool function. This is your own custom function and can perform any logic you want. const getWeather = async (city: string) => { try { const weather = await fetch( `http://api.weatherapi.com/v1/current.json?key=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}&q=${city}`, ); return weather.json(); } catch (error) { throw new Error(`Failed to fetch weather for ${city}`); } }; // Create a TamboTool definition including your tool function export const tools: TamboTool[] = [ { name: "get_weather", description: "Fetch current weather information for a specified city", tool: getWeather, toolSchema: z .function() .args(z.string().describe("The city to fetch weather for")) .returns( z.object({ location: z.object({ name: z.string(), }), }), ), }, ]; // Register your tools with Tambo ; ``` Now tambo can fetch weather information for a city when responding to a message! ## Returning Rich Content By default, tool responses are converted to strings and sent back to the AI as text. However, tools can return rich content like images, audio, or mixed media by using the `transformToContent` parameter. The `transformToContent` function transforms your tool's return value into an array of content parts before sending it back to the AI. This is useful when your tool needs to return images, audio files, or a combination of different content types. ```tsx import { TamboTool } from "@tambo-ai/react"; import { z } from "zod"; const getProductImage = async (productId: string) => { const product = await fetchProductData(productId); return { name: product.name, description: product.description, imageUrl: product.imageUrl, price: product.price, }; }; export const tools: TamboTool[] = [ { name: "get_product_image", description: "Fetch product information including image", tool: getProductImage, toolSchema: z .function() .args(z.string().describe("Product ID")) .returns( z.object({ name: z.string(), description: z.string(), imageUrl: z.string(), price: z.number(), }), ), // Transform the result into content parts transformToContent: (result) => [ { type: "text", text: `${result.name} - $${result.price}\n\n${result.description}`, }, { type: "image_url", image_url: { url: result.imageUrl }, }, ], }, ]; ``` ### Supported Content Types The `transformToContent` function can return an array of content parts with the following types: * **Text**: `{ type: "text", text: string }` * **Image**: `{ type: "image_url", image_url: { url: string } }` * **Audio**: `{ type: "input_audio", input_audio: { data: string, format: "wav" | "mp3" } }` You can mix and match these content types to create rich, multimedia responses from your tools. ### When to Use transformToContent Use `transformToContent` when your tool: * Returns image URLs that should be displayed inline * Generates audio that should be played * Needs to return a combination of text and media * Integrates with MCP servers (which already return content in this format) If your tool only returns text or simple data, you don't need `transformToContent` - the default behavior will handle it automatically.