This tutorial builds a working OpenAI Agents SDK agent setup that posts to social media. It uses two of the SDK's native features: MCP server attachment (so Posta's tools are typed and introspectable) and handoffs (so a router agent triages the request and delegates to a publisher agent that owns the Posta tools).
What you'll build
A Router agent that classifies an incoming request (post about a release? share a customer quote? cross-post a YouTube video?) and hands off to one of three specialist agents — Release, Quote, or Repurpose — each holding the Posta MCP server. Each specialist drafts and schedules through Posta in its own voice.
Prerequisites
- Python 3.11+ and
pip. - A Posta account with at least one connected social account. 14-day free trial.
- A Posta API token.
- An OpenAI API key.
Step 1 — Install dependencies
pip install openai-agentsStep 2 — Define the specialists
Each specialist gets the same Posta MCP server attached via MCPServerStdio — but with different instructions, so the model picks tool calls that match each agent's job:
# agent.py
import os, asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
POSTA_MCP_PARAMS = {
"command": "npx",
"args": ["-y", "posta-mcp"],
"env": {"POSTA_API_TOKEN": os.environ["POSTA_API_TOKEN"]},
}
async def main():
async with MCPServerStdio(params=POSTA_MCP_PARAMS) as posta_mcp:
release_agent = Agent(
name="Release",
instructions=(
"You announce product releases. Draft a long-form LinkedIn "
"post AND a short Bluesky post. Schedule both as drafts."
),
mcp_servers=[posta_mcp],
)
quote_agent = Agent(
name="CustomerQuote",
instructions=(
"You amplify customer quotes. Draft a single Bluesky post "
"that quotes the user with attribution and schedules as a draft."
),
mcp_servers=[posta_mcp],
)
repurpose_agent = Agent(
name="Repurpose",
instructions=(
"You repurpose long-form content (videos, posts) into "
"short-form across LinkedIn, Bluesky, and Threads — drafts only."
),
mcp_servers=[posta_mcp],
)
router = Agent(
name="Router",
instructions=(
"Classify the user request as a Release, a CustomerQuote, "
"or a Repurpose, then hand off to the right specialist."
),
handoffs=[release_agent, quote_agent, repurpose_agent],
)
result = await Runner.run(
router,
input=(
"We shipped v2 of our SDK today: per-platform caption limits, "
"batch media endpoint, OpenAPI updates. Get the word out."
),
)
print(result.final_output)
asyncio.run(main())Step 3 — Run it
export POSTA_API_TOKEN=posta_...
export OPENAI_API_KEY=sk-...
python agent.pyThe Router classifies the input as a Release, hands off to the Release specialist, and the Release specialist calls Posta's tools to create the LinkedIn and Bluesky drafts. The handoff carries the input + conversation context; the specialist returns the final answer up the chain.
Adding Sessions for multi-turn campaigns
For multi-turn campaigns ("now schedule the day-2 post"), wrap the runs in a session so the agent remembers the campaign state across turns. Session is the abstract base; use the concrete SQLiteSession (or OpenAIConversationsSession) to actually instantiate one:
from agents import SQLiteSession
async with MCPServerStdio(params=POSTA_MCP_PARAMS) as posta_mcp:
# ... define agents as above
session = SQLiteSession("sdk-v2-launch")
# Day 1
await Runner.run(router, input="Launch campaign: SDK v2...", session=session)
# Day 2 — same session, agent knows what day 1 looked like
await Runner.run(router, input="Schedule the day-2 post following up on yesterday's launch.", session=session)Closing the loop with webhooks
Pair this with a webhook receiver that triggers a new Runner.run() when Posta fires post.published — that's how the agent reacts to platform feedback in real time. See webhook-driven social media agent loops for the full pattern.
Pitfalls
- Attach the MCP server to the agent the handoff lands on, not the router. If the router holds the MCP server but doesn't use it, you pay for an extra tool list in every router prompt.
- Cap
max_turns. Defaults are generous; tool-calling loops can run away when an unfamiliar error shape comes back from Posta. - Always schedule as drafts for the first week. Handoff chains are easier to debug when posts haven't already shipped.
- Use
tool_use_behavior="stop_on_first_tool"for one-shot deterministic flows. When you want the agent to call exactly one Posta tool and return — not loop — set this.
When to use the Responses API directly instead
The Agents SDK is ergonomic sugar on top of the Responses API + function-tool contract. If you don't need handoffs or sessions, registering a function tool that wraps the Posta REST API directly with the Responses API is one fewer abstraction.
Where to go from here
Read the OpenAI Agents SDK integration reference for the full handoff + sessions wiring. Compare with the LangChain and CrewAI approaches in the LangChain tutorial and the CrewAI tutorial. For the broader pattern map, see agentic social media workflows. 14-day free trial.