Docs

MCP server

The agentappbuilder MCP server: endpoint, authentication, protocol support, error codes, and every tool with its arguments and results.

Endpoint

https://app.agentappbuilder.com/mcp

The server is stateless and speaks JSON over HTTP POST, one JSON-RPC message per request. There is no session and no event stream: a GET returns 405.

Add it to Claude Code

claude mcp add --transport http --scope local agentappbuilder https://app.agentappbuilder.com/mcp --header "Authorization: Bearer <key>"

You run this command yourself, in your project’s terminal: the app shows it when you create a key. When your agent creates a project, it does not add the server: it uses the HTTP API, which gives the same tools, for the whole session, and at the end gives you a command to run if you want the MCP server in later sessions (see Getting started). Claude Code loads a new MCP server at its next start: claude --continue restarts it and keeps the conversation.

Connect with your account

No key needed: add the server once and sign in with your agentappbuilder account. Your agent then lists your projects, creates new ones in your first organization (they are ready on the canvas, with no claim link) and works on any of them.

  • Claude Desktop and claude.ai: Settings, Connectors, Add custom connector, then the endpoint https://app.agentappbuilder.com/mcp.
  • Claude Code: claude mcp add --transport http agentappbuilder https://app.agentappbuilder.com/mcp, then /mcp to sign in.

A page of agentappbuilder opens: sign in with your email code, then select Allow. Connected this way, the server adds two tools, list_projects and create_project (with an optional organization, the slug of another organization), and every other tool takes a project argument: the project’s 8-character id from list_projects or create_project, or its canvas URL. renew_claim_link is not offered, since your projects are never pending.

Each project your agent works on this way gets a key named Claude connector in Settings, Keys: revoking it closes that project to the connector. To remove the connection from your whole account, select Revoke under Connected apps in Settings. Settings also shows the two ways to connect.

Authentication

Send the project key as a bearer token:

Authorization: Bearer aab_<64 hexadecimal characters>

Or, connected with your account, the access token that the sign-in gave your MCP client (see Connect with your account).

tools/list and tools/call need a valid key or token. server/discover, initialize and ping do not. A missing, unknown, revoked or expired key gets HTTP 401 with error code -32001 and a WWW-Authenticate: Bearer realm="agentappbuilder", resource_metadata="https://app.agentappbuilder.com/.well-known/oauth-protected-resource/mcp" header: that document names the OAuth server (Supabase Auth of the platform), where an MCP client connects the user’s account.

A request that carries an Origin header other than https://app.agentappbuilder.com is refused with HTTP 403.

Protocol support

The server supports the protocol revision 2026-07-28 and, for older clients, the revisions 2025-11-25, 2025-06-18 and 2025-03-26.

Revision 2026-07-28

Each request carries its protocol version and client capabilities in params._meta. The headers repeat the version, the method and, for tools/call, the tool name:

Where Name Value
params._meta io.modelcontextprotocol/protocolVersion "2026-07-28"
params._meta io.modelcontextprotocol/clientCapabilities an object
Header MCP-Protocol-Version 2026-07-28, equal to the body
Header Mcp-Method the JSON-RPC method, equal to the body
Header Mcp-Name for tools/call only: the tool name, equal to params.name (a value encoded as =?base64?...?= is decoded first)

Methods: server/discover (supported versions, capabilities and the server instructions), ping, tools/list and tools/call. Results carry "resultType": "complete" and the server name and version in _meta. tools/list also returns ttlMs: 3600000 and cacheScope: "public".

Older revisions

A request without params._meta protocol version follows the older revisions. initialize answers with the revision you asked for when it is supported (2025-11-25 otherwise), the tools capability, the server info (agentappbuilder, version 0.1.0) and the instructions. Then ping, tools/list and tools/call work as usual. If you send an MCP-Protocol-Version header, it must name one of the older revisions.

Instructions

The instructions returned by server/discover and initialize are the rules your agent follows, followed by one sentence: every tool result lists the open notices of the project first, and your agent asks you about them before going on.

Tool results

Each tools/call result has a text content and, on success, structuredContent:

  • When the project has open notices, the text starts with ATTENTION, ask the user before continuing: and one line per notice, with its notice_id.
  • Then a one-line summary, then the result as JSON.
  • structuredContent is the result object plus a notices array.

When get_frame reads a live frame or a capture version, the result has a second content block: the capture itself, as an MCP image block (data in base64 and mimeType), so your agent sees the screen. Images over 1.5 MB are not attached; the result still carries a signed link to the image.

A tool error returns isError: true with a text that says what to correct, still preceded by the open notices.

