Skip to main content

Connect AI Assistants via MCP

Playbook ships an official MCP (Model Context Protocol) server that lets AI assistants — Claude Code, Codex, Claude Desktop, Cursor, ChatGPT, and any other MCP-aware client — read and modify your Playbook workspace using natural language. Ask the assistant to "find every approved logo on the Brand board," "tag these screenshots as mobile-onboarding," or "upload this batch of URLs to the Marketing board" and it will call the right Playbook API for you.

The server is hosted at https://mcp.playbook.com/mcp — nothing to install and no token to create, copy, or paste. You connect it once, a Playbook consent screen opens in your browser, you click Allow, and the client holds an OAuth token from then on.

The server is built on top of the same v1 REST API documented in this site, so anything an MCP-connected agent can do, you can also do directly via HTTP — and vice versa.

How it works​

AI assistant ⇄ MCP client ⇄ Playbook MCP server ⇄ Playbook v1 REST API
  1. MCP client advertises a list of "tools" exposed by the Playbook MCP server.
  2. When the user asks a question, the assistant decides which tool to call, fills in the arguments, and the MCP client invokes the tool over JSON-RPC.
  3. The Playbook MCP server translates each tool call into one or more authenticated requests against the Playbook v1 REST API.
  4. The response is filtered (large/internal fields stripped) and returned to the assistant as text the model can reason about.

Plans and limits​

The MCP server is available on every plan, including Free — there is nothing to upgrade to connect it. Access follows Playbook's standard API rules, metered per organization:

  • Free — up to 1,000 API calls per month. Each MCP tool call is one or more API calls; when the monthly quota is used up, calls return an error until it resets.
  • Pro and up — higher monthly quotas (20,000 included on Pro) with metered overage.

You connect once in the browser and stay connected: the client holds a short-lived OAuth token that refreshes automatically, so the connection persists across sessions on any plan.

Claude Code​

The plugin ships the server configuration and five skills that teach Claude the common Playbook workflows, building and hosting an app on a board among them. If you installed it from Claude's directory on the web or desktop, it is already in Claude Code. Otherwise run these two commands inside Claude Code:

/plugin marketplace add playbook-labs/mcp-plugins
/plugin install playbook@playbook-plugins

Then run /mcp, pick playbook-creative, and choose Authenticate. Your browser opens the Playbook consent screen — click Allow and you're connected.

The same two steps work from your shell, without the interactive picker:

claude plugin marketplace add playbook-labs/mcp-plugins
claude plugin install playbook@playbook-plugins

Without the plugin​

One command, then approve in the browser:

claude mcp add --transport http playbook https://mcp.playbook.com/mcp

Run /mcp, pick playbook, choose Authenticate, and click Allow on the Playbook consent screen.

By default this registers the server for the current project. Pass --scope user to make it available in every project:

claude mcp add --transport http --scope user playbook https://mcp.playbook.com/mcp

Or add it by hand to .mcp.json at your project root, or to ~/.claude.json — note there is no headers block:

{
"mcpServers": {
"playbook": {
"type": "http",
"url": "https://mcp.playbook.com/mcp"
}
}
}

Claude on the web and desktop​

From the Claude directory​

Playbook is listed in Claude's connector directory. Open claude.ai/directory/playbook, connect Playbook there, and approve the Playbook consent screen. Nothing has to be pasted, and once it is connected Playbook is available in Claude on the web, in the desktop app, and on mobile.

The plugin is the connector plus the skills that teach Claude the common Playbook workflows. Install one or the other, not both.

Open the Playbook plugin in Claude's directory, sign in, and install it. Then connect it on the plugin's Connectors tab and approve the Playbook consent screen. A plugin installed this way also appears in Claude Code the next time a session starts.

The same plugin is also published from our repository, where updates arrive without waiting for directory review: open Customize > Plugins, choose Add, then Add marketplace, enter playbook-labs/mcp-plugins, and install Playbook from the list.

As a custom connector​

Open Customize > Connectors, choose Add custom connector, and paste https://mcp.playbook.com/mcp. Click Connect and approve. Leave the Advanced settings (OAuth client ID/secret) blank.

On Team and Enterprise plans an Owner adds the connector once for the organization, under Organization settings > Connectors; members then connect it from their own settings.

If you're on a client that only speaks stdio, bridge to the hosted server with mcp-remote, which runs the same browser sign-in:

{
"mcpServers": {
"playbook": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.playbook.com/mcp"]
}
}
}

Codex​

With the Playbook plugin​

The plugin adds the server and the same five skills. Two commands:

codex plugin marketplace add playbook-labs/mcp-plugins
codex plugin add playbook@playbook-plugins

