Mastra filled a gap: a genuinely good TypeScript framework for agents. LangChain.js never felt like a first-class citizen; Mastra does. Here's how to bolt Lumbox on in about 30 lines.
Defining email tools
import { createTool } from "@mastra/core";
import { Lumbox } from "lumbox";
import { z } from "zod";
const lumbox = new Lumbox({ apiKey: process.env.LUMBOX_API_KEY! });
export const createInbox = createTool({
id: "create_inbox",
description: "Create a fresh email inbox for a specific task.",
inputSchema: z.object({ purpose: z.string() }),
execute: async ({ context }) => {
const inbox = await lumbox.inboxes.create({
displayName: context.purpose,
});
return { inboxId: inbox.id, address: inbox.address };
},
});
export const waitForOtp = createTool({
id: "wait_for_otp",
description: "Block until a verification OTP arrives.",
inputSchema: z.object({
inboxId: z.string(),
timeout: z.number().default(120),
}),
execute: async ({ context }) => {
const result = await lumbox.inboxes.waitForOtp(context.inboxId, {
timeout: context.timeout,
});
return { otp: result.otp };
},
});
The agent
import { Agent } from "@mastra/core";
export const signupAgent = new Agent({
name: "signup_agent",
instructions: "You sign users up for services. Use create_inbox, then wait_for_otp.",
model: { provider: "anthropic", name: "claude-opus-4-7" },
tools: { createInbox, waitForOtp },
});
Workflow orchestration
Mastra's workflows give you checkpointed, resumable flows. A signup that stalls at the OTP step can be resumed hours later — Lumbox keeps the inbox alive and the OTP retrievable. lumbox.co.