Integrations

BuildOnce MCP Server

BuildOnce provides a production-grade Model Context Protocol (MCP) server allowing AI agents like Claude to create, edit, organize, and render branded marketing templates directly from conversational chat interfaces.

Transport

Streamable HTTP

Modern POST streaming protocol

Authentication

OAuth 2.1 + PKCE

Dynamic client registration (RFC 7591)

Capabilities

31 MCP Tools

Templates, brand kit, render, assets, social

Server Endpoint URL
https://buildonce.app/v1/mcp
The MCP endpoint is OAuth-only. When connecting, your MCP client automatically discovers the OAuth endpoints and directs you to sign in and authorize the workspace on your behalf.
Guide

Connecting to Claude

BuildOnce integrates seamlessly with Claude via Claude.ai Custom Connectors or Claude Desktop.

Option A: Claude.ai Custom Connector

Connect BuildOnce directly inside Claude.ai web or mobile app (requires a Pro, Team, or Enterprise account):

1
Open your Claude.ai Account Settings (or Organization Admin Settings) and navigate to Connectors (or visit claude.ai/customize/connectors).
2
Click Add Custom Connector.
3
Enter the connector details:
  • Name: BuildOnce
  • Server URL: https://buildonce.app/v1/mcp
4
Click Connect. A pop-up window will open with BuildOnce's OAuth consent screen. Click Allow access to authorize Claude to interact with your workspace.

Claude Desktop uses the same Custom Connector flow as Claude.ai — open Settings → Connectors → Add custom connector inside the app and follow the same steps as above. BuildOnce's OAuth flow requires the connector UI; there is no supported hand-edited claude_desktop_config.json entry for it.

Try It Out in Claude

Once connected, ask Claude any of these prompts to test the integration:

Explore Library

"List all the templates in my BuildOnce workspace and show their tags and dimensions."

Apply Brand Kit

"Fetch my brand kit colors and fonts, and create a new 1080x1080 template for a Summer Sale."

Stock Photos

"Search for minimalist coffee shop photos on Unsplash to use in my new banner design."

Instant Render

"Render my latest template to a PNG and give me the download URL."

Developer Setup

Connecting Cursor & Other MCP Clients

Any MCP client supporting the 2024-11-05 / 2025-03-26 specification over HTTP can connect by specifying the server URL:

mcp.json
{
  "mcpServers": {
    "buildonce": {
      "url": "https://buildonce.app/v1/mcp"
    }
  }
}
Authentication

OAuth 2.1 Specification Details

BuildOnce adheres strictly to RFC 8414 (Authorization Server Metadata), RFC 9728 (OAuth 2.0 Protected Resource Metadata), and RFC 7591 (Dynamic Client Registration).

Authorization Server Metadata

https://buildonce.app/.well-known/oauth-authorization-server

Protected Resource Metadata

https://buildonce.app/.well-known/oauth-protected-resource

For full implementation details, visit the MCP OAuth API Reference.

Reference

All 31 Available Tools

Every tool is a first-class wrapper around BuildOnce services. Each tool contains declared annotations (readOnlyHint, destructiveHint, openWorldHint) compliant with Claude connector directory requirements.

Template Management

list_templates

List templates in the workspace with tags, description, dimensions, and per-page summaries.

ParamTypeNotes
searchstringOptional free-text search filter.
tagsstring[]Optional tag filter.
folderIdstringFilter by folder ID, or "root" for unfiled templates.
sortstringSort order for the results.
pagenumberPage number (defaults to 1).
limitnumberItems per page (1–100).
get_template

Fetch a single template's metadata by its ID.

ParamTypeNotes
id*stringTemplate public ID.
create_templatescope: template:write

Create a new template with one blank page of the given dimensions.

ParamTypeNotes
name*stringTemplate name (1–120 chars).
descriptionstringOptional description (up to 500 chars).
tagsstring[]Up to 20 search tags.
widthnumberPage width in pixels (1–20,000).
heightnumberPage height in pixels (1–20,000).
folderIdstringOptional folder ID to file directly into.
pagesobject[]Start with your own pages instead of one blank page (up to 100).
update_templatescope: template:write

Rename, re-describe, or update tags on an existing template.

ParamTypeNotes
id*stringTemplate public ID.
namestringNew template name.
descriptionstringNew description.
tagsstring[]New tags array.
duplicate_templatescope: template:write

Make a complete copy of a template and its current draft canvas.

ParamTypeNotes
id*stringSource template ID.
namestringOptional name for the duplicate copy.
list_template_folders

List all organization folders in the workspace, with template counts.

move_templatescope: template:write

Move a template into a folder, or back to root (unfiled).

ParamTypeNotes
id*stringTemplate ID.
folderIdstring | nullTarget folder ID, or null for root.

