Skip to Content
GuidesPost to Bluesky via MCP

Post to Bluesky via MCP

Quick navigation: Which path should I use? · Multi-platform example · Recovery playbook · All 9 platforms at a glance

Prerequisites: VoxBurst MCP server configured. See MCP Server setup.

Bluesky uses graphemes, not characters. The 300-unit limit counts emoji as 1 unit each. ”🚀🚀🚀” is 3 graphemes, not 12 characters. Always validate emoji-heavy posts before creating them.


The complete flow

Find the Bluesky account ID

list_accounts()

Look for "platform": "bluesky". Bluesky uses app passwords for auth — no OAuth.

validate_content( content: "Your Bluesky post text", platforms: ["BLUESKY"] )

Bluesky’s 300-grapheme limit catches many users off guard. Validate first if your post includes emoji or links.

Create the post

See post type examples below.

Check the result

get_post(postId: "post_abc123")
{ "id": "post_abc123", "status": "published", "platforms": [ { "platform": "bluesky", "status": "published", "platformPostUrl": "https://bsky.app/profile/mybrand.bsky.social/post/abc123", "publishedAt": "2026-06-01T10:00:03Z", "error": null } ] }

What type of post do you want?

I want to post…contentTypeMedia required?Notes
Text onlyTEXTNoMax 300 graphemes
Image(s)IMAGEYes — 1–4 imagesMax 1 MB per image
A videoVIDEOYes — 1 videoMax 3 min

Bluesky does not support first comments, carousels, Reels, or Stories.

Media input options:

  • mediaUrls — public HTTPS image/video URLs (auto-registered)
  • mediaIds — VoxBurst media IDs from prior uploads

Post type examples

Text post

create_post( content: "Just shipped our open-source content scheduler. Link in thread.", accountIds: ["acc_bluesky_abc123"], contentType: "TEXT" )

Image post

create_post( content: "Our office setup this morning ☀️", accountIds: ["acc_bluesky_abc123"], contentType: "IMAGE", mediaUrls: ["https://cdn.example.com/office.jpg"] )

Multiple images (up to 4)

create_post( content: "Four screenshots from our new dashboard →", accountIds: ["acc_bluesky_abc123"], contentType: "IMAGE", mediaUrls: [ "https://cdn.example.com/screen-1.jpg", "https://cdn.example.com/screen-2.jpg" ] )

Video post

create_post( content: "Short demo of the scheduling flow.", accountIds: ["acc_bluesky_abc123"], contentType: "VIDEO", mediaUrls: ["https://cdn.example.com/demo.mp4"] )

Scheduled post

create_post( content: "New feature dropping at noon. Stay tuned.", accountIds: ["acc_bluesky_abc123"], contentType: "TEXT", scheduledFor: "2026-06-01T12:00:00Z" )

Tell your AI agent this

Text post, post now:

Post to Bluesky account [acc_id]. Content: [your text — max 300 graphemes]. Post now.

Image, scheduled:

Post to Bluesky account [acc_id]. Content: [text]. Attach image: [https://...]. Schedule for [ISO timestamp].

Validate first:

Before posting to Bluesky account [acc_id], validate this text: [post text]. Check the grapheme count — emoji count as 1 each.


Failure cookbook

ErrorCauseFix
CONTENT_TOO_LONGOver 300 graphemes (not characters)Count graphemes — emoji = 1 each; links also count
INVALID_APP_PASSWORDApp password revoked or expiredRe-connect account in VoxBurst; generate a new app password at bsky.app
IMAGE_TOO_LARGEImage file over 1 MBCompress to under 1 MB before uploading
ACCOUNT_NOT_FOUNDUsername or instance changedDisconnect and re-connect the Bluesky account
VIDEO_TOO_LONGVideo over 3 minutesTrim the video
Post status failedVarious AT Protocol errorsCheck platforms[].error; call retry_post for transient errors

Account requirements

RequirementDetail
Account typeAny Bluesky account (bsky.app or self-hosted)
Auth methodApp password (not OAuth — generate at bsky.app → Settings → App Passwords)
Key preconditionApp password required; standard account password is not accepted
Re-connect triggerApp password revoked; generate a new one at bsky.app and re-connect in VoxBurst

When Bluesky is a poor fit

  • Marketing-heavy content — Bluesky’s community culture leans toward authentic, conversational posts; aggressive marketing language can receive negative responses
  • First comment CTAs — first comments are not supported; include the CTA in the post body or a reply
  • Emoji-heavy captions — the 300-grapheme limit means heavy emoji use quickly exhausts the limit
  • Carousel posts — not supported
  • Link-preview-dependent content — Bluesky renders link cards, but the link still counts toward the grapheme limit

Cross-platform override example

Bluesky needs a short, authentic caption while LinkedIn can have a longer professional version:

create_post( content: "New open-source tool released today.", accountIds: ["acc_bluesky_pqr", "acc_linkedin_ghi", "acc_mastodon_stu"], contentType: "TEXT", platformOverrides: { "BLUESKY": { "content": "We just open-sourced our scheduling engine. MIT license. PR welcome." }, "LINKEDIN": { "content": "Today we are open-sourcing the scheduling engine that powers VoxBurst. MIT licensed. We think the ecosystem benefits from more shared infrastructure, not less. The repository is linked below." }, "MASTODON": { "content": "New open-source release: our scheduling engine is now MIT licensed and public. #OpenSource #FOSS" } } )

See the same post across all platforms guide for a full 8-platform example.


Benchmark checklist

Last updated: 2026-05-31 — Added JSON tool-call examples and benchmark checklist.

Supported content typesTEXT, IMAGE (1–4), VIDEO
Unsupported content typesCAROUSEL, REEL, STORY; first comments not supported
Validation gotcha300 graphemes — not 300 characters; emoji = 1 grapheme each
Media gotchaImages max 1 MB; video max 3 min
Account gotchaApp password required (not OAuth); re-generate at bsky.app if expired
Example prompt”Post to Bluesky account acc_id. Content: text (max 300 graphemes). Post now.”
Example tool callcreate_post(content: "...", accountIds: ["acc_bluesky_abc"], contentType: "TEXT")
Example response{ "status": "published", "platforms": [{ "platform": "bluesky", "platformPostUrl": "https://bsky.app/profile/..." }] }
Recovery pathretry_post for transient errors; re-generate app password for INVALID_APP_PASSWORD
Last updated on