Skip to content
SocialsForAI
Menu

Social media MCP server

One MCP server for every network your agent posts to.

Hosted, Streamable HTTP, bearer-key auth. The same preflight, idempotency and receipts as the REST API.

  • LinkedIn MCP server

    Hosted LinkedIn MCP server for personal profiles. What each tool returns for LinkedIn, a worked dry-run session, the 60-day token, escaping, caps and error fixes.

  • X (Twitter) MCP server

    Hosted X MCP server. What each tool returns for X, the 280 weighted-character and $0.20 link-post rules, OAuth with refresh, and X-specific error fixes.

  • Bluesky MCP server

    Hosted Bluesky MCP server, live today. What each tool returns for Bluesky, app-password setup, facets, a worked session, caps and Bluesky error fixes.

What is a social media MCP server?

A social media MCP server exposes posting as tools an AI agent can call through the Model Context Protocol. Instead of writing an integration per network, the agent calls create_post with account ids and text, and the server handles each network's API, limits and errors.

SocialsForAI's server runs at https://socialsforai.vercel.app/api/mcp over Streamable HTTP and authenticates with the same bearer API key as the REST API. It exposes eight tools: list_platforms, list_accounts, create_connect_link, create_post, get_post, list_posts, cancel_post and get_usage.

Why use a hosted server instead of one per network?

Running your own MCP server for a network usually means registering your own developer app with that network, keeping its client secret on your machine, and running a separate server per platform. A hosted server needs one key and one connection, and the account owner approves access on the network's own screen through a connect link.

It also applies the same rules on every network before anything goes out: length counted the way each network counts it, duplicate text on the same account within 24 hours, image limits, and a per-account daily cap. Those checks are ordinary code with no AI calls, and a dry run returns each problem with a fix the agent can act on.

Which networks work today?

Five networks are live: X, Bluesky, LinkedIn (personal profiles), Mastodon (any server) and Telegram (channels and groups, through a bot). Instagram, Threads, Facebook, TikTok, YouTube, Pinterest and Reddit are coming; each needs the network's own review or is still being built. Video isn't supported on any network yet. The list_platforms tool always returns the current status, so an agent never has to guess.

Keeping a human in the loop

Agents can't complete OAuth for someone else, so a person always approves account access. For posting, the safest pattern is to have the agent call create_post with dry_run: true, show you the preview, and publish only after you confirm. Passing an idempotency_key means a retried tool call never posts twice.

An agent with a posting tool can publish something wrong faster than a person can read it. The server gives you four controls; use all of them.

  • Dry run first. dry_run: true runs every preflight check and returns the exact text each account would get, without publishing or consuming an idempotency key. The checks are plain code with no AI calls and no cost.
  • Ask for approval. Tell the agent to show you the dry-run preview and wait for a yes. Leave your client's tool approval prompt on for create_post, so the publish call itself needs a click.
  • Send an idempotency key. If the agent retries after a timeout with the same key and the same body, it gets the original post back instead of a second one.
  • Rely on the caps. Each account has a fair-use cap per rolling 24 hours: 100 on X, 300 on Bluesky and Mastodon, 50 on LinkedIn, 500 on Telegram (daily_cap_reached). Identical text to the same account within 24 hours is blocked with duplicate_content.

Every tool and its inputs

The server exposes eight tools. None of them is tied to one network: the same create_post call can target accounts on several networks at once, with a different text per network through platform_options. Inputs below are the real schema fields. The LinkedIn, X and Bluesky pages describe what each tool returns for that network.

  • list_platforms (no input): each platform's id, name, whether it's available on this server, and its limits: maxChars, maxImages, supportsVideo, dailyPostCap.
  • list_accounts (platform?, external_ref?): connected accounts with id, platform, handle, display_name, status (active or needs_reauth) and connected_at. The ids go into create_post.
  • create_connect_link (platforms?, external_ref?, redirect_url?, expires_in?): a hosted URL the account owner opens. expires_in is 300 seconds to 30 days and defaults to 7 days.
  • create_post: accounts (1 to 100 account ids), text (up to 10,000 characters before per-platform limits), media (up to 20 items of {url, type?: image|video, alt?}), platform_options (per-platform text, for example {"x": {"text": "..."}}), scheduled_at (ISO-8601 with offset, up to 365 days ahead), dry_run (default false), wait (default true on the MCP server, so the call returns per-account results), idempotency_key (up to 255 characters) and metadata (any JSON object you want back on the post).
  • get_post (id): the post with one target per account: status, url, external_post_id, attempts, next_attempt_at, published_at, verified and error (code, message, fix, retryable).
  • list_posts (status?, limit 1 to 100, default 20, before? cursor): recent posts, newest first, with has_more and next_cursor.
  • cancel_post (id): cancels a scheduled post that hasn't started publishing. A post that is already publishing returns post_not_cancelable.
  • get_usage (no input): active accounts this month, posts, plan and estimated cost.

Set up in Claude Code, Cursor or Claude Desktop

Claude Code adds remote servers with claude mcp add --transport http and takes request headers with --header, per its MCP docs. Export your key first so it never lands in shell history as plain text, then run the command below.

The default scope is local (this project, only you). Add --scope user to load the server in every project. Avoid --scope project with a raw key: that scope writes .mcp.json in the project root, which is meant to be committed. Run claude mcp list to confirm the server shows as connected, or /mcp inside a session. Tools appear as mcp__socials__create_post and so on. Cursor and Claude Desktop follow in the next two sections; other clients are on the agent guides.