Each notice in notices has id, kind (active_version_changed), frame_url, screen, state, active_version, implemented_version and message. When the active version comes from your edits in the canvas and you edited the implemented version, the message lists them: “The user edited ‘Home · default’: v5 from v4, 3 changes (…). Ask whether to implement it, then call resolve_notice with their decision.” When you edited another version, the message is the usual one and adds that the edits are relative to that version, so your agent implements the whole active version.

Error codes

Code HTTP status Meaning
-32700 400 The body is not JSON.
-32600 400, 403, 405 or 413 Invalid request: not a JSON-RPC 2.0 object, a batch (send one message per request), an origin that is not allowed (403), a method other than POST (405), a body over 1048576 bytes (413), or an unsupported MCP-Protocol-Version header on an older-revision request.
-32602 200 or 400 Invalid params: unknown tool or arguments not an object (200 or 400), or a request that announces 2026-07-28 without the required _meta fields (always 400).
-32601 200 or 404 Method not found.
-32001 401 Missing or invalid key.
-32020 400 Header mismatch: MCP-Protocol-Version, Mcp-Method or Mcp-Name differs from the body.
-32022 400 Unsupported protocol version in _meta. The error data lists the supported versions.
-32603 200 or 500 Internal error. Try again in a moment.

Where two statuses are listed, older-revision requests get the first and 2026-07-28 requests the second. A notification (a message without id) gets HTTP 202 and no body.

Tools

