Updated October 2026

Give a Claude Agent SDK agent an X, LinkedIn and Bluesky tool

Pass OpenTweet's hosted MCP server to the Agent SDK's mcpServers option with your ot_ key in the Authorization header, and the agent gets 43 tools for posting, threads and scheduling. No X developer account is needed, and plans start at $11.99 a month.

The same entry works in TypeScript (@anthropic-ai/claude-agent-sdk) and Python (claude-agent-sdk). Both are below, along with the permission rule that trips most people up.

7-day free trial. Cancel anytime.

What your agent can do

All 43 tools arrive with one server entry. You do not write a tool wrapper for any of them.

Post now

opentweet_create_tweet with publish_now publishes the moment the agent calls it.

Schedule

Pass scheduled_date on a new post, or schedule existing drafts with opentweet_schedule_tweet and opentweet_batch_schedule.

Threads

opentweet_create_thread ships a connected thread in one call.

43 tools

Posts, threads, articles, evergreen, media and analytics, with no tool code to write.

Three networks

Pass platforms ["x","linkedin","bluesky"] and one call posts to all three.

No X API

No developer account, no OAuth to build, no per-post billing.

Install and set two keys

The Agent SDK needs Node.js 18+ or Python 3.10+ and an Anthropic API key. OpenTweet needs its own ot_ key, which you copy from the dashboard after connecting your accounts. The SDK does not load .env files for you, so export both in the shell that runs the agent or load them yourself.

terminal
# TypeScript
npm install @anthropic-ai/claude-agent-sdk

# Python
pip install claude-agent-sdk

# Both SDKs read these from the environment
export ANTHROPIC_API_KEY=your-anthropic-key
export OPENTWEET_API_KEY=ot_your_key

TypeScript

A remote server takes type: "http", a url and a headers object. The server name you pick, here opentweet, becomes the middle part of every tool name.

agent.ts
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: 'Post "Shipped v2.3: exports are 40% faster." to X and Bluesky now.',
  options: {
    mcpServers: {
      opentweet: {
        type: "http",
        url: "https://mcp.opentweet.io/mcp",
        headers: {
          Authorization: `Bearer ${process.env.OPENTWEET_API_KEY}`,
        },
      },
    },
    allowedTools: ["mcp__opentweet__*"],
  },
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log("MCP servers:", message.mcp_servers);
  }
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Python

Same fields, snake_case options: mcp_servers and allowed_tools on ClaudeAgentOptions.

agent.py
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "opentweet": {
                "type": "http",
                "url": "https://mcp.opentweet.io/mcp",
                "headers": {"Authorization": f"Bearer {os.environ['OPENTWEET_API_KEY']}"},
            }
        },
        allowed_tools=["mcp__opentweet__*"],
    )

    async for message in query(
        prompt='Post "Shipped v2.3: exports are 40% faster." to X and Bluesky now.',
        options=options,
    ):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            print("MCP servers:", message.data.get("mcp_servers"))
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

The init message lists each server with a status. connected means the key worked. failed or needs-auth means the agent is running without the OpenTweet tools, usually because the key is missing or wrong. pending on its own is not a failure: the server may still be connecting.

Allowing the tools

MCP tools follow the pattern mcp__<server-name>__<tool-name>. OpenTweet's tools already start with opentweet_, so the full name repeats it: mcp__opentweet__opentweet_create_tweet. Without an allowedTools entry, Claude sees the tools but cannot call them.

mcp__opentweet__* allows all of them, including delete and DM campaign tools. For an agent that only posts, list the ones it needs:

agent.ts
allowedTools: [
  "mcp__opentweet__opentweet_list_platforms",
  "mcp__opentweet__opentweet_create_tweet",
  "mcp__opentweet__opentweet_create_thread",
  "mcp__opentweet__opentweet_schedule_tweet",
  "mcp__opentweet__opentweet_list_tweets",
]

Prefer allowedTools to a permission mode here. Anthropic notes that acceptEdits does not approve MCP tools, and bypassPermissions approves them but also switches off most other safety prompts.

Develop against drafts or a test account

An allowed tool runs with no human in the loop. While you build, tell the agent not to publish: a post with neither publish_now nor scheduled_date is saved as a draft you can review in OpenTweet. Or connect a throwaway X test account and have the agent target it by passing the ID from opentweet_list_accounts as x_account_id. Switch to your real profiles only once the prompts behave.

Key or OAuth? Use the key

OpenTweet's hosted server also supports OAuth sign-in, which is how chat apps such as Claude connect with no key. That flow needs a person to click Allow. The Agent SDK does not open a browser or run an interactive OAuth flow: a server that asks for authorization reports needs-auth and the agent carries on without its tools. A headless agent should send the ot_ key.

