Skip to main content
Tools in Mastra are type-safe functions that agents and workflows can call to perform specific actions. Use the createTool helper to define tools with automatic input/output validation.

Basic Tool Creation

Create a tool using the createTool helper with an ID, description, and execute function:
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

const greetTool = createTool({
  id: 'greet',
  description: 'Say hello to someone',
  inputSchema: z.object({
    name: z.string().describe('The name of the person to greet'),
  }),
  execute: async (input) => {
    return { message: `Hello, ${input.name}!` };
  },
});

Tool with Input and Output Schemas

Define input and output schemas for type safety and validation:
const weatherTool = createTool({
  id: 'get-weather',
  description: 'Get current weather for a location',
  inputSchema: z.object({
    location: z.string().describe('City name'),
  }),
  outputSchema: z.object({
    temperature: z.number(),
    feelsLike: z.number(),
    humidity: z.number(),
    windSpeed: z.number(),
    conditions: z.string(),
    location: z.string(),
  }),
  execute: async (input) => {
    const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(input.location)}&count=1`;
    const geocodingResponse = await fetch(geocodingUrl);
    const geocodingData = await geocodingResponse.json();

    if (!geocodingData.results?.[0]) {
      throw new Error(`Location '${input.location}' not found`);
    }

    const { latitude, longitude, name } = geocodingData.results[0];
    const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`;

    const response = await fetch(weatherUrl);
    const data = await response.json();

    return {
      temperature: data.current.temperature_2m,
      feelsLike: data.current.apparent_temperature,
      humidity: data.current.relative_humidity_2m,
      windSpeed: data.current.wind_speed_10m,
      windGust: data.current.wind_gusts_10m,
      conditions: getWeatherCondition(data.current.weather_code),
      location: name,
    };
  },
});

Tool with Context Access

Access Mastra instance and other context in the execute function:
const saveTool = createTool({
  id: 'save-data',
  description: 'Save data to storage',
  inputSchema: z.object({
    key: z.string(),
    value: z.any(),
  }),
  execute: async (input, context) => {
    // Access Mastra instance for storage, agents, etc.
    const storage = context?.mastra?.getStorage();
    await storage?.set(input.key, input.value);
    
    // Access request context for authenticated clients
    const userId = context?.requestContext?.get('userId');
    
    return { saved: true, userId };
  },
});

Tool Requiring Approval

Create tools that require explicit user approval before execution:
const deleteFileTool = createTool({
  id: 'delete-file',
  description: 'Delete a file from the filesystem',
  requireApproval: true,
  inputSchema: z.object({
    filepath: z.string().describe('Path to the file to delete'),
  }),
  execute: async (input) => {
    await fs.unlink(input.filepath);
    return { deleted: true, filepath: input.filepath };
  },
});

Tool Execution Context

The execution context provides access to:
  • mastra - Mastra instance for accessing storage, agents, workflows
  • requestContext - Request-scoped values (auth, feature flags, etc.)
  • agent - Agent-specific context (toolCallId, messages, suspend/resume)
  • workflow - Workflow-specific context (runId, state, suspend/resume)
  • workspace - Workspace for file operations and command execution
  • writer - Stream writer for real-time output
const contextAwareTool = createTool({
  id: 'context-aware',
  description: 'Tool that uses execution context',
  execute: async (input, context) => {
    // Check execution source
    if (context?.agent) {
      console.log('Called by agent:', context.agent.toolCallId);
    }
    
    if (context?.workflow) {
      console.log('Called by workflow:', context.workflow.runId);
    }
    
    // Access workspace for file operations
    if (context?.workspace) {
      const files = await context.workspace.filesystem.list('.');
      return { files };
    }
    
    return { message: 'Context accessed' };
  },
});

Provider Options

Specify provider-specific options for model behavior:
const cachedTool = createTool({
  id: 'cached-tool',
  description: 'Tool with provider-specific caching',
  providerOptions: {
    anthropic: {
      cacheControl: { type: 'ephemeral' },
    },
  },
  execute: async (input) => {
    return { cached: true };
  },
});

Transforming Output for Models

Transform tool output before sending to the model:
const dataTool = createTool({
  id: 'get-data',
  description: 'Get data with custom model output',
  outputSchema: z.object({
    rawData: z.array(z.any()),
    metadata: z.object({}),
  }),
  toModelOutput: (output) => {
    // Return simplified version to model
    return {
      summary: `Found ${output.rawData.length} items`,
      data: output.rawData.slice(0, 5), // Only first 5 items
    };
  },
  execute: async () => {
    return {
      rawData: [/* ... */],
      metadata: { /* ... */ },
    };
  },
});

Next Steps

Tool Calling

Learn how to call tools from agents and workflows

MCP Overview

Connect tools via Model Context Protocol

Build docs developers (and LLMs) love