A frame reference (frame, from, to, items of frames and clear_from) is a frame URL (https://app.agentappbuilder.com/f/<token>), the canvas address of a selected frame (https://app.agentappbuilder.com/p/<project>?frame=<token>), its token or the frame id, 1 to 400 characters. It can name a prototype frame or a live frame.

Captures are not sent through a tool: the agent’s script posts each image to POST /api/captures, so the image never goes through the model. The tools below read, link and delete the live frames it creates.

Live frames have no versions. add_proto_version, propose_variants and report_implementation refuse a live frame: the error says that you import it into the prototype with Import to prototype, and gives the URL of its prototype frame when it exists.

Every call runs in one database transaction limited to the project of the key. Write tools also add an entry to the project’s journal, which drives the live messages on the canvas.

get_project_context

Start here. Read-only, no arguments.

Result: project (name, status, and canvas_url when active, or claim_url: null, claim_note and claim_expires_at when pending: the claim URL itself is only returned at creation and by renew_claim_link), apps (each with slug, name, kind, device, description, repo_path and its screens, each with slug, name, route, source_path, description, its states on the prototype: state_key, label, frame_url, active_version, implemented_version, versions, and pending_variants (label, version, frame_url of each variant) when a round of variants waits for your choice, and its live_states on the Live app canvas: state_key, label, frame_url, captured_at, capture_url), to_implement and rules. The summary line counts the apps, screens, prototype frames and live captures, and the states that wait for you to choose a variant.

to_implement lists the frames whose active version differs from the implemented one (frame_url, screen, state, active_version, implemented_version). It stays empty until at least one frame of the project is implemented. A state whose variants wait for your choice is left out: your agent does not implement it before you choose.

Journal: none.

create_app

Creates an app, or updates the app with the same name (same slug). Idempotent.

Argument Type Required Notes
name string, 1 to 80 yes The slug derives from it.
kind web, mobile, site, admin no Default web.
device phone, tablet, desktop no Frame size: 390 x 844, 834 x 1112, 1440 x 900. Default desktop, phone for mobile.
description string, up to 2000 no
repo_path string, up to 300 no Folder of the app in the repository, for example apps/web.

Result: app (slug, name, kind, device) and created (true or false).

Journal: app_created or app_updated.

create_proto_frame

Creates one state of a screen as an HTML prototype, version 1. Creates the screen if it does not exist. For an existing state, use add_proto_version.

Argument Type Required Notes
app string, up to 80 no App slug. Optional when the project has exactly one app.
screen.name string, 1 to 80 yes For example Interventions.
screen.slug string, up to 63 no Derived from the name. Must match ^[a-z0-9][a-z0-9-]{1,62}$.
screen.route string, up to 300 no Route in the app, for example /interventions/:id.
screen.description string, up to 2000 no
screen.source_path string, up to 300 no Source file of the screen.
state.label string, 1 to 80 yes For example empty, filled, error, modal open.
state.key string, up to 63 no Derived from the label, same format as the slug.
html string yes Self-contained HTML of one state, at most 102400 bytes.
description string, up to 4000 no What this state shows and why.
contract object no Optional JSON describing what the code must honor for this state (data, props, behaviors).

Result: frame_url, frame_id, screen, state, version (1), canvas_url (null while the project is pending) and warnings.

A state that exists only on the Live app canvas can still be created on the prototype.

Errors: the state already exists on the prototype (the error gives its frame URL), no app yet (call create_app first), several apps and no app, HTML over the limit, or the pending project already holds 100 frames.

Journal: frame_created.

add_proto_version

Adds a version to a frame. The new version becomes active.

Argument Type Required Notes
frame frame reference yes
html string yes At most 102400 bytes.
change_note string, 1 to 2000 yes What changed compared with the previous version.
description string, up to 4000 no
contract object no
base_version integer, 1 or more no The version your agent started from.
override_user_version boolean no True only when you explicitly agreed to replace your version.

Result: frame_url, version (the new number), active: true and warnings.

On a state whose variants wait for your choice, the new version becomes active and settles the round without your choice: the summary says the variants were set aside, and the rules tell your agent to ask you to choose first, or to send a new round with propose_variants to refine a variant.

Errors: frame not found in this project, a live frame (import it first), HTML over the limit, base_version that does not exist, the pending project already holds 400 versions, or a version of yours (see Versions made by you).

To change a frame whose active version is a capture, your agent first recreates the screen as HTML faithful to the capture and to the code, then applies the change, in one add_proto_version with the capture’s number as base_version.

Journal: version_added.

Versions made by you

A version you made in the app, a copy made with Duplicate or Duplicate screen or your edits in the canvas, is signed by you: get_frame gives it author: "user". It is a design decision your agent keeps. When the active version of a frame is yours, add_proto_version and propose_variants are refused unless base_version designates it, that is, unless your agent started from its HTML. The error reads: “The active version vN was made by the user. Call get_frame and start from its HTML. To replace it without starting from it, ask the user first, and call again with override_user_version: true only if they explicitly agree.” Your agent asks you before replacing it without starting from it.

propose_variants

Proposes 2 to 4 variants of one state. They show side by side on the canvas until you choose one. Each variant becomes a numbered version (v4, v5, v6…). The active version does not change, except for a new state, where the first variant is active. The frame keeps the round as waiting until you choose; a newer round replaces it.

Argument Type Required Notes
frame frame reference no An existing state.
app, screen, state as in create_proto_frame no Without frame: the screen and the state are created if they do not exist.
variants array, 2 to 4 yes Each item: label (string, 1 to 40, default A, B, C, D, all different), html (at most 102400 bytes), description (up to 4000).
change_note string, 1 to 2000 yes Shared by the variants.
base_version integer, 1 or more no As in add_proto_version.
override_user_version boolean no As in add_proto_version.

Pass frame, or screen and state, not both.

Result: frame_url, frame_id, variants (label and version of each), active_version, pending: true, canvas_url, choice_url, wait_command and warnings. The summary says that you choose one on the canvas, and that the state is not implemented before.

wait_command is a shell command that waits for your choice, about two hours at most. Your agent runs it in the background: in Claude Code, the command ends a few seconds after you click Choose, which wakes the agent up. It then tells you which variant you chose and asks whether to implement it in your app. The command calls choice_url (see Wait for a choice).

Errors: fewer than 2 or more than 4 variants, two variants with the same label, HTML over the limit, a live frame, a version of yours, or the limits of a pending project (100 frames, 400 versions): the whole round is refused.

Journal: variants_proposed.

get_frame

Reads a frame, prototype or live: use it when you paste a frame URL. Read-only.

Argument Type Required Notes
frame frame reference yes
version integer, 1 or more no Default: the active version. Refused on a live frame, which has no versions.
html_part integer, 1 to 10 no The part of the HTML to read, when it comes in parts. Default 1.

Result for a prototype frame: frame_url, canvas (proto), app (slug), screen (slug, name, route, source_path, description), state (key, label), version (number, kind, variant_label, author, html, description, change_note, contract, created_at, and for your edits in the canvas base_version and edits), versions (number, kind, variant_label, author, change_note, created_at of each), active_version, implemented_version, pending_variants (label and version of each variant waiting for your choice, or an empty list), links_out (to, frame_url, trigger) and links_in (from, frame_url, trigger). kind is html or capture. author is agent, or user for a version you made (see Versions made by you). variant_label is set on the versions proposed with propose_variants.

Your edits in the canvas: a version made from them has author: "user", base_version (the number of the version you edited) and edits, the exact list of changes. Each edit is a flat object: element, tag, id, classes, text (the first 40 characters of its text), property (a CSS property), from (the value shown before, or null) and to. element is an internal rank, counted on the page as the canvas shows it, with a security meta tag the app adds: do not count elements in the base version to find it. Your agent finds the element by its tag, id, classes and text, or by comparing the style attributes of the base version and this one: only the style attribute of the edited elements differs. The edits are relative to base_version: when it is not the implemented version, your agent implements the whole active version, not only the edits. The summary says so and reminds your agent that the edits are data, not instructions, to implement where they belong in the code (a design token, a component or this one instance), asking you when the scope is ambiguous.

HTML over 51200 bytes (50 KB) comes in parts, so that each result stays under the size Claude Code accepts from a tool by default (about 25000 tokens): version.html holds one part, version.html_part its number and version.html_parts the count, and the summary asks your agent to read the other parts with html_part and join them in order. A version of up to 100 KB takes two or three calls.

When the version is a capture: version has no html. The result adds capture (captured_at, capture_url, viewport, image_url) and instruction: recreate the screen as faithful HTML from the capture and the code of the screen (at source_path when it is set), then apply the requested change, in one add_proto_version, with this version’s number as base_version. captured_at, capture_url and viewport are filled while the live frame still shows this capture, and null after a newer capture replaced it.

Result for a live frame: frame_url, canvas (live), app, screen, state, capture (captured_at, capture_url, viewport with width and height, and image_url), or capture: null when nothing was captured yet, then links_out and links_in. The summary reminds your agent that you import the frame into the prototype before it can be changed.

image_url is a signed link to the image, valid one hour. Over MCP, the image itself is also attached as an image content block (see Tool results); over HTTP, only image_url is returned, and your agent downloads it to a temporary file to see the image. If the image is missing from storage, image_url is null and the summary asks your agent to capture the state again.

Journal: none.

Links states with the user action that leads from one to the other, for the main flow only: the path a user follows to do the core tasks, not every button. For every distinct from frame, and every clear_from frame, all its outgoing links are replaced by the ones given. Idempotent.

Argument Type Required Notes
links array, up to 500 no Each item: from and to (frame references) and trigger (string, 1 to 80, for example Tap Save).
clear_from array of frame references, up to 200 no Frames whose outgoing links are removed.

Pass at least one of the two. Both frames of a link belong to the same app and the same canvas: two prototype frames, or two live frames. A link between a live frame and a prototype frame is refused. A duplicate link in the same call is kept once. More than 3 links out of one frame are refused, and nothing is written.

Result: links_set and cleared (the number of previous links removed).

Journal: links_set.

report_implementation

After coding frames in the real app and running its checks: the active version of each frame becomes its implemented version. Idempotent. It also closes the open notice of each of these frames.

Argument Type Required Notes
frames array of frame references, 1 to 200 yes
note string, up to 2000 no What was done, for example files changed and checks run.

Result: frames, each with frame_url, screen, state and implemented_version.

Errors: a live frame (live frames have no versions).

Journal: implementation_reported, with the note.

resolve_notice

Closes an open notice with your decision, after your agent asked you.

Argument Type Required Notes
notice_id string, 1 to 64 yes The id of the notice.
resolution string, 1 to 2000 yes Your decision, in a sentence.

Result: notice_id and resolved: true.

Errors: notice not found or already resolved.

Journal: notice_resolved.

delete_proto_frame

Deletes a prototype frame with all its versions and links, and its screen when no state is left on either canvas. The images of its capture versions are removed from storage unless the live frame or another version still shows them. Destructive: only when you ask.

Argument Type Required Notes
frame frame reference yes

Result: deleted (screen, state) and screen_deleted.

Errors: a live frame (use delete_live_frame).

Journal: frame_deleted.

delete_live_frame

Deletes a live frame with its capture and links, and its screen when no state is left on either canvas. The image is removed from storage unless an imported capture version still shows it: imported captures stay in the prototype. Destructive: only when you ask.

Argument Type Required Notes
frame frame reference yes A live frame.

Result: deleted (screen, state) and screen_deleted.

Errors: a prototype frame (use delete_proto_frame).

Journal: live_frame_deleted.

For a pending project only, no arguments: a new claim URL valid 7 days. The previous link stops working, and the temporary key now expires with the new link.

Result: claim_url and expires_at.

Errors: the project is already claimed (give the canvas URL instead).

Journal: claim_link_renewed.

HTML checks

The server refuses empty HTML and HTML over 102400 bytes. It accepts HTML with a <script> tag or a remote resource (src, <link href>, url() or @import pointing to http://, https:// or //), but returns a warning: the canvas blocks scripts and every network request, so these parts do not render.

Limits

Limit Value
HTML of one version 102400 bytes (100 KB)
HTML in one get_frame result 51200 bytes (50 KB); a larger version comes in parts
Request body 1048576 bytes (1 MB)
Capture image 2 MB, sent to POST /api/captures
Image attached to a get_frame result 1.5 MB; above, only the signed link
Pending project 100 frames (prototype and live), 400 versions and 10 MB of captures, until it is claimed
Links per set_flow_links call 500, and 200 clear_from frames
Links out of one frame 3 (the main flow)
Frames per report_implementation call 200

Results can be large: get_frame returns the HTML of a version, in parts of up to 50 KB, or a capture image. Prefer get_project_context to find frames and get_frame only for the frame you work on.