🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 9 Min Lesezeit
0

Building a production AI agent in TypeScript with Mastra: a 2026 step-by-step.

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Building a production AI agent in TypeScript with Mastra: a 2026 step-by-step.



I spent an afternoon last month wiring up an AI agent in raw TypeScript using the Anthropic SDK directly. The code worked, but I owned every piece of it: the tool dispatch loop, the conversation history array, the retry logic. Around 400 lines before the agent did anything interesting.



Mastra cuts that to about 60. A TypeScript-first agent framework with 24k+ GitHub stars, an active release cadence (88 releases as of May 2026), and a model router that talks to 40+ providers through one API. This tutorial goes from zero to a running agent with a custom tool and persistent memory. All code in this article runs.






TL;DR






































Step What you build Time
Install Scaffolded project with Mastra wired in 5 min
Agent An agent with a system prompt and a model 10 min
Tool A custom tool the agent calls 15 min
Memory Conversation history across sessions 10 min
Deploy A running HTTP server 5 min





1. Where Mastra sits in the stack



Raw SDK calls give you full control but you write the orchestration layer yourself: the tool call loop, history management, error handling, retries. Frameworks like LangChain and LlamaIndex solve this but lean heavily Python-first; the TypeScript ports lag the Python versions.



Mastra starts from TypeScript. The primitives map directly to what TypeScript developers already know: classes, Zod schemas, async functions. No port-lag exists because the framework itself is the TypeScript version.



The trade-off is the same as any framework: you trade control for speed. For prototypes and most production agents, the trade is worth it. For cases where the framework's tool dispatch or memory behavior does not match your exact needs, you can always drop a layer and call the Vercel AI SDK directly, which Mastra wraps under the hood.






2. Project setup



Mastra's scaffolder creates everything you need:




CODE
npm create mastra@latest






The wizard asks for a project name, model provider, and whether you want the starter example files. Pick your provider (OpenAI, Anthropic, Google, or any of the 40+ supported). For this tutorial I'll use Anthropic.



After the wizard finishes:




CODE
cd my-agent
npm install






Open .env and add your key:




CODE
ANTHROPIC_API_KEY=sk-ant-...






The generated project structure looks like this:




CODE
src/
mastra/
index.ts # Mastra instance
agents/
weather-agent.ts
tools/
weather-tool.ts






You can rename or replace the starter files. The root entry point src/mastra/index.ts registers your agents and tools with the Mastra runtime:




CODE
// src/mastra/index.ts
import { Mastra } from "@mastra/core";
import { supportAgent } from "./agents/support-agent";

export const mastra = new Mastra({
agents: { supportAgent },
});






That is the full configuration. No YAML, no config files, no factory functions to memorize.






3. Defining your first agent



An agent in Mastra is an instance of the Agent class. You give it an id, a name, a model, and instructions. The instructions are the system prompt.




CODE
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";

export const supportAgent = new Agent({
id: "support-agent",
name: "Support Agent",
model: "anthropic/claude-sonnet-4-6-20250929",
instructions: `You are a support agent for a SaaS product.
Answer questions clearly. If you do not know the answer, say so.
When the user describes a bug, ask for their account ID and browser version before troubleshooting.
Keep responses under 150 words unless the user asks for detail.`
,
});






The model field uses Mastra's router format: provider/model-id. This means swapping from Anthropic to OpenAI is a one-line change. Pin the model ID to a dated version, not an alias, so you own when it upgrades.



To call the agent from your application code:




CODE
import { mastra } from "./mastra";

const agent = mastra.getAgentById("support-agent");

const response = await agent.generate("My dashboard stopped loading after your last update.");
console.log(response.text);






generate returns a full response after the model finishes. If you want streaming for a chat UI, swap to stream:




CODE
const stream = await agent.stream("What does the onboarding flow look like?");
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}






Both methods return { text, toolCalls, toolResults, usage }. The usage object gives you token counts per call, which you should log in production.






4. Adding a custom tool



Tools are how agents take action beyond text generation. A tool has an id, a description the model uses to decide when to call it, an inputSchema validated by Zod, and an execute function.



Here is a tool that looks up an account by ID from a hypothetical database:




CODE
// src/mastra/tools/account-lookup.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";

export const accountLookupTool = createTool({
id: "account-lookup",
description: "Look up a customer account by their account ID. Returns plan, status, and creation date.",
inputSchema: z.object({
accountId: z.string().describe("The customer account ID, format ACC-XXXXXXXX"),
}),
execute: async ({ context }) => {
const { accountId } = context;
// Replace with your real DB call
const account = await fetchAccountFromDb(accountId);
if (!account) {
return { found: false, accountId };
}
return {
found: true,
accountId,
plan: account.plan,
status: account.status,
createdAt: account.createdAt,
};
},
});