Canvas Drafts, Versions & Variables

get_template_draft

Fetch a template's full editable canvas design document (Fabric.js pages, objects, layers).

ParamTypeNotes
id*stringTemplate ID.
format"compact" | "full" | "outline""compact" (default) omits default-valued properties; "outline" returns a lightweight per-layer summary for finding what to patch.
pageIdsstring[]Read only these pages (up to 100). The result is marked partial.
layerIdsstring[]Read only these layers (up to 500). The result is marked partial.
fieldsstring[]Read only these layer properties (up to 50). id and type are always included.
save_template_draftscope: template:write

Replace a template's design document and automatically snapshot version history.

ParamTypeNotes
id*stringTemplate ID.
design*objectFull design JSON document ({ version, designName, pages }).
ifRevision*numberThe revision this save started from — fails with DRAFT_REVISION_CONFLICT if someone else saved since.
patch_template_draftscope: template:write

Edit part of a template's design without resending the whole document: change properties, add/remove/reorder layers, add/remove/resize pages.

ParamTypeNotes
id*stringTemplate ID.
ifRevision*numberThe revision this patch started from — fails with DRAFT_REVISION_CONFLICT if someone else saved since.
ops*object[]Patch operations (set, remove, add, move, set_page, add_page, remove_page), applied in order, up to 200. set on a layer can carry animation fields, and set_page a page's duration and transition.
dryRunbooleanValidate and report the result without saving.
list_template_versions

List the 10 most recent version snapshots of a template.

ParamTypeNotes
id*stringTemplate ID.
get_template_version

Fetch an earlier version's design document to inspect before restoring.

ParamTypeNotes
id*stringTemplate ID.
versionId*stringVersion ID.
restore_template_versionscope: template:write

Roll back a template to an earlier snapshot (creates an undo snapshot of the current state).

ParamTypeNotes
id*stringTemplate ID.
versionId*stringVersion ID to restore.
ifRevisionnumberFail with DRAFT_REVISION_CONFLICT instead of replacing edits made since this revision.
list_template_parameters

List dynamic variable fields (text placeholders, image overrides) derived from canvas layers.

ParamTypeNotes
id*stringTemplate ID.

Rendering & Output

render_templatescope: render:write

Render a template draft to PNG, JPEG or PDF, or the whole design as an animated MP4, WebM or GIF video, optionally applying variable modifications. A video costs 1 credit per started second (up to 60 s).

ParamTypeNotes
id*stringTemplate ID.
format"png" | "jpeg" | "pdf" | "mp4" | "webm" | "gif"Output file format (defaults to png). A video format renders every page as one video; if it is still rendering after about 20 seconds, the result is { renderId, status } — poll get_render.
modificationsRecord<string, string>Key-value variable overrides.
pageIdstringSpecific page ID to render.
allPagesbooleanRender every page in the template.
previewbooleanFree watermarked preview with per-layer layout info — check your work before a real render.
pageIdsstring[]Preview only — restrict to these pages (up to 12).
inline"none" | "thumbnail" | "full"How many page thumbnails to embed in the result (defaults to "thumbnail", the first 3 pages).
video{ fps?, scale?, quality? }Video only. fps 1–60 (GIF up to 15), scale 0.5 | 1 | 2, quality "small" | "standard" | "high".
atnumber[]Preview only — up to 12 moments, in seconds: a free sheet of the video's frames at those times, with the video's duration and price.
animation{ pages?, layers? }Change timing and animation for this render or preview only — different cuts of one template. Same shape as the render API's animation field.
get_renderscope: render:write

A render by renderId: status (queued, processing, succeeded or failed), its files and credits. Use it to wait for a video render_template returned as queued.

ParamTypeNotes
renderId*stringThe renderId from render_template.

Brand Kit & Stock Imagery

get_design_guide

The design guides. By default, the canvas guide: how a page.json is built — layer fields, text, images, shapes, variable bindings and limits. With topic: "animation", how to animate layers and pages for video: enter and exit presets, ambient motion, text reveals, page timing and transitions.

get_brand_kit

Fetch the workspace brand kit: logos (primary and dark-mode), brand fonts, color palette, and tone guidelines.

upload_assetscope: asset:write

Add a file to the workspace's media library and get back its id and a hosted URL. Used to fill the brand kit or add an image to a design from a brand brief.

ParamTypeNotes
kind*"image" | "font" | "icon"What kind of file is being uploaded.
urlstringA public http(s) URL for the server to download — pass this or base64, not both.
base64stringThe file's bytes as base64 (bare or a data: URL) — pass this or url, not both.
filenamestringName for the stored file; for a font, also sets its font family.
update_brand_kitscope: asset:write

Save the workspace's brand: colors, logos, fonts and brand guidelines. Only the fields passed change. Requires the workspace admin role.

