Studio Sessions & the MCP Authoring Loop
Beyond running layouts, CAR-TER supports authoring them live: push a layout
to a paired device, see it render instantly, read back what's on screen, and
iterate. The MCP server (carter-mcp) drives this loop, letting an LLM build
and push layouts; you can also author programmatically with carterkit
and push over the same mechanism. This is distinct from a data server
(Anatomy of a CAR-TER Server); it's about editing the UI.
The MCP server is open source at github.com/Mariner10/carter-mcp (MIT). Clone it, install it, and point your AI client at it — the three steps below get you authoring on-device in a couple of minutes.
Get it running
1. Install
Requires Python 3.11+. Clone the repo and install its dependencies — a virtual environment is recommended so the server always finds them:
git clone https://github.com/Mariner10/carter-mcp.git
cd carter-mcp
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
That pulls carterkit (the layout-authoring engine), meshsocket (the
transport), the mcp SDK, and qrcode.
2. Connect it to your AI client
carter-mcp speaks MCP over stdio under the server name carter; register
server.py with your client, using the interpreter that has the dependencies (the
venv Python above).
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"carter": {
"command": "/absolute/path/to/carter-mcp/.venv/bin/python",
"args": ["/absolute/path/to/carter-mcp/server.py"]
}
}
}
Claude Code — from the repo directory:
claude mcp add carter -- "$(pwd)/.venv/bin/python" "$(pwd)/server.py"
Restart the client and you should see the carter server and its tools. To smoke-test
the server on its own, run python server.py (it serves MCP on stdio and waits).
3. Author your first layout
Ask your assistant something like "pair with my phone and build a two-gauge server
dashboard." It will connect() (a zero-config local relay + a pairing QR — no account,
no cloud), you scan the QR with CAR-TER on the same Wi-Fi to start a Studio Session,
and it push_layout(...)s the panel — which renders on your device instantly and echoes
back exactly what rendered. The full tool sequence is in A typical loop
below.
How a Studio Session works
- The authoring client (the MCP) connects to a relay and shows a pairing QR (Connection & Pairing).
- The phone scans it and starts a Studio Session (role
viewer/editor), rendering a pushed layout and re-rendering on every push. - The client pushes layouts and reads device state over MeshSocket.
During a Studio Session the device arms read-back responders so the client
isn't flying blind. They are routed-request handlers (answered via route_msg):
| Verb | Returns |
|---|---|
get-current-layout |
The layout currently live (summary or full JSON) |
get-control-state |
Current control values ({ id: value }) |
get-connection-status |
Connected?/phase/channel/role/which events it's listening on |
apply-layout |
Applies a pushed layout and echoes exactly what rendered (or an error) |
list-layouts / save-layout |
List/persist layout files on the device |
The apply-layout echo is the important one: a push reports back the structure the
device actually rendered (a control dropped on decode won't appear), so the client
never assumes a blind "success."
The MCP server (carter-mcp)
carter-mcp exposes these as tools an LLM (e.g. Claude) can call:
- Docs:
list_controls,get_control_doc,get_layout_schema,list_sample_layouts,get_sample_layout. - Pairing:
connect,show_qr,wait_for_device,disconnect. - Authoring:
push_layout(truthful apply-layout echo),save_device_layout,list_device_layouts. - Read-back:
get_device_layout,get_control_state,get_connection_status.
Hassle-free transport
connect() defaults to target="local": it spins up an in-process,
auth-free MeshSocket relay on your machine and builds the QR with your LAN IP —
no gateway, no token, no cloud. Put the phone on the same Wi-Fi and scan. For
remote authoring, connect(target="relay") uses the Connect+ gateway and
auto-mints a token from the dev validator, so you still don't hand-paste
credentials.
A typical loop
connect() # zero-config local relay + QR
show_qr() # (or scan the QR connect() returned)
wait_for_device() # polls the roster until the phone joins
push_layout(<json>) # device renders it; returns the structural echo
get_device_layout(full=true) # confirm what's live
get_control_state() # read values off the device
save_device_layout(<json>) # persist it on the device
disconnect()
Roster note:
wait_for_devicepollsget_nodesrather than waiting on the membership push, because the relay's identify-time roster broadcast can miss a peer that joins after the authoring client — see Message Reference.
Two ways to author
- MCP (
carter-mcp) — LLM authoring: "describe the dashboard and watch it appear," with live push + read-back. Best for conversational, exploratory design. - carterkit — programmatic authoring in Python (
Layout, typedbuild.<control>,bind,validate) plus a CLI. Best for scripted, repeatable layout generation and CI.
Both produce the same layout JSON over the same protocol, so a layout authored either way runs against any data server you build.