async function fetchAccountFromDb(accountId: string) {
// Stub — wire to your actual data layer
if (accountId === "ACC-00000001") {
return { plan: "pro", status: "active", createdAt: "2025-03-15" };
}
return null;
}






Attach the tool to the agent by adding it to the tools array:




CODE
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";
import { accountLookupTool } from "../tools/account-lookup";

export const supportAgent = new Agent({
id: "support-agent",
name: "Support Agent",
model: "anthropic/claude-sonnet-4-6-20250929",
instructions: `You are a support agent for a SaaS product.
When a user provides an account ID, use the account-lookup tool to retrieve their account details before answering.
Answer questions clearly. If you do not know the answer, say so.`
,
tools: {
"account-lookup": accountLookupTool,
},
});






The model now sees the tool in its context. When a user says "My account ACC-00000001 is showing the wrong plan", the agent calls account-lookup, gets the account record back, and includes it in its reasoning before responding. You see the tool call in response.toolCalls and the result in response.toolResults.



The Zod schema does two things: it tells the model what the tool expects (the description and field names show up in the model's tool spec), and it validates the model's output before your execute function runs. If the model sends a malformed accountId, Mastra rejects the call before it hits your code.






5. Adding memory



Without memory, every call to agent.generate starts from a blank slate. The agent does not know what the user said two messages ago. For a support agent this breaks multi-turn conversations immediately.



Mastra's @mastra/memory package adds three layers: message history (the last N turns), working memory (key facts extracted and stored between turns), and semantic recall (vector search over past conversations). For most agents, message history is enough to start.



Install the package and a storage backend:




CODE
npm install @mastra/memory @mastra/libsql






Wire memory into the agent:




CODE
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/libsql";
import { accountLookupTool } from "../tools/account-lookup";

const memory = new Memory({
storage: new LibSQLStore({
url: process.env.DATABASE_URL ?? "file:./agent.db",
}),
options: {
lastMessages: 20,
},
});

export const supportAgent = new Agent({
id: "support-agent",
name: "Support Agent",
model: "anthropic/claude-sonnet-4-6-20250929",
instructions: `You are a support agent for a SaaS product.
When a user provides an account ID, use the account-lookup tool before answering.
Keep responses under 150 words unless the user asks for detail.`
,
tools: {
"account-lookup": accountLookupTool,
},
memory,
});






Pass a resource and thread when you call the agent. resource identifies the user; thread isolates a specific conversation:




CODE
const response = await agent.generate(
"What plan am I on?",
{
memory: {
resource: "user-42",
thread: "support-session-2026-05-25",
},
},
);






On the first turn the agent has no history. On the second turn it gets the last 20 messages from that resource and thread. The user can say "follow up from earlier" and the agent knows what earlier means.



LibSQL writes to a local SQLite file in development. For production, point DATABASE_URL at a Turso connection string and the same code writes to a distributed SQLite database with no other changes.






6. Running locally and deploying



Development server:




CODE
npx mastra dev






This starts a local server with a REST API over your agents and a browser-based studio on port 4111 where you can send messages to the agent, inspect tool calls, and read the memory state. The studio is useful enough that I use it even for non-UI agents.



For production you have two options.



The first is the Mastra cloud deploy, which packages your agents as a managed service:




CODE
npx mastra deploy






The second is self-hosting. Add @mastra/express and mount the Mastra server into your existing Express app:




CODE
npm install @mastra/express









CODE
// src/index.ts
import express from "express";
import { MastraServer } from "@mastra/express";
import { mastra } from "./mastra";

const app = express();
app.use(express.json());

const server = new MastraServer({ app, mastra });
await server.init();

app.listen(process.env.PORT ?? 3000);






MastraServer.init() registers the agent endpoints under /api. Your agents become callable over HTTP with no extra routing code. Deploy this to Railway, Fly.io, or any Node.js host that accepts a Dockerfile.






The bottom line



Mastra removes the orchestration scaffolding that accounts for the first 300 lines of every TypeScript agent project. The three hours I spent on tool dispatch and conversation history management with raw SDK calls collapse to about 15 minutes with Mastra.



The framework makes a bet on TypeScript as the language where agents actually ship to production, not just where they get prototyped. That bet reflects what I see in production codebases. Python still dominates training and research. TypeScript dominates the web services those agents plug into.



The main thing I'd add to the stack described above: log response.usage on every generate call so you can see what the agent actually costs per session in production. The number surprises most teams the first week.



What does your agent stack look like right now? Raw SDK, a framework, something in-house? Curious what the pressure points are.






GDS K S ·



The orchestration layer is the part nobody talks about until they've rewritten it twice.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building a production AI agent in TypeScript with Mastra: a 2026 step-by-step.

Thematisch verwandte Begriffe: Building, production, agent, TypeScript · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...