bash
export SOCIALS_API_KEY=sk_...
claude mcp add --transport http socials https://socialsforai.vercel.app/api/mcp \
  --header "Authorization: Bearer $SOCIALS_API_KEY"

Cursor configuration

Cursor reads .cursor/mcp.json in a project or ~/.cursor/mcp.json for every project, and supports Streamable HTTP servers with url and headers. Cursor resolves ${env:NAME} inside headers, so the key can stay in your environment. Cursor asks for approval before running MCP tools by default; keep that on for create_post. More in the Cursor guide.

json
{
  "mcpServers": {
    "socials": {
      "url": "https://socialsforai.vercel.app/api/mcp",
      "headers": { "Authorization": "Bearer ${env:SOCIALS_API_KEY}" }
    }
  }
}

Claude Desktop configuration

Claude Desktop launches local servers from claude_desktop_config.json (on macOS in ~/Library/Application Support/Claude/, on Windows in %APPDATA%\Claude\). mcp-remote bridges that to our HTTP server and forwards your key with --header. Its README notes that some clients, Claude Desktop on Windows among them, don't escape spaces inside args, so the header is written without a space after the colon and the Bearer sk_... value sits in env. Restart Claude Desktop after saving. More in the Claude Desktop guide.

json
{
  "mcpServers": {
    "socials": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://socialsforai.vercel.app/api/mcp",
               "--header", "Authorization:${AUTH_HEADER}"],
      "env": { "AUTH_HEADER": "Bearer sk_..." }
    }
  }
}

Troubleshooting by error code

Every error carries a stable code, a message and a fix written for the agent to act on. Tool errors come back as an MCP error result whose text is the same JSON body the REST API returns. This is the full list of codes that behave the same on every network; the LinkedIn, X and Bluesky pages add the causes specific to each.

  • HTTP 401 when the client connects: the Authorization header is missing or the key is wrong. The server checks the bearer key before any tool runs. On the REST API the same problem returns missing_api_key or invalid_api_key. Check the header spelling (Authorization: Bearer sk_...) and that the environment variable is set in the process that launches the client.
  • account_not_found (404): an id in accounts doesn't belong to this workspace, often because the agent invented one. The fix tells it to call list_accounts.
  • preflight_failed (422): the post would fail at least one check, and nothing was published. The issues array lists every problem with code, field and fix. Repeat the call with dry_run: true until ok is true.
  • text_too_long, too_many_media, video_not_supported, empty_post: per-network content checks inside preflight_failed. Each issue names the account and, for text, the platform_options field to set a shorter version in.
  • account_needs_reauth: the account's token expired or was revoked. Call create_connect_link with that platform and send the URL to the account owner. The account keeps its id when reconnected.
  • duplicate_content: the same text went to the same account in the last 24 hours. Vary the text, or set a per-platform version in platform_options.
  • daily_cap_reached: the account hit our fair-use cap for the rolling 24 hours. Pass scheduled_at to post later.
  • scheduled_in_past or scheduled_too_far: scheduled_at is more than 5 minutes ago or more than 365 days ahead. Omit it to publish now.
  • idempotency_key_reused (409): the key was already used with a different body. Use a new key for a different post; reuse a key only to retry the identical request.
  • post_not_cancelable (409): cancel_post was called on a post that already started publishing. Delete published copies on the network itself.
  • platform_unavailable (400) from create_connect_link, or platform_not_configured in a dry run: that network isn't live on this server. list_platforms shows which are.
  • connect_link_expired (410): the link is past its expires_in. Create a new one.
  • invalid_media_url, media_fetch_failed or media_too_large: we couldn't download an image from a public http(s) URL, or it's over that network's size limit. Host the file publicly and pass its URL.
  • platform_rate_limited or platform_unavailable on a target: the network said no for now. These are retryable; we try again after 30 seconds, 2 minutes, 10 minutes, 30 minutes and 2 hours, six attempts in total, then mark the target failed. Poll with get_post instead of posting again.
  • platform_rejected: the network refused the post after preflight passed. Its message is included; adjust the post and send it with a new idempotency key.
  • plan_limit_active_accounts or plan_limit_posts: the Free plan's 3 active accounts or 100 posts a month is used up. Both are hard limits on Free only.

Questions

What people ask

Is there a free social media MCP server?

Yes. SocialsForAI's Free plan covers 3 active accounts and 100 posts a month, with the MCP server included. Paid plans add accounts and unlimited posts; every plan includes the MCP server, the REST API and webhooks.

Which MCP clients does it work with?

Any client that supports remote MCP servers over Streamable HTTP with a custom Authorization header, such as Claude Code and Cursor. Clients that only run local servers can connect through mcp-remote, which forwards the header. Setup guides are on the agent pages.

Does the agent see my social media passwords?

No. Account owners approve access on the network's own OAuth screen, or with a Bluesky app password, Mastodon access token or Telegram bot token, from a hosted connect link. Credentials are stored encrypted with AES-256-GCM and never returned by the API or the MCP server.

Can an agent spam my accounts with this?

Each account has a fair-use cap per rolling 24 hours (100 on X, 300 on Bluesky and Mastodon, 50 on LinkedIn, 500 on Telegram), identical text on the same account within 24 hours is blocked, and every post can go through a dry run first. You can also revoke the API key at any time.

Get an API key and send your first post in five minutes.