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.