Approve the Playbook consent screen when Codex opens it.

Without the plugin​

Two commands:

codex mcp add playbook --url https://mcp.playbook.com/mcp
codex mcp login playbook

codex mcp login opens the Playbook consent screen in your browser; click Allow. Confirm it took with:

codex mcp list

codex mcp add writes to ~/.codex/config.toml. The equivalent hand-written entry is:

[mcp_servers.playbook]
url = "https://mcp.playbook.com/mcp"

You still run codex mcp login playbook after editing the file by hand — the login stores the OAuth tokens, which never live in config.toml.

note

codex mcp add --url and codex mcp login require a recent Codex CLI. Check with codex --version, and upgrade if Codex rejects the --url flag.

Cursor​

One click: Add Playbook to Cursor — Cursor opens with the server pre-filled.

Or do it by hand: Settings → MCP → "Add new MCP server", or edit ~/.cursor/mcp.json directly. No auth header:

{
"mcpServers": {
"playbook": {
"url": "https://mcp.playbook.com/mcp"
}
}
}

Cursor shows the server as needing login — click Login (or Needs authentication) to open the Playbook consent screen.

VS Code​

One click: Add Playbook to VS Code — VS Code opens with the server pre-filled.

The same install from the command line:

code --add-mcp '{"name":"playbook","type":"http","url":"https://mcp.playbook.com/mcp"}'

VS Code prompts you to sign in when the server first starts; approve the Playbook consent screen.

ChatGPT​

Turn on developer mode first: Settings → Security and login → Developer mode. Then open chatgpt.com/plugins, select the plus button, and fill in:

  • URL: https://mcp.playbook.com/mcp
  • Authentication: OAuth — leave the client ID and secret blank, ChatGPT registers itself automatically

Connect it and approve the Playbook consent screen.

Authentication​

The MCP server is an OAuth 2.1 resource server. On the first request the client gets a 401 carrying a WWW-Authenticate challenge, discovers Playbook's authorization server, registers itself (RFC 7591 dynamic client registration), and runs an authorization-code flow with PKCE. All of that is automatic — the only thing you see is the consent screen.

What that means in practice:

  • No token to manage. Nothing to generate, paste into a config file, rotate, or accidentally commit.
  • The assistant acts as you. It sees exactly the workspaces, boards, and assets your Playbook account can see, and its writes are attributed to you.
  • Scopes are read and write. read covers browsing boards, assets, comments, and documentation; write covers uploads, moves, edits, deletes, comments, and board changes. The consent screen lists what it is asking for.
  • Revoke at any time from the Playbook app — revoking ends the assistant's access without touching your API tokens.

Static API tokens​

The MCP server also accepts a Playbook API token as a static Authorization: Bearer header. Use it where nobody can approve a consent screen — CI, scripts, and headless agents. For an assistant you use interactively, the browser sign-in above is simpler.

claude mcp add --transport http playbook https://mcp.playbook.com/mcp \
--header "Authorization: Bearer YOUR_TOKEN"

It is the same token that works against the v1 REST API; create one in the Playbook app.

Data handling​

  • The assistant sends the server only its tool calls: a tool name and its arguments. Your conversation is not sent.
  • The server passes each call to the Playbook v1 REST API as you and returns the result to the assistant.
  • Playbook records usage analytics for each tool call in PostHog, linked to your Playbook user: the tool name, how long it took, whether it failed, and its arguments with passwords, upload credentials, note text and descriptions removed. Tool results are not recorded.
  • Playbook's privacy policy applies.

Available tools​

All tools require the read scope. Tools marked write additionally require the write scope.

Every tool except list_organizations takes an organization (workspace slug), and it is optional: leave it out and the server resolves it from your token. Pass it when your account has more than one workspace — the server will not choose for you, it answers with the slugs to pick from.

Read tools​

