Post to X from Claude Code
Claude Code works in your terminal, next to your code. Add calmposts' X (Twitter) MCP server and it can turn what you just shipped into a post or a thread for X and Bluesky, saved as a draft or put in the queue for you to approve.
- Connection
- Remote MCP server over Streamable HTTP: nothing to install
- Sign-in
- API key in the Authorization header
- Server address
https://calmposts.com/mcp- Where you set it up
- claude mcp add, or .mcp.json in the project
What Claude Code can do with calmposts
Claude Code already reads your repository, your diffs and your commit history. With calmposts it can write about them where people will see it: a release thread from the changelog, a short post about a fixed bug, a week of build-in-public updates from the git log.
It calls list_accounts to see your channels and each network's rules, get_limits for the posts left today and the workspace's time zone, and create_post to save a draft, add the post to the queue or schedule it for a time. Later it can check with list_posts and get_post what went out, and read get_post_metrics on plans with analytics.
calmposts' X (Twitter) MCP server gives Claude Code 11 tools, the same set every client gets:
| Tool | Does |
|---|---|
list_accounts | your channels and each network's rules; customer_id: one customer's |
list_customers | the customers (an agency's clients) with their channels' ids |
get_limits | plan usage, the workspace's time zone, network limits |
create_post | a post or a thread for the chosen accounts, wording per account, images by URL; when: draft, queue, at or now |
list_posts | posts by status, account, customer and time range |
get_post | one post with its channels, status and version |
update_post | edit or reschedule; what is left out stays |
delete_post | cancel and remove |
get_next_slot | where when=queue would put a post |
retry_post | send the failed channels again |
get_post_metrics | a published post's counts on each channel at 1 h, 24 h and 7 days (plans with analytics); read only |
Set up calmposts in Claude Code
Check the key before you start
Create a key in calmposts under API & MCP (it's shown only once), then ask the server for its tools. A list of 11 tools means the address and the key are right; a 401 means the key is wrong or was sent without “Bearer ”.
curl -s https://calmposts.com/mcp \
-H "Authorization: Bearer cp_live_…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# 200 {"jsonrpc":"2.0","id":1,"result":{"tools":[…]}}Setup 1: One command, with a key
The quickest setup: Claude Code stores the address and the header for this project.
In calmposts, open API & MCP, create a key with the permissions the agent needs and copy it: it is shown once.
Add the server, with your key in place of cp_live_…:
claude mcp add --transport http calmposts https://calmposts.com/mcp \ --header "Authorization: Bearer cp_live_…"Check the connection; the status should read ✔ Connected:
claude mcp get calmpostsIn a session, /mcp lists calmposts with its 11 tools:
/mcp
Setup 2: A team's .mcp.json, the key in the environment
For a repository you share: the file names a variable, and each person keeps their own key.
Each person puts their key in the environment Claude Code starts from, for example in ~/.zshrc:
export CALMPOSTS_API_KEY=cp_live_…Commit .mcp.json at the project's root:
{ "mcpServers": { "calmposts": { "type": "http", "url": "https://calmposts.com/mcp", "headers": {"Authorization": "Bearer ${CALMPOSTS_API_KEY}"} } } }Run claude in the project and approve calmposts when Claude Code asks; claude mcp list then shows it connected.
Signing in: a key or OAuth
Claude Code sends the key as a header with every request, so nothing else is needed: no browser and no consent page. That also makes it work in headless runs (claude -p), which have no /mcp panel to sign in from.
Give the key only what the agent needs: a key that only drafts can go without media:write. Revoking the key in API & MCP cuts Claude Code off on its next call.
Claude Code supports OAuth for remote servers too. If calmposts is already a connector in your claude.ai account, Claude Code signed in with that account picks it up and lists it in /mcp. For a server added with claude mcp add, the key is the setup this page was checked with.
Check that it works
- claude mcp get calmposts shows ✔ Connected; a failure comes with an Issue line naming the HTTP status and calmposts' error.
- /mcp in a session lists calmposts and its 11 tools.
- Ask “What does calmposts say about my limits?”: Claude Code calls get_limits and reads back your plan, the posts left today and the time zone.
- Ask for a draft and open Posts in calmposts: it is there with the source mcp and your key's name as its author.
Prompts to try
Ask in your own words and the agent picks the tools. A few that work well:
- “Read CHANGELOG.md and write a thread about v2.3 for X and Bluesky. Save it in calmposts as a draft.”
- “Look at the commits since Friday and draft three build-in-public posts; put them in calmposts' queue.”
- “How many posts do I have left today, and when is the next free slot for my X account?”
- “List my scheduled posts for next week and move Tuesday's to Wednesday at 9:30 a.m.”
- “Did yesterday's release post go out everywhere? If a channel failed, tell me why before you retry it.”
Networks, threads and approval
Posts go to X and Bluesky. A thread goes out as a reply chain on X and Bluesky. Coming soon: Threads and LinkedIn.
Write once, post everywhere: your agent sends one text for every account it picks. If the text is longer than a network allows, calmposts posts it there as a thread, splitting at a paragraph break, then at the end of a sentence, then at a space, with nothing numbered or added. calmposts checks each network's rules and your plan's limits before it saves the post and names the field that's wrong, so the agent can fix the text and try again.
By default your agent's posts wait for you. They come back as pending_approval, and you approve or reject each one in the app, in Telegram or from the email calmposts sends. The workspace owner can let agents publish on their own, but only when both the workspace and the API key are set to publish. X expects an account that posts automatically to carry its Automated label (Settings → Your account → Account information → Automation).
Limits and costs
- Agents need a paid plan: the Free plan has no API keys and can't approve connected apps. API keys per plan: Pro 3 · Advanced 10 · Agency 25.
- Your agent's posts count the same as yours. Posts a day: Pro 20 · Advanced 100 · Agency 300. Posts with a link per month: Pro 30 · Advanced 300 · Agency 600. Each post in a thread counts.
- Posts with a link are counted separately because X charges every app $0.015 per post and $0.20 per post with a link. Your plan includes X's fees, so you don't need an X developer account or an X API bill of your own.
- Try it first: 7-day free trial. Card required. 5 posts with a link during the trial.
- Each key can make 60 requests a minute across MCP and REST; beyond that, the server returns 429 with Retry-After.
What to know about Claude Code
- claude mcp add writes to the local scope by default: the server loads only in the project where you ran it, and the key sits in ~/.claude.json. Add --scope user to have calmposts in every project.
- Claude Code asks before it calls a tool that no permission rule allows. Allow rules such as mcp__calmposts__list_accounts or mcp__calmposts__get_* let the reading tools run without a prompt; keep create_post and delete_post on a prompt.
- In .mcp.json, name the variable anything but Claude Code's own credentials: CALMPOSTS_API_KEY expands, while a header built from ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN goes out empty. An unset variable stays as its ${…} text, and claude mcp list warns about it.
- list_posts returns 20 posts by default and at most 100. Claude Code warns when a tool's answer passes 10,000 tokens; ask for fewer posts or a shorter time range.
Without MCP: the REST API
Everything the tools do is also a REST call under /api/v1 with the same key, which suits a script or a workflow step that only speaks HTTP. calmposts posts through its own approved X app, so you don't need X API keys of your own.
export CALMPOSTS_API_KEY=cp_live_…
curl -H "Authorization: Bearer $CALMPOSTS_API_KEY" https://calmposts.com/api/v1/accounts
curl -X POST https://calmposts.com/api/v1/posts \
-H "Authorization: Bearer $CALMPOSTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"parts":[{"text":"Calm posts, scheduled."}],"targets":[{"account_id":"ACCOUNT_ID"}],"schedule":{"mode":"queue"}}'Troubleshooting
claude mcp get shows ✘ Failed to connect
Read its Issue line: 401 with missing_api_key or invalid_api_key is the key. Check the header's spelling, the space after “Bearer” and that the key starts with cp_live_.
Leading or trailing whitespace in: headers.Authorization
The pasted key carries a space or a line break. Run claude mcp remove calmposts and add it again.
⏸ Pending approval
A server from .mcp.json waits for your approval: run claude in the project and approve calmposts.
MCP server calmposts already exists
A server with that name is already in this scope. Remove it with claude mcp remove calmposts, or add the new one with another --scope.
401 missing_api_key
The request came without a key, or without “Bearer ” in front of it. Send Authorization: Bearer cp_live_…, with the space.
401 invalid_api_key, api_key_revoked or api_key_inactive
The key is mistyped, was revoked, or its creator is no longer in the workspace. Create a new key in API & MCP and put it in place of the old one.
401 invalid_token
An OAuth connection's access token expired or was disconnected. Clients refresh it on their own; if that fails, sign in again.
402 quota_exceeded
A plan limit is reached, and field names it: api_keys means the plan has no agents (Free); posts_per_day and link_posts_per_month free up the next day or month, or with a bigger plan.
403 insufficient_scope
The key lacks a permission the tool needs; field names it (posts:write to create posts). Create a key that has it.
429 rate_limited
More than 60 requests a minute came from this key. Wait for the seconds in Retry-After.
The tool answers duplicate_recent
The same text went to the same account in the last 7 days. Ask for a new wording.
The post is pending_approval
That is not an error: the post waits for your yes in calmposts. Approve it there, or let agents publish (the owner sets it on the workspace and on the key).
The account needs_reconnect
The network took back calmposts' access. Reconnect the account under Accounts in the app.
Questions
Does Claude Code need the calmposts-mcp program?
No. Claude Code connects to the hosted server over HTTP; there is nothing to install besides Claude Code.
Where does Claude Code keep the key?
claude mcp add writes it into ~/.claude.json, for this project (local scope) or every project (--scope user). With .mcp.json and ${CALMPOSTS_API_KEY}, the file holds only the variable's name and the key stays in your environment.
Can Claude Code publish right away?
Only when you ask it to post now and both your workspace and the key let agents publish. Otherwise the post waits for your approval, and the server tells agents to prefer the queue or a draft.
Does it work in claude -p and scripts?
Yes, with a key: a headless run cannot sign in with OAuth, but a header needs no sign-in. The key's 60 requests a minute apply.
Can the agent reply, follow or send DMs?
No. There are no tools for that: X forbids automating them, and calmposts only writes and schedules your own posts.
Do I need my own X API keys?
No. calmposts publishes through its own approved X app, and X's per-post fees are part of the plan's price.
The Claude Code docs this page follows
calmposts is an independent service and is not affiliated with or endorsed by the makers of Claude Code. Product names belong to their owners.
Let Claude Code draft your posts, calmly
Start your free trial, connect your accounts, create a key and give Claude Code the address.
Try it free