---
title: Mastra
description: Use @codespar/mastra to give Mastra agents commerce capabilities in Latin America.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";

# Mastra Adapter

<VersionBadge pkg="@codespar/mastra" />

The `@codespar/mastra` adapter converts CodeSpar session tools into Mastra's tool format. Tools are returned as a keyed record (by tool name) ready to pass directly to a Mastra Agent. Each tool's `execute` method routes through the CodeSpar session for billing and audit.

<Callout type="info">
**Pick this adapter when** you want workflow-first TypeScript agents with deterministic graphs, strong typing end-to-end, and first-class support for retries and branching — good fit for back-office commerce flows where you want fewer LLM judgment calls and more wired logic.
</Callout>

## Framework-specific notes

- **Keyed record, not an array** — `getTools(session)` returns `{ codespar_pay: Tool, codespar_invoice: Tool, ... }`, ready to pass into an Agent's `tools` property directly.
- **Wire into a Workflow for determinism** — when the tool sequence is fixed (charge → invoice → ship), a Mastra Workflow with three `.step()` calls is cheaper and more observable than an LLM-driven loop. Use `session.execute` directly inside steps; skip the agent.
- **Retries are declarative** — Mastra lets you attach retry + backoff to individual steps. CodeSpar's own router does not retry on runtime error, so framework-level retries here matter for transient provider failures.
- **TypeScript types end-to-end** — tool inputs and outputs flow typed through the workflow, which is useful when you branch on `result.data` fields from a Pix charge to decide the next step.

## Installation

<Tabs items={["npm", "pnpm", "yarn"]}>
<Tab value="npm">
```bash
npm install @codespar/sdk @codespar/mastra
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add @codespar/sdk @codespar/mastra
```
</Tab>
<Tab value="yarn">
```bash
yarn add @codespar/sdk @codespar/mastra
```
</Tab>
</Tabs>

<Callout type="info">
`@codespar/mastra` has a peer dependency on `@codespar/sdk@^0.10.0`. You also need `@mastra/core` for the Mastra runtime.
</Callout>
## API Reference

### `getTools(session): Promise<Record<string, MastraTool>>`

Fetches all tools from the session and returns them as a keyed record. Each tool has `id`, `description`, `inputSchema` (JSON Schema), and an `execute` method.

```typescript
import { CodeSpar } from "@codespar/sdk";
import { getTools } from "@codespar/mastra";

const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
const session = await codespar.create("user_123", {
  servers: ["stripe", "mercadopago"],
});

const tools = await getTools(session);
console.log(Object.keys(tools)); // ["codespar_charge", "codespar_pay", ...]
```

### `toMastraTool(tool, session): MastraTool`

Converts a single CodeSpar tool to Mastra format with a bound `execute` method.

```typescript
import { toMastraTool } from "@codespar/mastra";

const allTools = await session.tools();
const paymentTool = toMastraTool(
  allTools.find((t) => t.name === "codespar_pay")!,
  session
);
```

### `handleToolCall(session, toolName, args): Promise<ToolResult>`

Convenience executor that routes a tool call through the CodeSpar session.

## Full agent loop

This is a complete example of a Mastra Agent with CodeSpar tools:

```typescript title="mastra-agent.ts"
import { Agent } from "@mastra/core";
import { CodeSpar } from "@codespar/sdk";
import { getTools } from "@codespar/mastra";

const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

async function run(userMessage: string) {
  // 1. Create a session
  const session = await codespar.create("user_123", {
    servers: ["stripe", "asaas", "correios"],
  });

  // 2. Get tools in Mastra format (keyed record)
  const tools = await getTools(session);

  // 3. Create and run the agent
  const agent = new Agent({
    name: "commerce-assistant",
    instructions:
      "You are a commerce assistant for a Brazilian e-commerce store. " +
      "Handle payments, invoicing, and shipping. " +
      "Respond in the same language the user writes in.",
    model: { provider: "OPEN_AI", name: "gpt-4o" },
    tools,
  });

  const result = await agent.generate(userMessage);

  // 4. Clean up
  await session.close();

  return result.text;
}

const reply = await run("Generate a boleto for R$250 due in 7 days");
console.log(reply);
```

