This tutorial builds a working Mastra agent and Workflow that publishes social posts. The interesting part: Mastra's typed Workflows let you fan out to platforms in parallel with full input/output typing end-to-end — drafting and scheduling LinkedIn, Bluesky, and Threads concurrently in one Workflow run.
What you'll build
A Mastra setup with two pieces: (1) a publisher Agent that holds the Posta MCP server's tools and can be invoked for one-off prompts, and (2) a launch Workflow that fans out to three platforms in parallel and reports back with the scheduled post IDs.
Prerequisites
- Node 20+ and a Mastra project (or any TypeScript app).
- A Posta account with LinkedIn, Bluesky, and Threads connected. 14-day free trial.
- A Posta API token.
- An Anthropic API key.
Step 1 — Install dependencies
npm i @mastra/core @mastra/mcp @ai-sdk/anthropic zodStep 2 — Load Posta MCP into an Agent
Mastra's MCPClient takes a dict of MCP server configs and exposes getTools() for the agent:
// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { Agent } from '@mastra/core/agent'
import { MCPClient } from '@mastra/mcp'
import { anthropic } from '@ai-sdk/anthropic'
const mcp = new MCPClient({
servers: {
posta: {
command: 'npx',
args: ['-y', 'posta-mcp'],
env: { POSTA_API_TOKEN: process.env.POSTA_API_TOKEN! },
},
},
})
export const publisher = new Agent({
name: 'social-publisher',
instructions: "Draft and schedule social posts. Match each platform's voice.",
model: anthropic('claude-sonnet-4-6'),
tools: await mcp.getTools(),
})
export const mastra = new Mastra({ agents: { publisher } })
// One-off invocation:
const res = await publisher.generate(
'Draft a LinkedIn post about our v2 launch and schedule it for tomorrow 9am CET. Save as draft.'
)
console.log(res.text)Step 3 — Fan out across platforms in a Workflow
For a launch campaign, you don't want sequential one-by-one drafting — three parallel Workflow steps draft and schedule for LinkedIn, Bluesky, and Threads concurrently. Mastra's createStep() + .parallel() handles the orchestration:
import { createWorkflow, createStep } from '@mastra/core/workflows'
import { z } from 'zod'
const platformStep = (platform: string) =>
createStep({
id: `draft-and-schedule-${platform}`,
inputSchema: z.object({ launchSummary: z.string(), scheduledAt: z.string() }),
outputSchema: z.object({ platform: z.string(), postId: z.string() }),
execute: async ({ inputData, mastra }) => {
const publisher = mastra.getAgent('publisher')
const res = await publisher.generate(
`Draft and schedule a ${platform} post about: ${inputData.launchSummary}. ` +
`Schedule for ${inputData.scheduledAt} as a draft. Match the ${platform} voice. ` +
`Return only the Posta post ID.`
)
return { platform, postId: res.text.trim() }
},
})
export const launchWorkflow = createWorkflow({
id: 'launch-campaign',
inputSchema: z.object({ launchSummary: z.string(), scheduledAt: z.string() }),
outputSchema: z.array(z.object({ platform: z.string(), postId: z.string() })),
})
.parallel([
platformStep('linkedin'),
platformStep('bluesky'),
platformStep('threads'),
])
.commit()Step 4 — Run the Workflow
const run = await launchWorkflow.createRunAsync()
const result = await run.start({
inputData: {
launchSummary: 'Shipped v2 of the SDK: per-platform caption limits, batch media endpoint, OpenAPI updates.',
scheduledAt: '2026-06-20T09:00:00+02:00', // tomorrow 9am CET
},
})
console.log(result)Closing the loop with a webhook trigger
For closed-loop pipelines (publish → react), expose an HTTP endpoint in your Mastra deployment that receives Posta's outbound webhooks and triggers a follow-up Workflow. Verification is HMAC-SHA256; see the verified receiver pattern in webhook-driven social media agent loops.
When to use the REST path instead
For a single deterministic Workflow step that doesn't need an LLM, define a typed createTool() wrapping the Posta REST API directly. The two-step shape (POST /v1/posts with socialAccountIds/mediaIds, then POST /v1/posts/:id/schedule with scheduledAt) is documented on the Mastra integration page.
Pitfalls
- Top-level
await mcp.getTools()needs ESM. If you're still on CommonJS, wrap the Agent construction in an async init function. - Mastra Cloud vs self-hosted. REST wrapper runs anywhere fetch works; MCP stdio transport runs in any Node-capable Mastra deployment.
- Cap parallel platforms. Three concurrent platform-specific generates × Anthropic concurrency limits → you can hit rate limits fast. For more than ~3 platforms, consider chunking with
.foreach(). - Schedule as drafts for the first week. Workflow runs are non-deterministic — review before flipping out of draft mode.
Where to go from here
Read the Mastra integration reference for the full Agent + Workflow wiring and the Zod-tool REST example. Compare with the Vercel AI SDK setup in the Vercel AI SDK tutorial, or the Python framework setups in LangChain and CrewAI. 14-day free trial.