# Post Ripple MCP server — setup and tool reference

> Post Ripple is a short-form social platform: create videos, photo
> carousels, and text posts, then schedule and publish them to TikTok,
> Instagram Reels, YouTube Shorts, and X. This MCP server gives an AI agent
> the same abilities through scoped API keys. 59 tools: 26 `read`, 25 `content:write`, 8 `publish`.

- Package: `@post-ripple/mcp@latest`
- Transport: local stdio (nothing to host, no OAuth, no remote endpoint)
- API base: `https://api.postripple.app` (override with `POSTRIPPLE_API_URL`)
- Auth: `POSTRIPPLE_API_KEY` environment variable
- Human-readable version of this page: https://postripple.app/docs

## Setup

1. **Create an API key** — In Post Ripple, open Settings → API Keys and create one. Pick its scopes: `read`, `content:write`, and `publish`. `publish` is unchecked by default — leave it off until you want the agent reaching real social accounts. The key is shown once.
2. **Register the server with your client** — The server is a local stdio process launched with `npx -y @post-ripple/mcp@latest`, and it reads the key from the `POSTRIPPLE_API_KEY` environment variable. There is nothing to host and no OAuth flow. Snippets for each client are below.
3. **Verify it works** — Restart the client and call `whoami`. It returns the member the key acts as, its scopes, and every organization it can work in. The call appears in the audit log on the same API Keys page.

## Scopes

An API key carries any combination of three scopes. Pick the narrowest set that
does the job.

- `read` — List content, posts, accounts, and analytics. Everything an agent needs to answer questions about the workspace. Nothing it can call changes state.
- `content:write` — Create and organize videos, groups, and content. Creates content in your libraries. It can't put a post on an account or wire a rotation to one — that needs publish. It isn't inert, though: adding videos to a rotation that a publish-scoped key (or a human) already wired up re-rolls which videos that rotation will publish, and when.
- `publish` — Schedule and cancel posts to connected social accounts, and manage rotation-group schedules. Required for schedule_post, publish_slideshow, publish_images, create_text_post, anything that edits a queued post, and update_group_schedule — which hands an account a rotation queue that publishes on its own. Unchecked by default when you create a key; opt in deliberately.

## Client configuration

### Claude Code

```sh
claude mcp add postripple \
  -e POSTRIPPLE_API_KEY=pr_... \
  -- npx -y @post-ripple/mcp@latest
```

Run it, then restart Claude Code.

### Claude Desktop

`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "postripple": {
      "command": "npx",
      "args": ["-y", "@post-ripple/mcp@latest"],
      "env": { "POSTRIPPLE_API_KEY": "pr_..." }
    }
  }
}
```

Merge into the config, then quit and reopen the app.

### Cursor

`.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "postripple": {
      "command": "npx",
      "args": ["-y", "@post-ripple/mcp@latest"],
      "env": { "POSTRIPPLE_API_KEY": "pr_..." }
    }
  }
}
```

Project-local file, same shape. Reload the window.

### Codex

`~/.codex/config.toml`:

```toml
[mcp_servers.postripple]
command = "npx"
args = ["-y", "@post-ripple/mcp@latest"]
env = { POSTRIPPLE_API_KEY = "pr_..." }
```

Add the block, then restart Codex.

### opencode

`opencode.json`:

```json
{
  "mcp": {
    "postripple": {
      "type": "local",
      "command": [
        "npx", "-y", "@post-ripple/mcp@latest"
      ],
      "environment": {
        "POSTRIPPLE_API_KEY": "pr_..."
      }
    }
  }
}
```

Merge into opencode.json, then restart opencode.

### Any MCP client

```yaml
command: npx -y @post-ripple/mcp@latest
env:     POSTRIPPLE_API_KEY=pr_...
```

Register a local stdio server with this command and env.

## Tools

59 tools: 26 `read`, 25 `content:write`, 8 `publish`.

