Skip to main content
Glama
Firefloco

@chirpie/mcp

README.md
# @chirpie/mcp

**The publishing connector for AI agents.** Chirpie is one API to post, thread and schedule to X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook and Telegram, covering posting, threads, scheduling, drafts, deletion and analytics. This MCP server puts all of it in front of Claude, Cursor, ChatGPT or any other MCP-capable agent, so "post this to X and LinkedIn, and schedule the follow-up for 9am" is a single sentence rather than a pile of platform SDKs, OAuth dances and rate-limit handling.

## Hosted server (recommended)

You don't need to install anything. Point your client at:

```
https://chirpie.ai/mcp
```

Sign in when prompted and you're connected. No API key to copy, nothing to keep up to date.

**Claude Code**

```bash
claude mcp add --transport http chirpie https://chirpie.ai/mcp
```

**Claude**: add Chirpie from the [Claude Connectors Directory](https://claude.ai/directory/chirpie), or Customize → Connectors → + → Add custom connector → `https://chirpie.ai/mcp` ([guide](https://chirpie.ai/docs/mcp/claude))

**Cursor**: add to `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "chirpie": {
      "url": "https://chirpie.ai/mcp"
    }
  }
}
```

**ChatGPT** (web, developer mode): Settings → Apps → Create → MCP server URL `https://chirpie.ai/mcp` → OAuth → Scan Tools ([guide](https://chirpie.ai/docs/mcp/chatgpt))

Prefer a key over OAuth (CI, scripts, clients without an OAuth flow)? Send it as a header:

```json
{
  "mcpServers": {
    "chirpie": {
      "type": "http",
      "url": "https://chirpie.ai/mcp",
      "headers": { "Authorization": "Bearer chirpie_sk_your_key_here" }
    }
  }
}
```

## Local server (this package)

Run the same tool set locally over stdio.

```bash
npm install -g chirpie
chirpie login
```

**Claude Code**

```bash
claude mcp add chirpie -- npx @chirpie/mcp
```

**Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "chirpie": {
      "command": "npx",
      "args": ["@chirpie/mcp"]
    }
  }
}
```

**Cursor**: add to your MCP settings:

```json
{
  "mcpServers": {
    "chirpie": {
      "command": "npx",
      "args": ["@chirpie/mcp"]
    }
  }
}
```

The local server resolves credentials in this order:

1. `CHIRPIE_API_KEY` environment variable
2. `~/.chirpie/config.json` (written by `chirpie login`)

The CLI and this server share that config, so one `chirpie login` covers both.

## Tools

| Tool | What it does |
|------|--------------|
| `chirpie_upload_media` | Upload an image or video and get the id a post can attach. `idempotency_key` makes a retry safe |
| `chirpie_post` | Post to any connected account, now or scheduled, or to several at once. `configuration` publishes it as a story or a reel instead of a feed post; `timezone` reads a `schedule_at` with no offset in an IANA zone; `idempotency_key` makes a retry safe; `draft` saves it instead |
| `chirpie_thread` | Post a 2-25 part thread, to one account or to several at once. Takes `timezone` and `idempotency_key` too; `draft` saves it instead |
| `chirpie_list_posts` | List posts, filtered by status, account, or the group of a multi-account publish |
| `chirpie_get_post` | Fetch one post |
| `chirpie_update_post` | Edit a post that has not published yet, or finish a draft and schedule or publish it. `configuration` changes where it publishes |
| `chirpie_retry_first_comment` | Post a first comment that failed, again. `idempotency_key` makes a retry safe |
| `chirpie_delete_post` | Take a post down from the platform. Chirpie keeps it, marked deleted |
| `chirpie_hide_post` | Hide a post from your Chirpie listings. Nothing reaches the platform |
| `chirpie_unhide_post` | Put a hidden post back in your listings |
| `chirpie_list_accounts` | List connected social accounts, active and inactive |
| `chirpie_activate_account` | Activate an account so it can publish |
| `chirpie_deactivate_account` | Deactivate an account (stays connected, frees a plan slot) |
| `chirpie_disconnect_account` | Disconnect an account (ends the connection, cancels its scheduled posts, frees a plan slot) |
| `chirpie_analytics` | Engagement metrics for a published post. `refresh` asks the platform now instead of reading the stored snapshot, once per post every 5 minutes |
| `chirpie_create_key` | Create an API key, optionally narrowed with `scopes` so it can do less than yours |
| `chirpie_list_keys` | List API keys |
| `chirpie_revoke_key` | Revoke an API key |
| `chirpie_connect_x` | Connect X/Twitter (returns an authorization link) |
| `chirpie_connect_linkedin` | Connect a LinkedIn profile |
| `chirpie_connect_linkedin_pages` | Connect the LinkedIn Pages you administer (coming soon) |
| `chirpie_connect_threads` | Connect Threads |
| `chirpie_connect_instagram` | Connect Instagram, `via` `instagram` (the default) or `facebook` |
| `chirpie_connect_facebook` | Connect a Facebook Page |
| `chirpie_connect_bluesky` | Connect Bluesky with an app password |
| `chirpie_connect_mastodon` | Connect Mastodon on any instance |
| `chirpie_connect_telegram` | Connect a Telegram bot |
| `chirpie_set_x_keys` | Register your own X developer app for connecting X accounts |
| `chirpie_get_x_keys_status` | Check whether your own X developer app is configured |
| `chirpie_remove_x_keys` | Remove your own X developer app |

The hosted and local servers expose exactly the same tools. On the hosted server,
`chirpie_create_key`, `chirpie_list_keys`, `chirpie_revoke_key` and
`chirpie_remove_x_keys` require API-key auth. Sign in with OAuth and they are not
offered, since an OAuth connection must not leave a long-lived key behind or tear
down credentials your other connections depend on.

## Which tools ask before they run?

Every tool carries a title and the standard MCP tool annotations
(`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), so your
client knows what a call does before it runs it. Listing and reading tools are
read-only. Deleting a post or a comment, disconnecting or deactivating an
account, editing a queued post, revoking a key and setting or removing your own
X app are destructive, and clients such as Claude ask before running them unless you have allowed
them.
Hiding, unhiding and activating are neither: each has an exact undo. Creating
tools are not marked idempotent: the ones that take an `idempotency_key` only
make a retry safe when you pass one. Without a key, repeating `chirpie_post`,
`chirpie_thread`, `chirpie_reply_to_comment` or `chirpie_retry_first_comment`
can publish twice, and repeating `chirpie_upload_media` stores a second copy
that expires unused.

