How do I call Ballet playbooks from Mastra?
2min read
TL;DR: Use Mastra's MCPClient to connect to Ballet's MCP endpoint, or define a createTool that calls the execute endpoint. Configure a server entry with url: new URL("https://app.ballet.dev/mcp") and an Authorization header, then pass await mcp.getTools() to an Agent.
Who this is for
TypeScript developers building agents with Mastra.
Option A: Connect over MCP
Install @mastra/mcp, register Ballet as a server (Mastra tries Streamable HTTP first), and hand the tools to an Agent.
import { MCPClient } from "@mastra/mcp";
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
const mcp = new MCPClient({
servers: {
ballet: {
url: new URL("https://app.ballet.dev/mcp"),
requestInit: {
headers: { Authorization: `Bearer ${process.env.BALLET_API_TOKEN}` },
},
},
},
});
const agent = new Agent({
name: "ops-agent",
instructions: "You run Ballet playbooks to complete operational tasks.",
model: openai("gpt-4o"),
tools: await mcp.getTools(),
});
const result = await agent.generate(
"Run the lead-enrichment playbook for cus_123 and summarize the result.",
);
console.log(result.text);
For per-request auth (for example a rotating token), use the fetch option on the server entry instead of requestInit.
Option B: Define one playbook as a tool
To expose a single playbook, wrap the REST execute endpoint with createTool.
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
export const runOnboarding = createTool({
id: "run-onboarding",
description: "Run the customer onboarding playbook in Ballet.",
inputSchema: z.object({ customerId: z.string() }),
execute: async ({ context }) => {
const res = await fetch(
`https://app.ballet.dev/api/playbooks/${process.env.BALLET_PLAYBOOK_ID}/execute`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BALLET_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ input: { customerId: context.customerId } }),
},
);
let run;
for (const frame of (await res.text()).split("\n\n")) {
const line = frame.split("\n").find((l) => l.startsWith("data:"));
if (!line) continue;
const event = JSON.parse(line.slice(5).trim());
if (event.type === "run_stop") run = event.run;
}
return { success: run?.success, output: run?.output };
},
});
See Run playbooks over the REST API for streaming details.
Which option should I use?
- MCP — expose every playbook to the agent and let Mastra manage the connection.
- REST tool — expose one playbook with a precise schema.