| Tool | Scope | What it does |
| --- | --- | --- |
| `whoami` | read | Who the key acts as, which organizations it can work in, and its scopes — plus the selected workspace's overview. Call it first to orient. |
| `list_social_accounts` | read | Connected TikTok / Instagram / YouTube / X / LinkedIn accounts with connection health: status, token expiry, and last error. X accounts include their xPremium character-limit flag. |
| `list_videos` | read | The video library, newest first. Videos with status 'completed' are publishable; 'generating' clips are still rendering. |
| `get_video` | read | One library video in detail — status, signed URLs, duration, and generation provenance. Poll it for generate_video jobs. |
| `list_video_groups` | read | Video groups — shuffle rotations that pre-schedule a visible queue of posts — with video/account counts and status. |
| `get_video_group` | read | One group in detail: its videos and the per-account posting rules, next scheduled post, and current queue depth. |
| `list_images` | read | List or hybrid-semantic-search the workspace image library. Check here before generating or re-uploading — reuse is free and instant. |
| `list_characters` | read | Saved characters — reusable named subjects used to generate on-model images that look like the same person across scenes. |
| `list_hooks` | read | The shared hook video library — short vertical clips meant to open a short-form video. Shared platform-wide, not per-workspace. |
| `list_green_screens` | read | The shared green screen clip library — people cut out on green, composited over a background by create_video. |
| `list_backgrounds` | read | The shared background image library used behind green screen memes. |
| `list_music` | read | The platform music library — background tracks you can lay over a hook + demo video. |
| `get_creation` | read | Render status of a create_video job. Poll until 'completed', then publish the returned resultVideoId. |
| `list_slideshows` | read | Photo-carousel slideshows with status ('draft' or 'ready') and a signed cover thumbnail. |
| `list_slideshow_templates` | read | Slideshow layout templates: canvas size, each text slot's exact geometry, defaults, fonts, and treatments. |
| `get_slideshow` | read | One slideshow in full detail — per-slide render state, every text field's style overrides, and signed image URLs. |
| `list_posts` | read | Posts across every status: review drafts, rejected, scheduled, publishing, published, failed, and canceled. |
| `list_reviews` | read | Posts waiting for team review, with approval status, reviewer notes, target account, and planned publish time. |
| `get_post_metrics` | read | Engagement for one published post: the latest views/likes/comments/shares snapshot plus the scraped time series. |
| `get_account_metrics` | read | Follower and profile growth history (daily snapshots) for one connected account, or every account at once. |
| `get_engagement_summary` | read | Engagement overview for the last N days: totals, per-platform breakdown, top posts, and a per-account breakdown. |
| `list_inspirations` | read | Saved inspirations — external posts Post Ripple auto-analyzes into a reusable recreation recipe. |
| `get_inspiration` | read | One inspiration in full detail, including the complete AI deconstruction: hook, shots, subjects, audio, and a recreation brief. |
| `list_post_templates` | read | This workspace's brand post formats — saved house styles for a recurring multi-slide post — plus the starters available to clone. Returns each format's palette, standing text, named series with their next issue number, and its own editable layouts. |
| `list_tracked_accounts` | read | Tracked external accounts this workspace polls, with status, followers, median views, and last poll time. |
| `list_tracked_posts` | read | The 'what's working for competitors' feed — recent posts from tracked accounts, ranked by outlier score or recency. |
| `import_video_from_url` | content:write | Import a video into the library from a public URL. The download is asynchronous — poll list_videos until 'completed'. |
| `get_video_upload_url` | content:write | Get a presigned upload URL for pushing a local video file into the library. |
| `register_uploaded_video` | content:write | Register a video after PUTting its bytes to a presigned URL. The video becomes immediately publishable. |
| `create_video_group` | content:write | Create a video group (a shuffle rotation). Uses one 'groups' credit from the plan. |
| `add_videos_to_group` | content:write | Add up to 100 library videos to a group's rotation, reporting which were added and which were skipped. |
| `get_image_upload_url` | content:write | Get a presigned upload URL for pushing an image into the library. JPEG at 1080×1350 strongly recommended. |
| `register_uploaded_image` | content:write | Register an uploaded image into the workspace library with a title and tags, so it's findable and reusable later. |
| `import_image_from_url` | content:write | Import an image from a public URL — synchronous, so the returned imageId is immediately usable in create_slideshow. |
| `generate_character_image` | content:write | Generate a new AI image and save it to the library, optionally rendering a saved character on-model. Synchronous, ~10–30s. |
| `generate_video` | content:write | Generate a new ~5s vertical AI clip from a prompt, character, or reference image. Asynchronous (~30–60s) — poll get_video. |
| `save_inspiration` | content:write | Save an external post URL as an inspiration. Kicks off an async scrape → download → deconstruction pipeline. |
| `track_account` | content:write | Start tracking an external public account so its recent posts land in the 'what's working' feed. Up to 10 per workspace. |
| `untrack_account` | content:write | Stop tracking an account and delete its polled posts. Inspirations you already saved from it survive. |
| `save_tracked_post_as_inspiration` | content:write | Save a tracked post into the inspirations library so it gets deconstructed and becomes recreatable. |
| `recreate_inspiration` | content:write | Recreate a 'ready' inspiration as your own draft — 'person_swap' (Wan or Kling), 'video', or 'slideshow'. Nothing is published. |
| `replace_person_in_video` | content:write | Swap the person in any completed library video for a saved character (Wan scene-match or Kling motion-control). Async, ~5–10 min. |
| `update_image` | content:write | Update a library image's title, description, or tags — usually to make an older image easier to rediscover. |
| `delete_image` | content:write | Delete a library image and its stored file. Images still in use are reported back instead, unless you force it. |
| `create_slideshow` | content:write | Create a photo slideshow of 1–10 slides from library images, pre-rendered files, or template slides rendered server-side. |
| `create_video` | content:write | Render a 9:16 video from library ingredients — 'text_over_video' (timed text beats over your own clip), 'hook_demo', or 'green_screen_meme'. Asynchronous — poll get_creation. |
| `clone_post_template` | content:write | Create a brand post format for this workspace by cloning a starter. The starter's slide layouts are copied onto it, so the workspace owns and can edit every one. |
| `update_post_template` | content:write | Change a brand format's name, palette, standing text, slide plan, series, or caption footer. Only the fields you pass change; a palette missing a token its layouts reference is rejected. |
| `upsert_slide_layout` | content:write | Create or replace one of a brand format's own slide layouts — slot geometry, type, photo frame, and rules — as data. Same shape the in-app layout editor writes. |
| `delete_slide_layout` | content:write | Remove one of a brand format's layouts. Refused while a slide plan still names it. |
| `create_from_template` | content:write | Build a full multi-slide post in a brand format: pass the photos and only the copy that changes. The series eyebrow and issue number, slide counters, wordmark, footers, and each slide's layout come from the format. |
| `schedule_post` | publish | Schedule a completed library video to publish on a connected account at a future time. Always pass idempotencyKey. |
| `reschedule_post` | publish | Move a still-scheduled post to a new future time. Fails once publishing has started. |
| `swap_post_video` | publish | Replace the video on a still-scheduled video post with any completed library video. |
| `publish_slideshow` | publish | Publish or schedule a ready slideshow to one or more Instagram/TikTok/X/LinkedIn accounts as a native carousel, photo, or image post. X takes at most 4 slides; LinkedIn up to 20. |
| `publish_images` | publish | Publish or schedule library images to one or more Instagram/TikTok/X/LinkedIn accounts as a native carousel, photo, or image post. X takes at most 4 images. |
| `create_text_post` | publish | Publish or schedule a post to one or more connected X or LinkedIn accounts — text, optionally with attached library images (X takes up to 4, LinkedIn up to 10). X allows 280 characters (25,000 with X Premium); LinkedIn allows 3,000. |
| `cancel_post` | publish | Cancel a still-scheduled post and refund its credit. Fails once publishing has started. |
| `update_group_schedule` | publish | Attach a social account to a rotation group or update its posting rules: posts per day, active/paused, and posting windows. The pair then auto-publishes on that cadence. |