## Several accounts in one call

`chirpie_post` and `chirpie_thread` take `account_ids` in place of `account_id`,
up to 25 of them. The answer is then a `group_id` plus one result per account,
in the order they were named, and `account_configurations` gives a single
account its own text, media or thread. The accounts that worked stay published
when another one's platform refuses, so an agent should read `success` on each
result. Pass the `group_id` to `chirpie_list_posts` to read the whole group
back.

## First comment

`chirpie_post` and `chirpie_thread` take `first_comment`, a comment published
under the post the moment it goes out. On a thread it is one comment for the
whole thread, published under the last part. X, Threads, Instagram and Facebook
only: anywhere else the call is refused with `400 first_comment_unsupported`
rather than the comment dropped. It counts as one post against the monthly
quota.

On a multi-account call the shared `first_comment` reaches every account unless
its `account_configurations` entry says otherwise: an entry naming a
`first_comment` replaces it for that account, and `"first_comment": ""`
publishes that account with none, which is how one call sends a first comment
to the accounts that take one while an account whose platform has none still
publishes the post.

Every post carries `first_comment` back, either `null` or
`{ text, status, comment_id, error }`, with `status` one of `pending`, `posted`
and `failed`. A failed first comment never fails its post, so a published post
can be carrying one that did not go out: `chirpie_retry_first_comment` sends it
again, and `chirpie_update_post` changes the text or, with an empty string,
removes it.

## Stories, reels and other publishing options

`chirpie_post`, `chirpie_thread` and `chirpie_update_post` take `configuration`,
the per-platform publishing options, keyed by platform. Instagram takes a
`feed` post, a `story` or a `reel`, and a Facebook Page takes a `feed` post or a
`story`. Leave it out and everything publishes to the feed.