ToolWhat it does
list_organizationsList the workspaces you have access to, with each one's remaining permalink quota.
list_membersList workspace members, or resolve a name to the token the uploader filters take.
list_boardsList boards in a workspace, with optional search and hierarchy depth.
get_boardFetch a single board's details by token.
list_board_childrenList the direct child boards of a parent.
list_board_descendantsList every board nested under a parent, at any depth, in one paginated call.
resolve_share_linkTurn a share URL of your workspace, or a board's own address in the app, into the board token behind it.
list_assetsList assets by board/subtree or uploader, with page or stable full-crawl cursor pagination. Takes fields to return only the columns you need.
get_assetFull details of one asset, including approval and upload status (see Async ingest semantics).
get_assetsFull details for up to 100 assets in one call — the batch form of get_asset. Reports unresolved tokens in not_found instead of failing.
list_group_childrenThe assets inside a group (a stack of variants, or a palette), paginated. Listings and searches return only top-level rows.
list_asset_versionsAn asset's version history, newest first, with the current head version number.
list_custom_fieldsThe workspace's option custom fields and their options, including the built-in Status field. Typed date/person/URL fields are not listed.
search_assetsKeyword search across filename / title / tags, filtered by uploader, status, or field value. Scopes to a board, or a board and its sub-boards.
ai_searchAI-powered visual and semantic search. Scopes to a board, or a board and its sub-boards.
get_commentsRead comments on an asset or board.
get_asset_permalinksRead assets' permanent public URLs, optionally rendered at a given width/height.
get_asset_previewsRender images at a size you choose and get a short-lived URL each — how an assistant actually looks at an asset (see Looking at assets).
get_asset_download_urlsA signed URL of each asset's original file — the uploaded bytes, not a render — valid about a day. Up to 25 assets a call; each counts as one API call.
list_documentationIndex the Playbook API docs and guides available to the assistant.
read_documentationRead a specific docs page (e.g. upload, webhooks, search). Lets the assistant ground answers in the official docs without hallucinating.

Write tools — assets​

ToolWhat it does
upload_from_url  writeIngest a single asset by public URL. Returns immediately with a skeleton; Playbook fetches the bytes asynchronously.
upload_from_urls  writeIngest up to 100 assets in one call by public URL — all assets land on the same board, asynchronously.
create_upload_url  writeStep 1 of 2 for bytes you already hold: a one-time storage address plus the exact request to make.
finish_upload  writeStep 2 of 2: turn bytes already sent to storage into an asset.
create_upload_urls  writeBatch form of create_upload_url (1–100 files); returns a batch_id and echoes each item's uuid.
finish_uploads  writeBatch form of finish_upload; pass the batch_id so the quota reservation is released.
create_note  writeAdd a note to a board — a text asset with optional background colour and card height (synchronous).
create_colors  writeAdd up to 100 colour swatches (hex or Pantone); two or more merge into a palette (synchronous).
group_assets  writeMerge assets into a group (variants, or a palette when every child is a colour).
ungroup_assets  writePull assets out of their group; emptying a group removes the group asset.
move_assets  writeBulk-move up to 1000 assets to a target board.
copy_assets  writeBulk-copy up to 1000 assets to a target board (async).
set_asset_approval  writeApprove or hide up to 1000 assets across boards, optionally scheduling when hidden assets become visible again.
change_asset_tags  writeAdd and/or remove tags on an asset.
update_asset_status  writeSet an asset's status (e.g. Approved, In Review).
update_asset  writeUpdate title, description, tags, status, or board for one asset.
create_asset_version  writeUpload a public URL as a new version of an existing asset, replacing its bytes. Needs versioning enabled.
revert_asset  writeRevert an asset to an earlier version_number (head moves forward). Needs versioning enabled.
edit_asset_version_comment  writeEdit the comment on an existing asset version. Needs versioning enabled.
delete_asset  writeSoft-delete an asset (recoverable from trash).
share_asset  writeCreate or return the shareable link for one asset.
retry_video_processing  writeStart an encode for a video whose stream_url is stuck at null, whether the last attempt failed, died on the way to the encoder, or was never made. Workspaces that encode on upload need it only for a failed or stalled encode; elsewhere it is how an encode is started — reading an asset through MCP never starts one. Call it once, not in a loop: it cannot tell a running encode from a dead one, so a second call while one is under way queues a second job.
add_asset_permalinks  writePublish assets at a permanent public URL. Plan-capped; over the cap the whole batch is refused.
remove_asset_permalinks  writeRevoke permalinks. A later re-add mints a different URL, and the published file stays fetchable until the public copy is purged.

Import tools​

ToolWhat it does
list_import_sourcesThe Google Drive and Dropbox connections your Playbook user made in the web app, each with its provider, plus the connect_url to make one. There is no tool that connects a service.
import_from_google_drive  writeImport up to 20 Drive folders (URLs or IDs, private folders included), each into a sub-board named after it, asynchronously. Re-importing into the same board skips unchanged files. Never bills unconsented storage overage — refuses or cancels instead.
import_from_dropbox  writeImport up to 20 Dropbox folders (address-bar URLs, paths or id: keys; not shared links), each into a sub-board named after it, asynchronously. Re-importing into the same board skips unchanged files. Same storage rules.
get_importAn import's status and file counts — poll until completed or canceled. See Import from Google Drive and Import from Dropbox.

