CodelabDocs
Model

App

The workspace that owns pages, components, stores, and theme.

An App is the unit you build against on the hosted MCP (https://mcp.codelab.app/mcp). It is identity, published URL, and the parent of every page, component, store, and theme token in the project.

Nothing on the canvas exists outside that app. Element trees hang off pages and components the app owns; stores, hooks, schemas, env vars, and theme rules are app-scoped too.

App
├── Pages          routed element trees
├── Components     reusable element trees + fields
├── Stores         runtime state (app-wide or attached to a page/component)
└── Theme          tokens + kind styles

Docs Nest app card on My Apps — name, description, and the builder entry
Docs Nest app card on My Apps — name, description, and the builder entry

Fields

Pages belong to the app but are listed separately (list_pages) — they are not nested on the app record.

NameTypeDefaultDescription
idstringApp id. Pass this to set_context.
namestringDisplay name.
handlestringGuaranteed URL: <handle>.codelab.app.
customSubdomainstringAdmin-granted subdomain on the same apex; overrides the handle.
customDomainstringYour own host; wins over handle and subdomain.
customDomainStatus"pending" | "active" | emptyemptyTLS for a custom domain: pending while the cert issues, active once live.
descriptionstringOptional summary.
defaultOgImagestringDefault Open Graph image.
faviconUrlstringFavicon.
siteTitleSuffixstringAppended to page titles.

create_app does not leave an empty shell. It creates the app, a default Home page (isHome: true, routePattern: ""), a chat, variant presets, and heading kind styles.

An app must keep at least one page. Home is the page flagged isHome, else the first page.

How it relates

ChildRole
PageA routed tree visitors hit. Shared chrome lives on a layout page, not copied onto every leaf.
ComponentA reusable tree. Place one on a page as an element whose kind is { _tag: "Component", value: componentId }.
ElementA node inside a page or component. The app never owns an element directly.
StoreNamed runtime state. App-wide when unscoped; attach to a page or component so the name can be a plain state per owner. Store actions[] are Action chains.
ThemeApp-level tokens (theme_tokens) and kind styles (style_rules). Brand here before per-element style_*.

Hooks, reusable schemas, and env vars are also app-scoped. Hook methods bind as "<hookId>.<method>" actions; field shapes are the type system.

MCP tools

Connect to https://mcp.codelab.app/mcp. App CRUD addresses the app by id (you can only touch your own). Everything else that lists or mutates inside an app needs a conversation context.

ToolWhat you use it for
list_appsDiscover appId, name, subdomain, domain, customDomainStatus. Call this before set_context.
set_contextActivate an app. Omit contextId on the first call; keep the returned contextId and pass it to every app-scoped tool. Send the same id when switching apps.
get_contextVerify the active app.
clear_contextDrop this conversation's handle.
create_app{ name, description? } — scaffolds Home + chat + presets. Then set_context with the new appId.
update_appPartial metadata (name, description, customDomain, SEO defaults). Omitted fields stay. customSubdomain is admin-only.
delete_appCascades pages, elements, stores, … Irreversible. If it was the active context, set_context again.

App-scoped follow-ups (all take contextId): list_pages, list_components, list_stores, list_hooks, list_schemas, list_env_vars, list_theme_tokens, list_theme_styles.

Element tools take a container ({ _tag: "Page", id } or { _tag: "Component", id }) instead of appId. Ownership is checked from that id, not from context — but you still need context to find those ids.

Typical first calls: list_appsset_context with an appIdget_context to confirm → list_pages (Home is already there).

Gotchas

  • No context, no canvas. list_pages, create_store, add_element (once you need a page id), and the rest fail until set_context. Keep contextId; there is no hidden session app.
  • create_app already made Home. Do not create_page for the landing page. list_pages first.
  • Theme before elements. Tokens (list_theme_tokens / update_theme_tokens) restyle every Button and Card. Kind styles (list_theme_styles / update_theme_style) cover extras the theme does not set. Per-element style_* is last. Token keys are fixed — you change values, not names.
  • previewData is builder-only. Sample {{session.*}} for the canvas. The published site never reads it.
  • delete_app is total. Every page, element, and store goes with it.

On this page