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 — 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.
Claude Code
With the Playbook plugin (recommended)
The plugin ships the server configuration, so there is nothing to type but the two commands. Run them inside Claude Code:
/plugin marketplace add playbook-labs/claude-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/claude-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
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
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"
}
}
}
Codex
Codex has no plugin system, so connect the server directly. 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/"
}
}
}
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"}'
VS Code prompts you to sign in when the server first starts; approve the Playbook consent screen.
ChatGPT
Settings → Connectors → "Add custom connector":
- URL:
https://mcp.playbook.com - Authentication: OAuth — leave the client ID and secret blank, ChatGPT registers itself automatically
Click Connect on the connector and approve the Playbook consent screen.
Claude Desktop
Settings → Connectors → "Add custom connector" → paste https://mcp.playbook.com, then click Connect and approve. Leave the Advanced settings (OAuth client ID/secret) blank.
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"]
}
}
}
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: deprecated, removed 2026-09-30
Pasting a Playbook API token as a static Authorization: Bearer header against mcp.playbook.com still works and is deprecated. Those responses carry Deprecation and Sunset headers.
# Deprecated — use the browser sign-in above instead.
claude mcp add --transport http playbook https://mcp.playbook.com \
--header "Authorization: Bearer YOUR_TOKEN"
On 2026-09-30 the MCP server stops accepting that form of authentication and answers 401 with the OAuth challenge instead; a client recovers by running the sign-in above. To be precise about the scope of that change:
- Your API token is not revoked. It keeps working against the v1 REST API — scripts, CI, and existing integrations are unaffected.
- Only the static-header path at
mcp.playbook.comgoes away.
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_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_asset_versions | An asset's version history, newest first, with the current head version number. |
list_custom_fields | The workspace's custom fields and their options, including the built-in Status field. |
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). |
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. Not needed for the normal path — reading the asset is what starts an encode. 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. |
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. |
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). |
| 422 | "Validation error: <message from the API>". |
| 429 | "Rate limited — too many requests. Wait a moment and try again." |
| 5xx | "Playbook API error: <status> <statusText>". |
Credentials are never echoed back to the assistant, even when the upstream error body would contain one.