Write tools — boards​

ToolWhat it does
create_board  writeCreate a new board, optionally nested under a parent.
update_board  writeUpdate a board's title, description, or parent.
delete_board  writeDelete a board and all of its contents.
share_board  writeCreate or update a share link, including expiry, download, and password controls.
publish_board  writeCreate or update a published page with the same optional controls, plus a design template. Without one, a board that is not live and has no design yet gets standard so it can be edited.

Published page design​

These edit the design of a board published with a template. Writes also need page layout API writes enabled for the workspace. See Published Page Design.

ToolWhat it does
get_page_elements_catalogTemplate ids, element type names, legal colours and typographies. Pass element_types to get the props of those types.
get_page_layoutThe stored page design, verbatim, with its version_token. slots: null is normal for an unedited page.
add_page_element  writeInsert an element into a slot or a section column.
update_page_element  writeReplace an element — the whole props object, not one field.
move_page_element  writeMove an element within or between slots, or into/out of a section.
delete_page_element  writeRemove an element. An id that is already gone answers converged: true.
reorder_page_slot  writeSet a slot's top-level order from its exact id list.
apply_page_operations  writeUp to 50 add/update/move/delete/reorder edits, all-or-nothing.
update_page_settings  writeSet or clear the page's background colour and typography.

Hosted apps​

A hosted app is a small public web app over one board that the assistant writes and Playbook hosts. These need hosted apps enabled for the workspace. See Hosted Apps.

ToolWhat it does
list_appsThe workspace's apps: slug, name, public address, the board each shows, and whether it is enabled.
deploy_app  writePut an app live, or replace the files of the app with the same slug. Takes the complete file set as text.
delete_app  writeTake an app offline and delete it.

Write tools — custom fields​

ToolWhat it does
create_custom_field  writeCreate a custom field with its options. A name that already exists replaces its option set.
delete_custom_field  writeDelete a custom field and its values.

Write tools — comments​

ToolWhat it does
create_comment  writePost a top-level comment on an asset or board.

Looking at assets​

An asset row carries display_url, the full-size render — 5000px wide is ordinary. It is the wrong thing to fetch just to see what an asset looks like, and too large for most vision models.

Ask get_asset_previews for a size instead (1024 wide is plenty). It renders images only — a video, PDF or note comes back as a URL that will not load — and the URLs die at the end of the next hour, so they are for looking now, never for storing.

When the URL has to keep working — a document, a page, a hand-off — publish the asset with add_asset_permalinks and read it back with get_asset_permalinks, which also takes a width and height. Permalinks are public to anyone holding the URL and capped per plan; list_organizations reports the remaining quota, and both permalink write tools return it after their writes.

Async ingest semantics​

The upload_from_url and upload_from_urls tools return immediately with skeleton assets — the asset rows exist but the bytes are still being fetched. The MCP response wraps each asset as { asset, status: "queued", note: "..." } to nudge the assistant against reporting the upload as "done" prematurely.

To detect completion, call get_asset on the returned token — or get_assets with all of them at once, which is one call per poll rather than one per asset for a batch of a hundred. The upload is finished when is_skeleton: false AND one of:

  • media_type populated → success
  • source_error non-null → failed (the message is the latest worker error)
  • is_link: true (only when as_link: true was passed) → kept as a bare link, no fetch attempted

See the Upload guide → Async Ingest Semantics for the same contract documented from the REST side, including recommended polling cadence.

Errors​

Tool errors are returned as MCP isError: true text content with a human-readable message. The server maps Playbook API errors as follows:

StatusTool message
401"Authentication failed" — sign in again from your client's MCP menu.
403"Permission denied — check your token's scopes (read/write)."
404The API's own message when it names the missing identifier ("Not found: Assets not found: abc123"); otherwise guidance to re-read the workspace slug and the board or asset token, and a note that retrying unchanged will fail the same way.
406"Invalid input: <message from the API>" (used by batch URL ingest validation).
409"Conflict: <message> (<code>; retryable=<bool>)" — the code tells conflicts apart, e.g. stale_document (re-read first) versus lock_wait_timeout (retry as-is).
422"Validation error: <message from the API>".
429From the Playbook API: "Rate limited: Rate limit of 120 requests per 60s exceeded. Retry in <n>s. (rate_limit_exceeded)" — wait the stated seconds. A 429 without that body (e.g. from a proxy): "Rate limited — too many requests. Wait up to a minute and try again."
5xx"Playbook API error: <status> <statusText>", followed by the API's message and code when the response carries them.

Credentials are never echoed back to the assistant, even when the upstream error body would contain one.