Documentation Index Fetch the complete documentation index at: https://mintlify.com/mastra-ai/mastra/llms.txt
Use this file to discover all available pages before exploring further.
Mastra tools can be called directly, used by agents, or executed in workflows. This guide covers all tool calling patterns.
Agents can automatically call tools based on their descriptions and schemas:
import { Agent } from '@mastra/core/agent' ;
import { createTool } from '@mastra/core/tools' ;
import { z } from 'zod' ;
const weatherTool = createTool ({
id: 'get-weather' ,
description: 'Get current weather for a location' ,
inputSchema: z . object ({
location: z . string (),
}),
execute : async ( input ) => {
return await fetchWeather ( input . location );
},
});
const agent = new Agent ({
id: 'weather-assistant' ,
name: 'Weather Assistant' ,
instructions: 'You help users check the weather' ,
model: 'openai/gpt-4' ,
tools: {
weatherTool ,
},
});
const response = await agent . generate ( 'What is the weather in San Francisco?' );
Tools can be called as workflow steps:
import { Workflow } from '@mastra/core/workflows' ;
import { z } from 'zod' ;
const workflow = new Workflow ({
id: 'weather-report' ,
description: 'Generate a weather report' ,
inputSchema: z . object ({
cities: z . array ( z . string ()),
}),
});
workflow
. step ( weatherTool , {
variables: { location: { step: 'trigger' , path: 'cities.0' } },
})
. then ( weatherTool , {
variables: { location: { step: 'trigger' , path: 'cities.1' } },
})
. commit ();
const run = await workflow . createRun ();
const result = await run . start ({
inputData: { cities: [ 'New York' , 'London' ] },
});
Call tools directly for testing or programmatic use:
const tool = createTool ({
id: 'calculate' ,
description: 'Perform calculations' ,
inputSchema: z . object ({
operation: z . enum ([ 'add' , 'subtract' ]),
a: z . number (),
b: z . number (),
}),
execute : async ( input ) => {
if ( input . operation === 'add' ) {
return { result: input . a + input . b };
}
return { result: input . a - input . b };
},
});
// Direct execution
const result = await tool . execute ?.({
operation: 'add' ,
a: 5 ,
b: 3 ,
});
console . log ( result ); // { result: 8 }
Tool Execution with Context
Pass context for access to Mastra resources:
import { RequestContext } from '@mastra/core/request-context' ;
const authenticatedTool = createTool ({
id: 'get-user-data' ,
description: 'Get user-specific data' ,
execute : async ( input , context ) => {
const userId = context ?. requestContext ?. get ( 'userId' );
const apiClient = context ?. requestContext ?. get ( 'apiClient' );
return await apiClient . getUserData ( userId );
},
});
// Execute with context
const requestContext = new RequestContext ();
requestContext . set ( 'userId' , '123' );
requestContext . set ( 'apiClient' , myApiClient );
const result = await authenticatedTool . execute ?.({}, {
requestContext ,
mastra ,
});
For tools marked with requireApproval: true, implement approval handling:
const agent = new Agent ({
id: 'admin-agent' ,
name: 'Admin Agent' ,
instructions: 'You help with administrative tasks' ,
model: 'openai/gpt-4' ,
tools: {
deleteFileTool , // requireApproval: true
},
});
// Implement approval handler
const response = await agent . generate ( 'Delete the log file' , {
onToolCall : async ({ toolCall , approve , reject }) => {
if ( toolCall . requiresApproval ) {
const userConsent = await promptUser (
`Allow deletion of ${ toolCall . args . filepath } ?`
);
if ( userConsent ) {
await approve ();
} else {
await reject ( 'User denied file deletion' );
}
}
},
});
Stream tool output in real-time:
const streamingTool = createTool ({
id: 'process-data' ,
description: 'Process data with progress updates' ,
execute : async ( input , context ) => {
const writer = context ?. writer ;
for ( let i = 0 ; i < 10 ; i ++ ) {
await processChunk ( i );
// Stream progress updates
await writer ?. write ({
type: 'progress' ,
value: { progress: ( i + 1 ) * 10 , step: i + 1 },
});
}
return { completed: true };
},
});
const agent = new Agent ({
id: 'processor' ,
tools: { streamingTool },
model: 'openai/gpt-4' ,
});
const stream = await agent . stream ( 'Process the data' );
for await ( const chunk of stream ) {
if ( chunk . type === 'tool-output' ) {
console . log ( 'Tool output:' , chunk . value );
}
}
Error Handling
Handle tool execution errors gracefully:
const resilientTool = createTool ({
id: 'api-call' ,
description: 'Call external API' ,
execute : async ( input ) => {
try {
const response = await fetch ( input . url );
if ( ! response . ok ) {
throw new Error ( `API returned ${ response . status } ` );
}
return await response . json ();
} catch ( error ) {
// Return error information instead of throwing
return {
error: true ,
message: error instanceof Error ? error . message : 'Unknown error' ,
};
}
},
});
Validation Errors
Validation errors are automatically returned when input doesn’t match the schema:
const tool = createTool ({
id: 'validate' ,
inputSchema: z . object ({
email: z . string (). email (),
age: z . number (). min ( 0 ). max ( 120 ),
}),
execute : async ( input ) => {
return { valid: true };
},
});
// Invalid input
const result = await tool . execute ?.({
email: 'not-an-email' ,
age: 150 ,
});
// Result will be a ValidationError with details
if ( 'error' in result ) {
console . log ( result . error . errors );
// [
// { path: ['email'], message: 'Invalid email' },
// { path: ['age'], message: 'Number must be less than or equal to 120' }
// ]
}
Agents automatically select appropriate tools based on the conversation:
const agent = new Agent ({
id: 'multi-tool-agent' ,
instructions: 'You can check weather, search the web, and send emails' ,
model: 'openai/gpt-4' ,
tools: {
weatherTool ,
searchTool ,
emailTool ,
},
});
// Agent will automatically choose the right tool
const response = await agent . generate (
'What is the weather in Tokyo and email it to john@example.com'
);
// Agent will call: weatherTool -> emailTool
Next Steps
Creating Tools Learn how to create custom tools
MCP Overview Connect tools via Model Context Protocol