carter-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| CARTER_RELAY_URL | No | Gateway ws/wss URL for target='relay' connects. | |
| CARTER_MESH_TOKEN | No | Gateway auth token (else auto-minted via a validator). | |
| CARTER_VALIDATOR_URL | No | Dev validator base URL used to auto-mint a token. | |
| CARTER_LOCAL_RELAY_PORT | No | Port for the in-process local relay (default 8765). | 8765 |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| begin_editA | Start (or restart) the working layout buffer for incremental editing. Then use add_control / insert_example / update_control / move_control / etc. to edit surgically, preview_buffer to see it, and push_buffer to send it live — without ever re-emitting the whole layout. The app-authored wiring flow: the user arranges controls in the phone's Layout
Editor and saves; Args: name: Layout name (blank-buffer mode). columns, rows: Grid of the first tab (blank-buffer mode). accent: Accent color hex (blank-buffer mode). mode, row_height: First tab's grid mode ("grid" default 2-D / "flow") and 2-D row-unit height in points (blank-buffer mode). from_sample: Seed from a sample layout filename (e.g. 'demo-offline.json'). from_device: Seed from the layout currently live on the paired device (read-modify-write). from_device_file: Seed from a SAVED layout on the device by filename or display name (the phone-editor handoff), whether or not it's active. |
| preview_bufferA | Show the current working buffer: structure, per-tab grid maps, and any placement issues. Never re-dumps the whole JSON (use get_buffer_json for that). |
| get_buffer_jsonA | Return the full JSON of the working buffer (for inspection or manual save). |
| add_controlA | Add one control to the buffer. Auto-assigns a unique id and (if no position is given) the next free grid slot honoring the control's default span. Args: control_json: A single control object, e.g. {"type":"gauge","label":"Battery"}. tab_index: Which tab to add to (default 0). position: Optional [row, col]; omit to auto-place. |
| insert_exampleA | Drop a documented control example straight into the buffer, with a fresh id and a free grid slot. Browse with list_control_examples, then place one here. Args: control_id: Control type or doc node-id (e.g. 'gauge'). name: Example name (prefix match); omit for the first example. tab_index: Which tab to add to. position: Optional [row, col]; omit to auto-place. |
| update_controlA | Merge fields into an existing control. Set a field to null to remove it. Args: control_id: id of the control to edit. patch_json: Object of fields to merge, e.g. {"tint":"#FF0000","style":"ghost"}. |
| remove_controlB | Remove a control from the buffer by id. |
| move_controlB | Reposition / resize a control, or move it to another tab. Args: control_id: id of the control. position: New [row, col]. span: New [rowSpan, colSpan]. tab_index: Move to this tab index. |
| add_tabA | Add a tab to the buffer. Returns its index. mode: "grid" (default 2-D — controls span row x col) or "flow" (legacy row-banded; use for a full-page map/chat/cardList or a plain form). row_height: points per row-unit in 2-D mode (default 56). |
| add_groupA | Add a group container to the buffer (auto-placed unless position given). Nested children are normalized like add_control: each gets an id and an auto-placed position in the group's own grid. Args: group_json: A group object, e.g. {"label":"Lights","grid":{"columns":2,"rows":2},"children":[...]}. tab_index: Which tab to add to. position: Optional [row, col]. |
| show_gridA | ASCII occupancy map of a tab's grid — which cells are filled (by which control) and which are free. 'See' the layout spatially before editing. |
| discard_bufferA | Discard the working buffer without sending anything. |
| validate_layoutA | Lint a layout against the control schema WITHOUT pushing it: duplicate ids, unknown control types, unknown/bad-enum fields, and grid overlaps/out-of-bounds. Args: layout_json: Complete layout JSON string. |
| validate_bufferA | Lint the working buffer against the control schema (same checks as validate_layout) before you push or save it. |
| snapshot_bufferB | Save a snapshot of the working buffer so you can revert later. |
| list_snapshotsB | List saved buffer snapshots. |
| revert_bufferA | Restore the working buffer from a snapshot (default the most recent). Args: index: Snapshot index (see list_snapshots); -1 = latest. |
| push_layoutA | Push a layout to the paired device. The device renders it immediately. When a single device is paired, this pushes over routed RPC and reports back exactly what the device rendered (or why it rejected the layout) — no more blind "pushed successfully". With no resolvable device it falls back to a broadcast so every paired viewer updates at once. Args: layout_json: Complete layout JSON string. Must be valid LayoutConfig. |
| save_layoutB | Push a layout and tell the device to save it to disk permanently. Args: layout_json: Complete layout JSON string. Must be valid LayoutConfig. |
| push_bufferA | Push the working buffer to the paired device (truthful apply with a rendered echo when a single device is paired). Edits stay in the buffer for further work. |
| save_bufferB | Push the working buffer AND tell the device to persist it to disk. Args: filename: Optional filename (derived from the layout name if omitted). |
| get_device_layoutA | Read the layout currently live on the paired device (structural summary). Lets you SEE what's on the phone before editing, instead of pushing blind. Args: full: If true, also include the complete layout JSON (default: summary only). |
| get_control_stateA | Read the current values of controls on the paired device. Args: ids: Optional list of control ids to filter to. Omit for all controls. |
| get_connection_statusA | Read the paired device's relay connection status — whether it's connected, on which channel/account, and which events it's listening on. |
| get_device_infoA | Read the paired device's CAR-TER app version, build, and protocol version. Use this to confirm the phone's installed app understands the control definitions you're authoring against. An older app silently drops controls or fields it doesn't recognize — see check_sources for a full drift verdict. |
| check_sourcesA | Report where the MCP is pulling truth from, and flag any drift. CAR-TER's MCP is a thin local tool layer over live sources: control DEFINITIONS come from the website catalog (carterbeaudoin.net/CAR-TER), and authoring DEMOS come from the installed carterkit. This shows the catalog version/freshness/fingerprint, installed-vs-latest carterkit, and — when a device is paired — the phone's app/protocol version, then gives an alignment verdict. Run this at the start of a session, and again whenever a pushed layout behaves unexpectedly, to catch the case where the site, the kit, and the app have drifted out of sync. Args: refresh: Force a fresh fetch of the website catalog + PyPI version, bypassing the local cache. |
| list_device_layoutsA | List all layout files stored on the paired device. Returns the name, filename, tabs, and accent color of each layout. The device must be connected and paired first via connect. |
| save_device_layoutA | Create or update a layout file on the paired device. The layout is written to the device's Layouts folder. If a file with the same name already exists, it is overwritten. Args: layout_json: Complete layout JSON string. Must be valid LayoutConfig with a "name" field. filename: Optional filename (e.g. 'my-layout.json'). Derived from the layout name if omitted. |
| customize_on_phoneA | Hand a control to the phone's on-screen configurator so the USER customizes it by hand (live preview + field editor), then read back exactly what they shaped. "Shape it on glass, wire it on the model": the human does the look/feel, you do the plumbing. The user taps "Send to Editor" on the phone to return the control. Requires a paired device in a live-edit session (connect + scan QR). Args: control_json: The control to hand off (e.g. {"type":"gauge","label":"Battery"}). timeout: Seconds to wait for the user to finish (default 120). add_to_buffer: If true, drop the returned control into the working buffer. tab_index: Tab to add to when add_to_buffer is set. |
| list_controlsA | List all available CAR-TER control types and system features. For placeable controls the |
| get_control_docA | Get the full documentation for a specific control type or system feature. Args: control_id: The control identifier (e.g. 'button', 'gauge', 'sync', 'layout-config') |
| list_sample_layoutsA | List all available sample layout files that can be used as references. |
| get_sample_layoutB | Get the full JSON of a sample layout file. Args: name: Filename (e.g. 'demo-offline.json') or name without extension |
| get_layout_schemaA | Get the layout JSON structure reference showing all fields and their types. |
| get_control_catalogA | Machine-readable schema for every placeable control, in ONE call. Returns compact JSON keyed by control Args: types: Optional list of control types/node-ids to filter to (e.g. ['gauge','button']). include_theme: Also include each control's per-control theme override fields. |
| list_control_examplesA | List the named example snippets available in a control's documentation. Use get_control_example to fetch one as a ready-to-tweak config. Args: control_id: Control type or doc node-id (e.g. 'gauge', 'color-picker'). |
| get_control_exampleA | Get a ready-to-customize JSON config for a documented control example. Copy it, tweak the fields, then place it into a layout (or use insert_example to drop it straight into the working buffer with a fresh id + free grid slot). Args: control_id: Control type or doc node-id (e.g. 'button', 'gauge'). name: Example name (prefix match, case-insensitive). Omit for the first example. |
| infer_layoutA | Infer a wired first-draft layout from a real JSON payload (paste a sample from your service, or use probe_service to capture one). Numbers→gauges, 0..1→progress rings, bools→toggles, lat/lng→map, arrays→sparklines/cardlists, strings→labels — each bound to the right nested valuePath. Args: payload_json: A sample JSON object emitted by your service. name: Layout name. event: The mesh event the controls should listen on (default 'telemetry'). columns, rows: Grid of the inferred tab. into_buffer: Load the result into the working buffer for further editing (default). |
| autotune_gaugeA | Tune a buffer gauge from observed samples: sets min/max and color zones at the data's percentiles, oriented by whether higher is better (battery) or worse (temp), inferred from the field name. Args: control_id: id of a gauge in the working buffer. samples_json: JSON array of numeric samples, e.g. [40,52,61,73,95]. field_name: Metric name for unit/direction hints (defaults to the id). |
| list_theme_vibesA | List the built-in theme vibes you can generate with generate_theme. |
| generate_themeA | Generate a layout theme from a vibe description or a brand color, and (by default) apply it to the working buffer. Args: description: Free text, e.g. 'fighter jet HUD', 'synthwave neon', 'clean apple'. accent: A brand hex color to build the theme around (overrides description). apply_to_buffer: Set the buffer layout's theme + accentColor (default true). |
| generate_serviceA | Generate a runnable Python MeshSocket service that speaks to a layout — handles the events its controls fire and emits the telemetry they listen for. Uses the working buffer if no layout_json is given. Args: layout_json: Optional layout JSON; defaults to the working buffer. |
| generate_adapterA | Generate a REST-poll → MeshSocket adapter that maps an API's fields to a layout's synced valuePaths. Uses the working buffer if no layout_json is given. Args: base_url: The REST endpoint to poll. layout_json: Optional layout JSON; defaults to the working buffer. |
| connectA | Pair a device for live layout authoring. Hassle-free by default. target="local" (default): spins up an in-process, auth-free MeshSocket relay on this Mac and builds a QR with the LAN IP — no gateway, no token, no AWS. Just have the phone on the same Wi-Fi (the app allows ws:// on the LAN). target="relay": use the Connect+ gateway instead (phone can be on any
network, wss). The token is taken from Args: channel: MeshSocket channel name (default 'editor'). role: MeshSocket role for the editor (default 'editor'). target: 'local' (default, zero-config) or 'relay' (gateway). url: gateway ws/wss URL (target='relay' only); else CARTER_RELAY_URL/default. token: gateway token (target='relay' only); else env, else auto-mint. validator_url: dev-validator base URL to mint a token from (target='relay'). |
| show_qrA | Show the QR code for pairing a device to the current editing session. Must be connected first via the connect tool. |
| wait_for_deviceA | Wait for a device to pair after scanning the QR code. Blocks until a device joins the editing channel or the timeout expires. Args: timeout: Max seconds to wait (default: 30) |
| disconnectA | Disconnect from the MeshSocket relay and end the editing session. |
| probe_serviceA | Listen to the live mesh and report the service's data schema: which events and fields it emits, their value types, ranges, and examples. Run this, then autowire_buffer / lint_against_traffic / infer_layout can use what was discovered. Args: seconds: How long to listen (default 8). event: The mesh event to sniff (default 'broadcast', the data channel). |
| simulateA | Emit a data frame onto the channel as if from the service — drives any synced controls so gauges move and sparklines fill (live demo / no-backend testing). Args: payload_json: The frame to emit, e.g. {"battery":82,"cpu_temp":61}. event: Event to emit on (default 'broadcast'). |
| set_control_valueB | Drive one buffer control live by emitting a frame at its bound valuePath. Args: control_id: id of a control in the working buffer (must have a listen sync). value_json: The value to push, e.g. 82 or "online" or true. |
| autowire_bufferA | Bind unbound display controls in the buffer to fields discovered by the last probe_service run (matched by name), then report what still needs wiring — values without a match AND input controls without an action (the triggers half, which needs the server's command vocabulary, i.e. you). Run probe_service first. |
| lint_against_trafficA | Check the buffer's sync valuePaths against fields seen by the last probe; flags bindings that would silently show no data (wrong path / namespace). |
| lint_dynamic_trafficA | Check the buffer's |
| show_mesh_graphB | Visualize the live MeshSocket network on the device — builds a graph layout and pushes the current roster as animated nodes/edges. "Show me my mesh." Replaces the working buffer with the mesh layout. Args: name: Layout name. |
| run_scenarioA | Drive the device through a scripted scenario and assert control states — UI testing over the mesh, no XCUITest. Each step: {"emit": {...frame...}, "event": "broadcast", "wait": 0.5,
"expect": {"control_id": expected_value, ...}}.
Args: steps_json: JSON array of step objects. |
| say_in_chatA | Post a message into a layout's channel chat control as the LLM — the in-app agent surface. Requires a paired device showing a chat control. Args: text: The message to send. sender_name: Display name to send as (default 'Claude'). |
| read_chatA | Listen for incoming chat messages for a while and return them — so the LLM can answer what users type in an in-app chat control. Args: seconds: How long to listen (default 15). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mariner10/carter-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server