How do I call Ballet playbooks from the Vercel AI SDK?
TL;DR: Use the AI SDK's MCP client to import Ballet's tools, or define a single tool() that calls the execute endpoint. Point the MCP client at https://app.ballet.dev/mcp with an Authorization: Bearer header, await mcpClient.tools(), and pass them to generateText.
Who this is for
TypeScript developers building agents with the Vercel AI SDK.
Option A: Import Ballet's tools over MCP
Configure the AI SDK's MCP client with the HTTP transport and your token. The returned tools (run_playbook, get_run, list_playbooks, …) drop straight into generateText or streamText.
import { openai } from "@ai-sdk/openai";
import { createMCPClient } from "@ai-sdk/mcp";
import { generateText, stepCountIs } from "ai";
const mcpClient = await createMCPClient({
transport: {
type: "http",
url: "https://app.ballet.dev/mcp",
headers: { Authorization: `Bearer ${process.env.BALLET_API_TOKEN}` },
},
});
try {
const tools = await mcpClient.tools();
const { text } = await generateText({
model: openai("gpt-4o"),
tools,
stopWhen: stepCountIs(10),
prompt: "Run the lead-enrichment playbook for cus_123 and summarize the result.",
});
console.log(text);
} finally {
await mcpClient.close();
}
For interactive apps you can supply an authProvider instead of a static header to use Ballet's browser-based OAuth — see the MCP endpoint.
Option B: Define one playbook as a tool
When you only need to expose a single playbook, define a tool() that calls the REST execute endpoint and returns the run output.
import { tool } from "ai";
import { z } from "zod";
export const runPlaybook = tool({
description: "Run the customer onboarding playbook in Ballet.",
inputSchema: z.object({ customerId: z.string() }),
execute: async ({ customerId }) => {
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 } }),
},
);
let result;
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") result = event.run;
}
return { success: result?.success, output: result?.output };
},
});
See Run playbooks over the REST API for the streaming details.
Which option should I use?
- MCP — let the model discover and call any playbook in your workspace.
- REST tool — expose exactly one playbook with a precise input schema.