## Notes for agents

- Call `whoami` first. Keys are personal, not organization-bound: one key works in every organization its creator belongs to unless it was restricted at creation. Pass `organizationId` per call, or set `POSTRIPPLE_ORG` to pin a default (handy for one brand per repo).
- Anything outside a key's scopes fails with `insufficient_scope`; it does not partially run.
- `schedule_post`, `publish_slideshow`, `publish_images`, and `create_text_post` publish to **real** accounts. Always pass `idempotencyKey` — a retry with the same key resolves to the same post instead of creating a second one. Pass `tiktokSettings` if a TikTok post should be public; the default is private (`SELF_ONLY`).
- X posts are limited to 280 characters (25,000 on accounts whose `xPremium` flag is true in `list_social_accounts`) and at most 4 images per post. Over-limit text fails validation up front, before anything publishes.
- TikTok `settings.postMode: "inbox"` sends a photo post to the account's TikTok drafts inbox instead of publishing it, which is what you want when a human finishes posts from a real device.
- If the workspace requires approval, publish calls create in-review items and return `submittedForReview: true` instead of scheduling. Inspect them with `list_reviews`; an owner or admin approves, rejects, or requests changes from the Review page.
- `update_group_schedule` needs `publish`: attaching a group to an account hands that account a queue that publishes on its own cadence, with no per-post confirmation. `add_videos_to_group` only needs `content:write`, but it re-rolls an existing rotation's queue — machine-placed `scheduled` slots are deleted and re-materialized (slots a human moved are kept), so it changes which videos publish and when. Workspaces with approval enabled can't run rotation groups at all; attaching one errors until approval is turned off in Team settings.
- Imports, renders, and generations are asynchronous. Poll the matching `get_*`/`list_*` tool until the status settles rather than assuming success.
- Prefer a brand post format over `create_slideshow` when one exists for the brand. `list_post_templates` shows them; `create_from_template` fills one, keeping series numbering, the wordmark, slide counters, and footers consistent across every post.
- Every authenticated call is audit-logged and attributed to the member who created the key. Agent API access is included on every paid plan.

