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
- MCP client advertises a list of "tools" exposed by the Playbook MCP server.
- 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.
- The Playbook MCP server translates each tool call into one or more authenticated requests against the Playbook v1 REST API.
- 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
With the Playbook plugin (recommended)
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.
With the Playbook plugin (recommended)
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.
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
readandwrite.readcovers browsing boards, assets, comments, and documentation;writecovers 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
| Tool | What it does |
|---|---|
list_organizations | List the workspaces you have access to, with each one's remaining permalink quota. |
list_members | List workspace members, or resolve a name to the token the uploader filters take. |
list_boards | List boards in a workspace, with optional search and hierarchy depth. |
get_board | Fetch a single board's details by token. |
list_board_children | List the direct child boards of a parent. |
list_board_descendants | List every board nested under a parent, at any depth, in one paginated call. |
resolve_share_link | Turn a share URL of your workspace, or a board's own address in the app, into the board token behind it. |
list_assets | List assets by board/subtree or uploader, with page or stable full-crawl cursor pagination. Takes fields to return only the columns you need. |
get_asset | Full details of one asset, including approval and upload status (see Async ingest semantics). |
get_assets | Full 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_children | The assets inside a group (a stack of variants, or a palette), paginated. Listings and searches return only top-level rows. |
list_asset_versions | An asset's version history, newest first, with the current head version number. |
list_custom_fields | The workspace's option custom fields and their options, including the built-in Status field. Typed date/person/URL fields are not listed. |
search_assets | Keyword search across filename / title / tags, filtered by uploader, status, or field value. Scopes to a board, or a board and its sub-boards. |
ai_search | AI-powered visual and semantic search. Scopes to a board, or a board and its sub-boards. |
get_comments | Read comments on an asset or board. |
get_asset_permalinks | Read assets' permanent public URLs, optionally rendered at a given width/height. |
get_asset_previews | Render 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_urls | A 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_documentation | Index the Playbook API docs and guides available to the assistant. |
read_documentation | Read a specific docs page (e.g. upload, webhooks, search). Lets the assistant ground answers in the official docs without hallucinating. |
Write tools — assets
| Tool | What it does |
|---|---|
upload_from_url write | Ingest a single asset by public URL. Returns immediately with a skeleton; Playbook fetches the bytes asynchronously. |
upload_from_urls write | Ingest up to 100 assets in one call by public URL — all assets land on the same board, asynchronously. |
create_upload_url write | Step 1 of 2 for bytes you already hold: a one-time storage address plus the exact request to make. |
finish_upload write | Step 2 of 2: turn bytes already sent to storage into an asset. |
create_upload_urls write | Batch form of create_upload_url (1–100 files); returns a batch_id and echoes each item's uuid. |
finish_uploads write | Batch form of finish_upload; pass the batch_id so the quota reservation is released. |
create_note write | Add a note to a board — a text asset with optional background colour and card height (synchronous). |
create_colors write | Add up to 100 colour swatches (hex or Pantone); two or more merge into a palette (synchronous). |
group_assets write | Merge assets into a group (variants, or a palette when every child is a colour). |
ungroup_assets write | Pull assets out of their group; emptying a group removes the group asset. |
move_assets write | Bulk-move up to 1000 assets to a target board. |
copy_assets write | Bulk-copy up to 1000 assets to a target board (async). |
set_asset_approval write | Approve or hide up to 1000 assets across boards, optionally scheduling when hidden assets become visible again. |
change_asset_tags write | Add and/or remove tags on an asset. |
update_asset_status write | Set an asset's status (e.g. Approved, In Review). |
update_asset write | Update title, description, tags, status, or board for one asset. |
create_asset_version write | Upload a public URL as a new version of an existing asset, replacing its bytes. Needs versioning enabled. |
revert_asset write | Revert an asset to an earlier version_number (head moves forward). Needs versioning enabled. |
edit_asset_version_comment write | Edit the comment on an existing asset version. Needs versioning enabled. |
delete_asset write | Soft-delete an asset (recoverable from trash). |
share_asset write | Create or return the shareable link for one asset. |
retry_video_processing write | Start 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 write | Publish assets at a permanent public URL. Plan-capped; over the cap the whole batch is refused. |
remove_asset_permalinks write | Revoke permalinks. A later re-add mints a different URL, and the published file stays fetchable until the public copy is purged. |
Import tools
| Tool | What it does |
|---|---|
list_import_sources | The 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 write | Import 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 write | Import 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_import | An import's status and file counts — poll until completed or canceled. See Import from Google Drive and Import from Dropbox. |
Write tools — boards
| Tool | What it does |
|---|---|
create_board write | Create a new board, optionally nested under a parent. |
update_board write | Update a board's title, description, or parent. |
delete_board write | Delete a board and all of its contents. |
share_board write | Create or update a share link, including expiry, download, and password controls. |
publish_board write | Create 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.
| Tool | What it does |
|---|---|
get_page_elements_catalog | Template ids, element type names, legal colours and typographies. Pass element_types to get the props of those types. |
get_page_layout | The stored page design, verbatim, with its version_token. slots: null is normal for an unedited page. |
add_page_element write | Insert an element into a slot or a section column. |
update_page_element write | Replace an element — the whole props object, not one field. |
move_page_element write | Move an element within or between slots, or into/out of a section. |
delete_page_element write | Remove an element. An id that is already gone answers converged: true. |
reorder_page_slot write | Set a slot's top-level order from its exact id list. |
apply_page_operations write | Up to 50 add/update/move/delete/reorder edits, all-or-nothing. |
update_page_settings write | Set 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.
| Tool | What it does |
|---|---|
list_apps | The workspace's apps: slug, name, public address, the board each shows, and whether it is enabled. |
deploy_app write | Put an app live, or replace the files of the app with the same slug. Takes the complete file set as text. |
delete_app write | Take an app offline and delete it. |
Write tools — custom fields
| Tool | What it does |
|---|---|
create_custom_field write | Create a custom field with its options. A name that already exists replaces its option set. |
delete_custom_field write | Delete a custom field and its values. |
Write tools — comments
| Tool | What it does |
|---|---|
create_comment write | Post 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_typepopulated → successsource_errornon-null → failed (the message is the latest worker error)is_link: true(only whenas_link: truewas 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:
| Status | Tool message |
|---|---|
| 401 | "Authentication failed" — sign in again from your client's MCP menu. |
| 403 | "Permission denied — check your token's scopes (read/write)." |
| 404 | The 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>". |
| 429 | From 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.