```json
{
  "account_id": "...",
  "text": "Three minutes on how we schedule posts.",
  "media_ids": ["..."],
  "configuration": {
    "instagram": {
      "placement": "reel",
      "video_cover_timestamp_ms": 1500,
      "collaborators": ["a_co_author"],
      "share_to_feed": true
    }
  }
}
```

Each placement carries its own options:

- `instagram` `feed`: up to 10 images, `collaborators` (at most 3 usernames)
  and `user_tags`, each of which needs both `x` and `y`.
- `instagram` `story`: exactly one image or video, no caption (send empty
  text), no first comment and no collaborators. `user_tags` may carry
  coordinates or leave them out.
- `instagram` `reel`: exactly one video and no images, plus `collaborators`,
  `user_tags` (the username on its own, since Instagram reads coordinates only
  on images and stories), `cover` or `video_cover_timestamp_ms` but never both,
  `share_to_feed` and `trial_reel`.
- `facebook` `feed`: a `link`, shown as a preview.
- `facebook` `story`: exactly one image or video, no text, no first comment
  and no link.

Nothing is dropped quietly: a block keyed on a platform that takes no options,
or a field the chosen placement does not carry, is refused with
`400 configuration_unsupported` naming the platform and the field. A story and a
reel are each a single post, so `chirpie_thread` refuses either placement. On a
multi-account call one block serves every account of that platform, and an
`account_configurations` entry naming its own `configuration` replaces it for
that account. On `chirpie_update_post` an absent `configuration` keeps the
options the post already has, and `"configuration": {}` puts it back to a plain
feed post.

An Instagram account connects one of two ways, and `chirpie_connect_instagram`
takes `via` to pick: `instagram` (the default) signs in with Instagram, and
`facebook` signs in with Facebook and connects the Instagram accounts linked to
the Pages the user shares, several at once. Both publish identically, whatever
the placement. The one difference is deleting a published post, which works on
an account connected via Facebook and is refused with
`501 delete_unsupported` on one connected through Instagram. Connecting an
account that is already connected through the other route moves it rather than
adding a second one: it keeps its id and everything it has published, and
deleting is the only thing that changes hands. Where the two routes report
different Instagram accounts you get a second account instead, so list the
accounts again afterwards.

## Drafts

`draft: true` on `chirpie_post` or `chirpie_thread` saves the content and sends
nothing: no platform call, no quota, and a draft never publishes on its own. A
draft is held to far less than a post, so the text may be empty and a draft
thread may be a single part, and the answer carries a `warnings` list saying,
per account, what would go wrong if it were sent as it stands.

Promote it with `chirpie_update_post`: `schedule_at` queues it, `publish: true`
sends it now, and the two are never valid together. Promotion runs every rule a
create runs and takes the quota, so anything refused leaves the draft exactly as
it was.

## Try it

Once connected, ask your agent:

- "Post to X and LinkedIn: we just shipped v2, but keep the X one shorter."
- "Draft a 5-post thread about why we moved off cron, and schedule it for 9am tomorrow."
- "How did my last Bluesky post do?"
- "Save that as a draft, I will pick the wording tomorrow."
- "Connect my X account."

## Kiro power

The root of this repository is also a Kiro power in the Agent Plugins format:
`plugin.json` names it and lists the keywords that activate it, and `mcp.json`
points at the hosted server, `https://chirpie.ai/mcp`. You sign in to Chirpie
in your browser the first time a tool runs, so there is no API key to paste.

## Links

- Docs: https://chirpie.ai/docs/mcp
- API reference: https://chirpie.ai/docs
- Dashboard: https://chirpie.ai/dashboard
- Privacy policy: https://chirpie.ai/privacy
- Terms of service: https://chirpie.ai/terms
- Support: https://chirpie.ai/support or support@chirpie.ai

MIT © Fireflo LLC

---

> This repository is an automatically maintained source mirror of `packages/mcp` in the Chirpie monorepo. Pull requests opened here cannot be merged.