Skip to main content

Use Upload-Post with Pydantic AI

Pydantic AI agents use MCP servers as toolsets. Register the hosted Upload-Post MCP server and your agent gets nearly 60 tools to publish, schedule and analyze posts on TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky and more.

  • Endpoint: https://mcp.upload-post.com/mcp (Streamable HTTP)
  • Auth: Authorization: ApiKey <UPLOAD_POST_API_KEY>

Installation​

pip install "pydantic-ai-slim[mcp,openai]"

(or pip install pydantic-ai for every optional group).

API key​

Generate a key in the Upload-Post dashboard under API Keys, connect your social accounts to a profile, then export it together with the key for your model provider:

export UPLOAD_POST_API_KEY="your-upload-post-api-key"
export OPENAI_API_KEY="your-openai-api-key"

Example​

import asyncio
import os

from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset

upload_post = MCPToolset(
"https://mcp.upload-post.com/mcp",
headers={"Authorization": f"ApiKey {os.environ['UPLOAD_POST_API_KEY']}"},
)

agent = Agent(
"openai:gpt-5.2",
toolsets=[upload_post],
instructions=(
"You publish social media posts through Upload-Post. Call list_users first "
"to find the profile and its connected accounts. After an upload, poll "
"get_status with the returned request_id until it finishes."
),
)


async def main() -> None:
async with agent: # opens the MCP connection once for the whole block
result = await agent.run(
"List my Upload-Post profiles, then post 'Hello from Pydantic AI!' to X "
"and LinkedIn from the first profile and tell me the final status."
)
print(result.output)


asyncio.run(main())

If you also connect other MCP servers, prefix the tool names to avoid clashes: MCPToolset(...).prefixed("upload_post").

Pydantic AI v1

MCPToolset is the Pydantic AI v2 API. On v1 the equivalent class is MCPServerStreamableHTTP from pydantic_ai.mcp, which takes the same url and headers arguments.

Uploads are asynchronous​

upload_video, upload_photos and upload_text return a request_id right away while the post is delivered to each platform in the background. The agent should call get_status with that request_id until it reports success or failure. Scheduled or queued posts return a job_id instead: check them with get_job_status or list_scheduled. See Async uploads.