Tools
Tool execution signatures have been updated to use separate input and context parameters with reorganized context properties.
Changed
createTool execute signature to (inputData, context) format
All createTool execute functions now use a new signature with separate inputData and context parameters instead of a single destructured object. This change provides clearer separation between tool inputs and execution context.
Note: This change only applies to createTool. If you're using createStep for workflows, the signature remains async (inputData, context) and does not need to be changed.
To migrate, update createTool signatures to use inputData as the first parameter (typed from inputSchema) and context as the second parameter.
createTool({
id: 'weather-tool',
- execute: async ({ context, requestContext, mastra }) => {
- const location = context.location;
- const userTier = requestContext.get('userTier');
- return getWeather(location, userTier);
- },
+ execute: async (inputData, context) => {
+ const location = inputData.location;
+ const userTier = context?.requestContext?.get('userTier');
+ return getWeather(location, userTier);
+ },
});
createTool context properties organization
Context properties in createTool are now organized into namespaces. Agent-specific properties are under context.agent, workflow-specific properties are under context.workflow, and MCP-specific properties are under context.mcp. This change provides better organization and clearer API surface.
For tools that are executed inside an agent, access agent-specific properties through context.agent.
createTool({
id: 'suspendable-tool',
suspendSchema: z.object({ message: z.string() }),
resumeSchema: z.object({ approval: z.boolean() }),
- execute: async ({ context, suspend, resumeData }) => {
- if (!resumeData) {
- return await suspend({ message: 'Waiting for approval' });
- }
- if (resumeData.approval) {
- return { success: true };
- }
- },
+ execute: async (inputData, context) => {
+ if (!context?.agent?.resumeData) {
+ return await context?.agent?.suspend({
+ message: 'Waiting for approval',
+ });
+ }
+ if (context.agent.resumeData.approval) {
+ return { success: true };
+ }
+ },
});
For tools that are executed inside a workflow, access workflow-specific properties through context.workflow.
createTool({
id: 'workflow-tool',
- execute: async ({ workflowId, runId, state, setState }) => {
- const currentState = state;
- setState({ step: 'completed' });
- return { result: 'done' };
- },
+ execute: async (inputData, context) => {
+ const currentState = context?.workflow?.state;
+ context?.workflow?.setState({ step: 'completed' });
+ return { result: 'done' };
+ },
});
For MCP-specific tool context changes, see the MCP migration guide.
RuntimeContext to RequestContext
The RuntimeContext class has been renamed to RequestContext throughout the tool execution context. This change provides clearer naming that better describes its purpose as request-specific data.
To migrate, update references from runtimeContext to requestContext in tool execution functions.
createTool({
id: 'my-tool',
execute: async (inputData, context) => {
- const userTier = context?.runtimeContext?.get('userTier');
+ const userTier = context?.requestContext?.get('userTier');
return { result: userTier };
},
});
You can use Mastra's codemod CLI to update your imports automatically:
npx @mastra/codemod@beta v1/runtime-context .
This applies to all tool executions, whether called directly or through agents and workflows. The type narrowing ensures you handle validation errors appropriately and prevents runtime errors when accessing output properties.
Tool output validation with outputSchema
Tools with an outputSchema now validate their return values at runtime. Previously, outputSchema was only used for type inference - the output was never validated.
If your tool returns data that doesn't match its outputSchema, it will now return a ValidationError instead of the invalid data.
To fix validation errors, ensure the tool's output matches the schema definition:
const getUserTool = createTool({
id: "get-user",
outputSchema: z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
}),
execute: async (inputData) => {
- return { id: "123", name: "John" }; // Missing email
+ return { id: "123", name: "John", email: "john@example.com" };
},
});
When validation fails, the tool returns a ValidationError:
+ // Before v1 - invalid output would silently pass through
await getUserTool.execute({});
- // { id: "123", name: "John" } - missing email
+ // {
+ // error: true,
+ // message: "Tool output validation failed for get-user. The tool returned invalid output:\n- email: Required\n\nReturned output: {...}",
+ // validationErrors: { ... }
+ // }
tool.execute return type includes ValidationError
The return type of tool.execute now includes ValidationError to handle validation failures. You must narrow the result type before accessing output schema properties to satisfy TypeScript's type checking.
When calling tool.execute, check if the result contains an error before accessing output properties:
const result = await getUserTool.execute({});
// Type-safe check for validation errors
if ('error' in result && result.error) {
console.error('Validation failed:', result.message);
console.error('Details:', result.validationErrors);
return;
}
// TypeScript knows result is valid here
console.log(result.id, result.name, result.email);
Alternatively, update the outputSchema to match your actual output, or remove outputSchema entirely if you don't need validation.