RouteFitsSetupFor an Agent SDK agent
Hosted MCP + ot_ Bearer keyAgent SDK agents, cron jobs, servers, CIheaders: { Authorization: "Bearer ot_..." }Use this
Hosted MCP + OAuth sign-inChat apps where a person clicks Allow, such as ClaudeAdd the URL, sign in to OpenTweetNot for headless agents
npm package over stdioRunning the server as a local processcommand: "npx", args: ["-y", "@opentweet/mcp-server"]Works, more to maintain
REST, POST /api/v1/postsScripts with no model in the loopOne HTTP call with the same keyUse when no agent decides

Or keep it in .mcp.json

With default query() options the SDK also loads servers from a .mcp.json at the project root (if you set settingSources yourself, include "project"), with ${OPENTWEET_API_KEY} expanded from the environment at runtime. That keeps the key out of the file, which matters because the file usually sits in the repository. You still need the allowedTools entry.

.mcp.json
{
  "mcpServers": {
    "opentweet": {
      "type": "http",
      "url": "https://mcp.opentweet.io/mcp",
      "headers": {
        "Authorization": "Bearer ${OPENTWEET_API_KEY}"
      }
    }
  }
}

Prompts that work

Name the networks every time. A post that leaves platforms out follows your account's auto cross-post setting, which may not be what you meant.

prompt
Draft a post about today's release for X and LinkedIn. Do not publish it.

Write a 4 part thread from CHANGELOG.md and post it to X and Bluesky now.

Post the release note to all three networks: platforms ["x","linkedin","bluesky"].

Write five drafts with platforms ["x"], then schedule them for 9am UTC
on weekdays next week with opentweet_batch_schedule.

Scheduling

opentweet_schedule_tweet takes an ISO 8601 time such as 2026-10-20T09:00:00Z. Once scheduled, OpenTweet sends the post at its time, whether or not your agent process is still running.

Per-network limits

If X is a target and the text is over its limit, the call fails. LinkedIn allows 3,000 characters and gets a thread as one post. A post too long for Bluesky or LinkedIn is skipped there with a reason and still goes to the others.

Plans and limits

Every plan includes the API and the MCP server. Account limits apply per network. LinkedIn means personal profiles only.

PlanPriceX accountsLinkedIn profilesBluesky accountsPosts with links per day
Pro$11.99/month1110
Advanced$29/month33310
Agency$49/month10101020

Over the link allowance, OpenTweet removes the URL and posts the text. URL credits cover overflow on any plan.

The REST fallback

If no model needs to decide anything, for example a nightly job that posts a fixed message, skip the agent. Same key, one endpoint.

post.sh
curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -d '{"text":"Shipped v2.3.","platforms":["x","linkedin","bluesky"],"scheduled_date":"2026-10-20T09:00:00Z"}'

Full field reference in the API docs. Tool details are in the MCP docs.

Frequently asked questions

How does a Claude Agent SDK agent post to X?

Add OpenTweet's hosted MCP server to the mcpServers option (mcp_servers in Python) with type "http", the URL https://mcp.opentweet.io/mcp and an Authorization: Bearer ot_ header. Allow the tools with allowedTools set to mcp__opentweet__*. The agent then has 43 tools, including opentweet_create_tweet, and posts to X through OpenTweet.

Can the same agent post to LinkedIn and Bluesky?

Yes. Connect LinkedIn and Bluesky in OpenTweet settings, then have the agent pass platforms ["x","linkedin","bluesky"] on a post. One tool call goes to all three. LinkedIn means your personal profile. Company pages are not supported.

Why use an ot_ key and not OAuth?

The Agent SDK does not open a browser or run an interactive OAuth flow. Anthropic documents that a server which answers with an authorization challenge reports the status needs-auth and the run continues without its tools. A headless agent should send the ot_ key in the headers. OAuth sign-in is for chat apps such as Claude, where a person clicks Allow.

Why does my agent see the tools but never call them?

MCP tools need explicit permission in the Agent SDK. Without an allowedTools entry, Claude sees the tools but cannot use them. Add mcp__opentweet__* to allow every OpenTweet tool, or list single tools such as mcp__opentweet__opentweet_create_tweet.

Do I need an X developer account?

No. OpenTweet holds the X connection, the OAuth flow and token refresh. Your agent authenticates to OpenTweet with one ot_ key, and the same key covers LinkedIn and Bluesky once they are connected.

Can the agent post links?

Only within your plan allowance. Pro includes 0 posts with links per day, Advanced 10 and Agency 20. Over the allowance OpenTweet removes the URL and still posts the text. URL credits cover overflow on any plan.

Give your agent accounts it can post to

Connect X, LinkedIn or Bluesky, copy your key, add one mcpServers entry.

7-day free trial. Cancel anytime.