Agents
Author, rename, and extend the assistant - a Mastra agent registered in code, with AI SDK tools, MCP clients, inline skills, and an editable persona.
The assistant is a Mastra agent (packages/api/src/mastra/agents/assistant/config.ts). Chat and automated runs both call it, so anything you change here changes both.
Author with Mastra's conventions, not a wrapper of ours - this boilerplate adds no abstraction over the agent, its tools, memory, or MCP clients. Mastra's docs are the source of truth for shapes and options; this page covers only the boilerplate-specific seams.
Register the agent in code
The agent is constructed and registered in one place - getMastra() (packages/api/src/mastra/index.ts) - via Mastra's agents map. Add or rename one by editing that map and its folder under packages/api/src/mastra/agents/<name>/.
new Mastra({
storage,
agents: { assistant: createAssistantAgent(assistantMemory) }
});Register in code - do not rely on file-based discovery. Mastra's agents/ folder auto-discovery runs only under the Mastra CLI, and this backend imports its Mastra instance directly as a library, so the agents map is the registration. The folder shape mirrors Mastra's convention so it stays recognizable if you later adopt the CLI.
Re-voice the persona
The persona is the agent's inline instructions string (assistantInstructions), not a sibling instructions.md: the production build rewrites module paths and does not copy adjacent markdown, so a readFileSync loader throws at runtime. The capability nudge and the other injected strings are a separate seam - see AI prompts.
Give it tools
The agent's tools are AI SDK tool() objects, re-exported by @repo/ai:
import { tool } from "@repo/ai";
import { z } from "zod";
const getForecast = tool({
description: "Look up the weather forecast for a city.",
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => fetchForecast(city)
});Attach it to the agent (new Agent({ ..., tools: { getForecast } })) or hand it in per run as a named toolset - the pattern chat and automations use for the capability set. You rarely start from scratch: the capabilities that operate the app and the integrations users connect are already tools per run. See Mastra's tools docs for dynamic tools, approval, and toolsets.
Give it MCP clients
To call external MCP servers (a user's connected service, an internal tool server), use Mastra's MCPClient from @mastra/mcp and pass its toolset into a run. This is the inbound direction; the outward server (your app as an MCP server to someone else's agent) is a separate, config-gated option.
import { MCPClient } from "@mastra/mcp";
const mcp = new MCPClient({
servers: { docs: { url: new URL("https://example.com/mcp") } }
});
const toolsets = await mcp.listToolsets();
// pass `toolsets` into agent.stream(..., { toolsets }) / agent.generate(..., { toolsets })@mastra/mcp already ships in the API package; if a lean build dropped it, run pnpm --filter @repo/api add @mastra/mcp first. Follow Mastra's MCP docs for auth, lifecycle, and server config.
Give it skills
Skills are written as folders under packages/ai/skills, not in this file: each holds a SKILL.md, and a build step inlines them into a committed module the agent receives at construction. See AI skills for the format and the build.
The agent loads a skill on demand. A project with at least one skill also gains three tools automatically - skill, skill_search and skill_read - and its system message lists what exists. A project with no skills gains none of that, and behaves exactly as it did before.
Never reference a skill by path. skills: ["./skills/refund-policy"] reads its SKILL.md at runtime, and the production build does not trace a file named only by a path string - the file never reaches the bundle and skill_read fails there. The build step exists so the instructions travel as code instead.
Reaching the agent from the Mastra CLI
Mastra's CLI can talk to a running Mastra server (mastra api --url <origin>), but this backend's server.auth is a cookie-session guard - the same Better Auth session the app uses. The CLI's bearer-token access is not wired, so add your own token mechanism to the server auth if you want it.
AI
The AI product the agent powers: chat, automated runs, capabilities, billing.
AI prompts
The injected prompt seams, and how they layer with the agent's persona.
AI integrations
Third-party services that become agent tools when a user connects them.
Mastra docs
Agents, tools, memory, workflows, MCP, and skills - the framework's own reference.
AI
The config.ai product - a streaming chat assistant, cron-automated runs, and an act-on-your-app capability layer on the shared Hono backend, billed from credits or run on your users' own API keys.
AI skills
One folder where you write your product's skills - instructions your AI loads on demand - reaching the assistant, external MCP clients, and Mastra Studio with no wiring.