Building agents
Build one
The shortest path to a working Mastra agent: define a tool → define an agent → register it on the runtime → call it.
[!NOTE] APIs evolve across
@mastra/coreversions. The exact import paths and the version this targets are recorded in the research dossier at_INBOX/2-Research/Mastra/; treat the snippets below as the shape of the API and confirm against the version you install.
1. Define a tool
Section titled “1. Define a tool”A tool is a typed function the agent can call. Input/output are validated with Zod.
import { createTool } from '@mastra/core/tools';import { z } from 'zod';
export const weatherTool = createTool({ id: 'weather-tool', description: 'Fetches current weather for a location', inputSchema: z.object({ location: z.string().describe('City, e.g. "San Francisco"') }), outputSchema: z.object({ weather: z.string() }), execute: async (inputData) => { const { location } = inputData; const response = await fetch(`https://wttr.in/${location}?format=3`); return { weather: await response.text() }; },});2. Define an agent
Section titled “2. Define an agent”Bind instructions, a model, the tool, and (optionally) memory. The model is a model-router string ("provider/model"); you can also pass an AI SDK provider module directly (e.g. groq('gemma2-9b-it')).
import { Agent } from '@mastra/core/agent';import { Memory } from '@mastra/memory';import { LibSQLStore } from '@mastra/libsql';import { weatherTool } from './tools/weather-tool';
export const weatherAgent = new Agent({ id: 'weather-agent', name: 'Weather Agent', instructions: 'You are a concise weather assistant. Use weather-tool before answering, and remember the user\u2019s preferences.', model: 'openai/gpt-5.5', // model-router string; or an AI SDK module, e.g. groq('gemma2-9b-it') tools: { weatherTool }, memory: new Memory({ storage: new LibSQLStore({ id: 'agent-memory', url: 'file:./mastra.db' }), }),});3. Register it on the runtime
Section titled “3. Register it on the runtime”The single Mastra instance owns every agent and workflow. Give it storage and a logger — memory and tracing need a storage provider.
import { Mastra } from '@mastra/core';import { LibSQLStore } from '@mastra/libsql';import { PinoLogger } from '@mastra/loggers';import { weatherAgent } from './agents/weather-agent';
export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:./mastra.db' }), logger: new PinoLogger({ name: 'Mastra', level: 'info' }),});4. Call it from your app
Section titled “4. Call it from your app”Routes ask the runtime for the agent by id — they never import it directly. Pass memory (a resource + thread) so the agent keeps continuity per user/conversation.
import { mastra } from './mastra';
const agent = mastra.getAgentById('weather-agent');
// One-shot — returns text plus a traceId you can look up in observability.const res = await agent.generate('What should I wear in Paris today?', { memory: { resource: 'user-123', thread: 'weather-chat' },});console.log(res.text, res.traceId);
// Streamingconst stream = await agent.stream('And tomorrow?');for await (const chunk of stream.textStream) process.stdout.write(chunk);[!TIP] Streaming to an AI SDK UI frontend? Use
handleChatStreamfrom@mastra/ai-sdk— it bridges a registered agent to AI SDK UI / AI Elements message streams.
Reference: Agents · Using tools · Memory · Models
Next: Workflows — when one agent call isn’t enough.