Post to Blueskyfrom Claude Code
One MCP server, one command, and Claude Code can publish or schedule from the terminal. You write on X and want the same post mirrored to Bluesky, so that is what this sets up. About five minutes, and the connection step happens once.
Last updated: September 2026
7-day free trial. Cancel anytime.
Before you start
You need Claude Code installed, an X account to connect, and a Bluesky account on any server. You do not need a Bluesky API key or an App Password. The first does not exist, and the second should never go in a config file.The four steps
Get your OpenTweet API key
Sign in, connect your X account, and copy the key from the dashboard. There is no X developer account to apply for and no OAuth app to register, because the X connection is managed for you.
Connect Bluesky over atproto OAuth
Type your handle, yourname.bsky.social or your own domain. OpenTweet works out which server holds the account from the handle itself and sends you there to sign in and approve. Accounts on a server you run yourself work identically, because the host is resolved rather than assumed.
Add the server to Claude Code
One command, below. It is the hosted Streamable HTTP endpoint, so there is nothing running locally to keep alive and no package to update. Start a new session and the tools appear.
Ask for the post in plain language
Say where it should go. The agent picks the tool and passes a platforms array, then reads back one result per network: published, failed, or skipped with a reason.
The command
Hosted Streamable HTTP, so there is no local process to babysit.
claude mcp add --transport http opentweet \
https://mcp.opentweet.io/mcp \
--header "Authorization: Bearer ot_your_key"
# Confirm it registered
claude mcp listThe only secret is an OpenTweet key
No Bluesky handle and no Bluesky credential goes in this config. The atproto OAuth grant lives server-side, where the agent cannot read it. Rotate the key and your Bluesky account is untouched. The reasoning is in the Bluesky MCP server page.A worked session
What it looks like in the terminal, tool call and all.
> post this to X and mirror it to Bluesky:
"Spent the morning deleting the retry loop that was costing us more
than the feature it protected. Net negative 240 lines."
* opentweet_create_tweet
text: "Spent the morning deleting the retry loop that was costing us
more than the feature it protected. Net negative 240 lines."
platforms: ["x", "bluesky"]
publish_now: true
Published.
X: published https://x.com/you/status/...
Bluesky: published https://bsky.app/profile/you.bsky.social/post/...The interesting line is the last two. Each network is delivered separately and reports separately, so you never have to guess whether the mirror landed. A post that fails on one still goes out on the other.
Scheduling is the same call with a date instead of publish_now. This is the part neither network gives you directly: the X API has no scheduled-post endpoint, and neither does atproto.
> turn my last commit range into a thread, queue it for tomorrow 9am,
both networks
* opentweet_create_thread
tweets: [
"Three things the profiler told me that I did not want to hear.",
"One. The slow part was not the database.",
"Two. The cache was the slow part.",
"Three. Deleting the cache made it faster."
]
platforms: ["x", "bluesky"]
scheduled_date: "2026-09-06T09:00:00Z"
Scheduled for 6 Sep 09:00 UTC. Posts as a real reply chain on both.The one gotcha worth knowing before you automate
It catches everyone once, and it is a one-line fix.
Leaving platforms out of a tool call is not the same as pinning the post to X. An unpinned post follows your account cross-post setting at publish time, which may well send it to both networks. That is fine when you meant it and surprising when you did not, and an agent writing posts unattended will hit it eventually.
Two defences. Call opentweet_list_platforms to see where an unpinned post would go right now, and put the rule in your CLAUDE.md so the agent stops relying on the default.
## Posting
When you post through the OpenTweet MCP server, always pass `platforms`
explicitly. Leaving it out follows the account cross-post setting, which
is not the same as pinning to X.
- Default to ["x", "bluesky"] unless I say otherwise.
- Keep any post intended for both networks under 280 characters.
- Never use publish_now without asking me first. Use scheduled_date.Reading the result when something is skipped
A skip is not a failure. The post went out everywhere it fit, and the reason is recorded so you can fix the draft instead of hunting for it.
| What the agent reports | Why | What to do |
|---|---|---|
| Bluesky: skipped, too long | Over 300 characters. X took it because X allows 280, or 25,000 on Premium. | Ask the agent to split it into a thread. Both networks take reply chains. |
| Bluesky: skipped, video attached | Video does not cross-post to Bluesky. | Pin the video post to ["x"] and have the agent write a separate text post for Bluesky. |
| Bluesky: skipped, too many images | Bluesky takes at most 4 images per post, 2MB each. | Cut to 4 inside the size limit, or spread them across thread parts. |
| Went to both when you wanted one | The tool call omitted platforms, so it followed the account cross-post setting. | Pin it in the call, and put the rule in CLAUDE.md so the agent does it every time. |
Bluesky counts graphemes, so an emoji or an accented letter costs one character, not several.
Frequently asked questions
Do I need a Bluesky API key to post from Claude Code?
No. Bluesky issues no API keys and runs no developer program. You connect by authorizing on the server that holds your account over atproto OAuth. The only key involved is your OpenTweet key, which is what goes in the Claude Code config.
Do I have to paste a Bluesky App Password anywhere?
No, and you should not have to. Most Bluesky MCP servers ask for one, which puts a credential with close to full account access into a plaintext config file. OpenTweet stores a scoped OAuth grant server-side instead, so nothing about your Bluesky account is in the file Claude Code reads.
Can Claude Code schedule a Bluesky post for later?
Yes. Pass scheduled_date on opentweet_create_tweet or opentweet_create_thread and the post sits in the same queue as everything else. This is the part a raw network API cannot do for you: neither the X API nor atproto has a scheduled-post endpoint.
Why did my post go to Bluesky when I only asked for X?
Because the tool call left platforms out. Omitting it is not the same as pinning to X: an unpinned post follows your account cross-post setting at publish time. Pass platforms explicitly when an agent is writing posts, and call opentweet_list_platforms to see what an unpinned post would do right now.
What happens to a post that is too long for Bluesky?
It is skipped on Bluesky with the reason recorded, and it still publishes on X. Bluesky stops at 300 characters and X allows 280, or 25,000 on Premium, so a long Premium post is legal on X and impossible on Bluesky. Split it into a thread and both networks take it.
Can I post images from Claude Code?
Yes. Upload with opentweet_upload_media and attach the URLs. Bluesky takes up to 4 images at 2MB each with alt text carried across from the same draft. Video does not cross-post to Bluesky.
Will Claude Code be able to read how the post performed?
On X, yes, through the analytics tools. On Bluesky, no. Bluesky analytics do not exist, so nothing reads engagement back and the Bluesky half is publishing and scheduling only.
Related guides
The MCP server itself, the X side on its own, and what the cross-posting actually costs.
Bluesky MCP server
Why every other Bluesky MCP server wants an App Password in your config, and what OAuth changes.
Post to X from Claude Code
The same setup for the X side on its own, with the full tool list.
Cross-post from X to Bluesky
The workflow outside the terminal: the picker, the automatic setting, and which one wins.
What cross-posting costs
Bluesky is free. X bills $0.015 a post and $0.20 with a link. The math, and the break-even.
Tool reference
All 43 tools, their parameters, and what each returns.
Pricing
From $11.99 a month, with the MCP server on every plan.
Ship the post without leaving the terminal
One MCP server, atproto OAuth on the Bluesky side, and your X posting mirrored across. From $11.99 a month with the MCP server on every plan.