## Common flows

**Publish a photo carousel.** `import_image_from_url` (or
`get_image_upload_url` then PUT the bytes, then `register_uploaded_image`)
for each image → `create_slideshow` → poll `get_slideshow` until
`ready` (template slides render server-side) → `publish_slideshow`.
Pre-rendered JPEG slideshows are ready immediately.

**Publish a carousel in a saved house style.** `list_post_templates` to find
the brand format and the series → one `create_from_template` call with the
photos and the copy that changes → poll `get_slideshow` until `ready` →
`publish_slideshow`. The series eyebrow and issue number, slide counters,
wordmark, and footers come from the format.

**Post to X or LinkedIn.** `list_social_accounts` for the accountId (X
accounts carry an `xPremium` flag — 280 characters without it, 25,000 with
it; LinkedIn allows 3,000) → `create_text_post` with the text and targets,
plus optional `imageIds` from `list_images` (attached in order; X takes up
to 4) and `scheduledFor` to schedule instead of posting immediately.

**Render a video.** `create_video` with `text_over_video`, `hook_demo`,
or `green_screen_meme` → poll `get_creation` until `completed` →
`schedule_post`.

**Generate new footage.** `generate_video` (optionally with a saved
character from `list_characters`) → poll `get_video` → `schedule_post`.

## More

- Tool reference, rendered: https://postripple.app/docs/tools
- HTTP API (same tools, no MCP client): https://postripple.app/docs/api
- Worked end-to-end examples: https://postripple.app/workflows
- Plans and limits: https://postripple.app/pricing