ParamTypeNotes
colorsobject[]Replaces the whole palette: { name, hex, role } entries.
primaryLogoAssetIdstring | nullAsset ID from upload_asset; null clears the logo.
reversedLogoAssetIdstring | nullLogo for dark backgrounds; null clears it.
fontAssetIdsstring[]Replaces the whole list of brand font asset IDs.
styleGuidestringFreeform brand voice/guidelines text (up to 20,000 chars); "" clears it.
search_stock_photos

Search royalty-free stock photography from Pexels and Unsplash to inject into designs.

ParamTypeNotes
querystringSearch terms (e.g., "minimalist workspace").
provider"pexels" | "unsplash"Filter by provider or omit for all.
pagenumberPage number (defaults to 1).
perPagenumberResults per page (1–80).

Social Publishing

Render a design and post it in the same conversation. Accounts are connected on the dashboard's Social page; these tools post to the accounts already connected to the workspace. A post goes to a real account, so the agent confirms the account, text and media with you first.

get_platform_requirementsscope: social:read

Each platform's rules — character limit, required media, image or video, formats, which fields apply, platformOptions and delete support — from the same table posts are checked against.

ParamTypeNotes
platformstringOne platform, or omit for all.
list_social_accountsscope: social:read

List the social accounts connected to the workspace, with each one's platform, name and whether it needs reconnecting.

list_social_postsscope: social:read

List the workspace's posts, newest first, in every status — check whether a scheduled post went out or why one failed.

ParamTypeNotes
status / platform / accountIdstringFilters: status (scheduled, publishing, published, failed, canceled, deleted), platform, or one account.
from / tostringISO 8601 dates bounding when the post was created.
pagenumberPage number (defaults to 1).
limitnumberPosts per page (1–100).
schedule_social_postscope: social:write

Schedule a post on one connected account; it publishes by itself at the scheduled time.

ParamTypeNotes
accountId*stringAccount ID from list_social_accounts.
content*stringPost text (up to 3,000 characters).
mediaUrlsstring[]Up to 9 public image/video URLs — a render_template URL works as is.
linkUrlstringLink to attach.
title / description / tagsstring / string / string[]LinkedIn and YouTube only.
accountIdsstring[]Post to several accounts at once instead of accountId — one result per account.
platformOptionsobjectPer platform: instagram.postType (feed, story, reel), youtube.privacy / categoryId, pinterest.boardId, x.replyToPostId.
idempotencyKeystringSending the same key again returns the original post instead of posting twice.
dryRunbooleanCheck the post against the platform's rules and return valid, errors and warnings — nothing is created or posted.
scheduledAt*stringISO 8601 with a timezone, e.g. "2026-10-08T09:00:00+05:00". Must be in the future.
publish_social_postscope: social:write

Publish a post on one connected account right now. Returns published, or failed with the reason.

ParamTypeNotes
accountId*stringAccount ID from list_social_accounts.
content*stringPost text (up to 3,000 characters).
mediaUrlsstring[]Up to 9 public image/video URLs — a render_template URL works as is.
linkUrlstringLink to attach.
title / description / tagsstring / string / string[]LinkedIn and YouTube only.
accountIdsstring[]Post to several accounts at once instead of accountId — one result per account.
platformOptionsobjectPer platform: instagram.postType (feed, story, reel), youtube.privacy / categoryId, pinterest.boardId, x.replyToPostId.
idempotencyKeystringSending the same key again returns the original post instead of posting twice.
dryRunbooleanCheck the post against the platform's rules and return valid, errors and warnings — nothing is created or posted.
get_social_postscope: social:read

One post by ID, in full — status, lastError, externalPostId, publishedAt. Poll it after publishing a video.

ParamTypeNotes
postId*stringPost ID.
update_scheduled_postscope: social:write

Change a scheduled post's text, media, link or time, keeping the same ID. Checked like a new post.

ParamTypeNotes
postId*stringA post that is still scheduled.
content / mediaUrls / linkUrl / scheduledAt …optionalOnly the fields that change.
retry_social_postscope: social:write

Publish a failed post again as the same post. Refused with RETRY_UNSAFE when the first attempt may already be live (it timed out or was interrupted).

ParamTypeNotes
postId*stringA post with status failed.
delete_social_postscope: social:write

Remove a published post from its platform. Works on X, Facebook, LinkedIn, Pinterest, Discord and Bluesky; Instagram, TikTok, Threads and YouTube return unsupported_by_platform with the reason.

ParamTypeNotes
postId*stringA published post.
confirm*trueRequired — deleting is permanent.
cancel_social_postscope: social:write

Cancel a scheduled post before it goes out. A post already sent can't be canceled.

ParamTypeNotes
postId*stringPost ID from schedule_social_post or list_social_posts.

Was this page helpful?