## Handling parallel tool calls

Mastra handles parallel tool execution automatically through its agent runtime. If you need manual control:

```typescript
const toolEntries = Object.entries(tools);
const results = await Promise.all(
  toolEntries
    .filter(([name]) => name.startsWith("codespar_pay"))
    .map(([, tool]) => tool.execute({ context: { amount: 5000 } }))
);
```

## Streaming

Mastra supports streaming via the agent's `stream` method:

```typescript title="mastra-streaming.ts"
import { Agent } from "@mastra/core";
import { CodeSpar } from "@codespar/sdk";
import { getTools } from "@codespar/mastra";

const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

async function runStreaming(userMessage: string) {
  const session = await codespar.create("user_123", {
    servers: ["stripe", "mercadopago"],
  });

  const tools = await getTools(session);

  const agent = new Agent({
    name: "commerce-assistant",
    instructions: "You are a commerce assistant for a Brazilian store.",
    model: { provider: "OPEN_AI", name: "gpt-4o" },
    tools,
  });

  const stream = await agent.stream(userMessage);

  for await (const chunk of stream.textStream) {
    process.stdout.write(chunk);
  }

  await session.close();
}

await runStreaming("Create a Pix payment for R$150");
```

## Error handling

Tool execution errors are handled by the Mastra runtime. For manual error handling:

```typescript
const tool = tools["codespar_charge"];
try {
  const result = await tool.execute({
    context: { provider: "stripe", amount: 4990, currency: "BRL" },
  });
  console.log("Success:", result);
} catch (error) {
  console.error("Failed:", error instanceof Error ? error.message : error);
}
```

<Callout type="info">
The Mastra agent runtime automatically catches tool execution errors and feeds them back to the LLM for reasoning.
</Callout>
## Best practices

1. **Always close sessions.** Use `try/finally` to ensure `session.close()` runs.

2. **Scope servers narrowly.** Only connect the MCP servers your agent needs.

3. **Use clear instructions.** Mastra agents work best with specific, domain-focused instructions.

4. **Leverage the keyed record.** Access tools by name (`tools["codespar_pay"]`) for direct invocation.

5. **Combine with Mastra workflows.** Use tools inside Mastra Workflows for complex multi-step operations.

6. **Filter tools when possible.** Use `session.findTools()` to get only relevant tools before converting.

## Newer SDK wrappers

`getTools(session)` is the LLM-driven path. For deterministic Workflow steps you can call typed wrappers on the session directly — same routing, no LLM hop:

- `session.discover(query)` / `session.charge(args)` / `session.pay(args)` / `session.ship(args)` — typed shortcuts for the meta-tools.
- `session.connectionWizard(serverId)` — open a hosted auth flow for a missing connection.
- `session.paymentStatus(toolCallId)` and `session.paymentStatusStream(toolCallId)` — async settlement correlation (poll or SSE).
- `session.verificationStatus(toolCallId)` and `session.verificationStatusStream(toolCallId)` — KYC outcome polling / SSE.

Full reference at [/docs/api/sdk](/docs/api/sdk).

## Next steps

<NextStepsGrid items={[
  { label: "CONCEPT", title: "Sessions", description: "Session lifecycle and configuration.", href: "/docs/concepts/sessions" },
  { label: "CONCEPT", title: "Tools & Meta-Tools", description: "Meta-tools and how routing works.", href: "/docs/concepts/tools" },
  { label: "PROVIDER", title: "Vercel AI SDK", description: "Similar keyed-record tool pattern.", href: "/docs/providers/vercel" },
  { label: "PROVIDER", title: "LangChain Adapter", description: "Compose with LangChain.js chains and retrievers.", href: "/docs/providers/langchain" },
  { label: "QUICKSTART", title: "Quickstart", description: "End-to-end setup in under 5 minutes.", href: "/docs/quickstart" },
]} />
