Robutler

MCP build tools

These are the build and control tools exposed at https://robutler.ai/mcp once your coding agent is connected. Apps are built as widgets, so the tools are named widget_* (authoring) and workspace_* (driving apps you have open). For the discovery and platform tools (search, delegate, and so on) see the MCP tool catalog.

Every tool authorizes as the connected user and re-checks ownership in the underlying pipeline. Client-supplied ids are never trusted: you cannot publish a folder you do not own or invoke a command in a workspace you cannot access.

Each tool returns JSON. Errors come back as a text result flagged isError.

Two ids per app, and they are not interchangeable. An app has a widget id (widgetContentId — the row that mounts and renders) and a bundle folder id (folderId — where its files live). Mount and share with the widget id; read and write files with the folder id. widget_instantiate resolves an owned bundle folder to its widget for you, but the distinction is worth keeping straight.

Permissions. Every tool carries MCP annotations: read-only tools (widget_catalog, widget_download, widget_fn_logs, widget_scaffold, the workspace_* listing and log tools) run without a per-call confirmation in clients such as Claude; write tools create or update something you own; destructive tools (widget_put_files, which overwrites files, widget_publish, which replaces the live public version, and workspace_widgets_invoke, which runs whatever command an app declares) prompt before each call. See the MCP tool catalog.

Publishing is open to every owner. widget_publish and widget_snapshot are registered for every account; both re-check that you own the folder or working app before anything reaches the catalog. An unpublished app still runs, mounts, and can be shared privately.

Authoring tools (widget_*)

create_widget

The one-call authoring path: scaffolds the chosen template, lands it as an editable bundle folder you own, registers it as a private widget you can mount immediately, and mints a dev token.

ArgumentTypeNotes
namestringApp name. Non-kebab characters are normalized to -.
templatestringcollab-app (default, full starter) · minimal · webgpu · webrtc.

Returns { folderId, widgetContentId, widgetType, name, template, fileCount, files, openUrl, devToken, hint }. Mount with widget_instantiate(refId=widgetContentId); edit with widget_put_files(folderId, …); openUrl opens the app full screen.

widget_scaffold

Returns the same starter bundle as a files map to write locally: widget.json, the entry HTML, app code, and (for collab-app) an AGENT.md, tests, and a server function. It does not write anything server-side — prefer create_widget unless you want to iterate locally first.

ArgumentTypeNotes
namestringApp name.
templatestringSame choices as create_widget.

Returns { name, template, files, hint } where files is a path-to-contents map.

widget_put_files

The edit step of the loop. Upserts text files into a bundle folder you own, writing the bytes inline so the sandbox serves them immediately. Creates parent subfolders as needed.

ArgumentTypeNotes
folderIdstringThe bundle folder id (from create_widget, widget_remix, or widget_download).
files[]arrayEach entry is { path, text } (full replace) or { path, edits: [{ oldText, newText }] } (in-place patch; each oldText must occur exactly once). Prefer edits for large files so you do not re-send them.

UTF-8 text only: widget.json, the entry HTML, JS / CSS modules, AGENT.md. Binary assets (images, fonts) go through the dev-token upload path, not this tool. Limits: at most 100 files per call, 32 MiB per file. Storage is automatic: small files live inline, larger ones go to content-addressed blob storage — edits patch a file of any size either way (a remixed app's multi-MB built boot.js included).

File edits are live in the bundle — reload the mounted instance (workspace_widgets_invoke builtin __reload) to see them, and bump any ?v= cache token on assets you changed. Changes to widget.json or the declared command surface are snapshotted onto the widget row and refresh on republish.

Returns { folderId, results: [{ path, action: 'created' | 'updated', id }], hint }.

widget_instantiate

Mounts an app on a workspace canvas and returns where to open it. Validates the ref before mounting: an id that does not resolve to content you can read is an error, and a bundle folder id is auto-resolved to its widget row (registering one for a folder you own) rather than mounting an inert file.

ArgumentTypeNotes
refIdstringA widget id (widget_catalog refId, or the widgetContentId from create_widget / widget_remix), a project contentId (create_document), or an owned bundle folderId (auto-resolved).
workspaceIdstringExisting workspace. A new one is created if omitted.
namestringName for the new workspace.
freshbooleanForce a new instance. By default the call is idempotent: an existing mount of the same refId (recent call, or one of your open workspaces) is returned with reused: true.

Returns { workspaceId, itemId, refId, mountKind, canvasUrl } (+ reused, and resolvedFrom when a folder id was resolved). Assert on mountKind: "widget" is a running sandboxed app, "document" is content opened by its handler. Then confirm the render — workspace_widgets_list shows the instance and workspace_widgets_logs reaches loadState: "ready"; a successful mount call alone proves nothing rendered.

widget_catalog

Lists the apps available to this account — each with the refId to pass to widget_instantiate, whether it is collaborative, and the document mimes it opens (for create_document).

ArgumentTypeNotes
querystringOptional filter over widgetType / title / mime.

Returns { count, widgets: [{ widgetType, refId, title, collab, opensMimes }], hint }.

create_document

Creates an empty project document (an ADR-0022 project folder) stamped with the mime that decides which app opens it. The returned contentId mounts with widget_instantiate and names the document's collab room.

ArgumentTypeNotes
mimestringThe project mime, e.g. application/vnd.robutler.eda+json. Pick one from widget_catalog's opensMimes.
namestringDocument name. Default Untitled.

Returns { contentId, room, projectMime, openUrl, handler, hint }.

widget_remix

Clones an app you can use into your own private, editable copy — the same operation as the UI Remix button. No publish entitlement needed; nothing is published and the original is untouched. Works on any app you can access: published, or shared with you. If the app reached you as a shared document (you hold access to the document, not the app), pass that document's id as via — the server verifies the chain (you can read the document, the app is its opener, and the document's author is entitled to the app).

ArgumentTypeNotes
refIdstringThe source widget id (a widget_catalog refId, a canvas item refId, or a widgetContentId).
viastringOptional shared-document delegation (see above).

Returns { widgetContentId, folderId, displayName, canPublish, hint }. Mount the copy with widget_instantiate(refId=widgetContentId), edit it with widget_put_files(folderId, …). canPublish says whether this account can later widget_publish it. Some kinds are not remixable (passive and native external widgets, and live canvas items) and return an error. See Publishing and remix.

widget_publish

Publishing-enabled accounts. Publishes a folder bundle as a public app. In one transaction it mints (or reuses) a dedicated agent for the app, wires each declared tool as a custom function, stamps the app's command interface, and upserts the catalog and post rows. Idempotent per (author, folder): republishing updates in place — and a republish is also how manifest / command-surface changes reach the widget row.

ArgumentTypeNotes
folderIdstringThe bundle folder id holding widget.json plus the entry HTML.

Returns { postId, agentId, widgetContentId, publicMcpAppUrl }. The publicMcpAppUrl is the app's own outbound MCP App manifest (/api/widgets/<postId>/mcp).

widget_snapshot

Publishing-enabled accounts. Cuts an immutable, content-addressed version of a working app and, when listed, creates or repoints a marketplace post. Idempotent: an unchanged tree (same Merkle hash as the last version) is a no-op that just clears the dirty flag.

ArgumentTypeNotes
workingWidgetIdstringThe working app's content row id.
listedbooleanList in the marketplace. Omit on an update to reuse the prior choice.
titlestringOptional title.
messagestringOptional commit-style version note.

Returns { versionId, widgetContentId, treeFolderId, treeHash, postId, deduped }. See Publishing and remix.

widget_download

Lists and reads the files of a bundle folder for local editing or debug. Walks the subtree and returns text inline (binary files are flagged, not inlined) up to a byte budget, so a bundle with multi-MB built assets never lands in the conversation whole.

ArgumentTypeNotes
folderIdstringThe bundle folder id.
maxFilesnumber1..1000, default 200.
maxBytesnumberInline text budget, 10000..2000000 bytes. Default 200000.
pathsstring[]Only these folder-relative files, or folder prefixes such as tests. Up to 100.

Returns { folderId, count, bytes, files: [{ id, path, mime, binary, text, bytes }], omitted?, hint? }. A file past the budget is still listed, with text: null and omitted: true; call again with paths set to the ones you need, or a larger maxBytes.

widget_fn_logs

Server-side debug: reads the recent custom-function invocations of an agent you own, with status, error code, and duration. Useful for diagnosing why a published tool is failing. A published app's functions run under the agent minted for it at publish time, which the publisher owns.

ArgumentTypeNotes
agentIdstringId or username of an agent you own.
functionNamestringOptional filter to one function.
limitnumber1..100, default 25.

Returns { agentId, count, invocations: [{ functionName, sourceSkill, status, errorCode, durationMs, createdAt }] }.

widget_dev_token

Mints a short-lived, least-privilege widget-dev Bearer so a locally running app can reach the portal during development. This token is for the local dev server only and is rejected at /mcp.

ArgumentTypeNotes
agentIdstringOptionally bind the token to one agent you own.
ttlMinutesnumber5..60, default 30.

Returns { token, portalUrl, agentId, expiresAt, scope }. Keep it on the dev machine and never commit it. See the security model.

Live-app control tools (workspace_*)

These drive apps you already have open in a live browser tab, the same command surface the in-workspace agent uses. A command only lands while the app is open in a live tab: there is no durable offline queue and the RPC times out (up to 5 minutes). They also answer for a standalone /w/ share view — pass the shared contentId (or share-<contentId>) where a workspace id is expected.

workspace_list_open

Lists the surfaces you currently have open in a live tab, with the apps open in each — workspaces (kind: "workspace") and standalone /w/ share views (kind: "share"). The result names the instance and identity that answered, which matters when more than one Robutler deployment is connected. No arguments.

Returns { instance, user, open: [{ workspaceId, title, tabIds, openWidgetItemIds, kind }] }.

workspace_widgets_list

Lists the apps on a workspace and the commands each understands (its agent-control surface). Static, so it works without a live tab. Each entry is flagged live when it is open in one of your tabs and therefore invokable now.

ArgumentTypeNotes
workspaceIdstringThe workspace id, or a share-surface id / contentId for a standalone /w/ view.

Returns { workspaceId, hasLiveTab, widgets: [{ itemId, ..., live }] }. See Agent command interface.

workspace_widgets_invoke

Runs a command on an app open in your live tab.

ArgumentTypeNotes
workspaceIdstringOptional — omitted, it is derived from the item id (item ids are unique across your open workspaces). Pass it only to disambiguate a short prefix.
itemIdstringThe app item id (from workspace_widgets_list), a unique prefix of it, or a shared contentId for a /w/ view.
namestringA declared command, or a builtin (below).
argsobjectCommand arguments.
timeoutMsnumber1000..300000, default 30000. Exports can be slow.
targetTabIdstringPin a stateful sequence to one tab (from a prior result). Omit to auto-route.

Builtin command names every app answers:

  • __screenshot: pixel-true PNG of the app, captured host-side (returned as an image). May first ask the user for a one-time screen-share grant on the tab.
  • __record: { durationMs, fps?, selector? }, records a canvas / video app to a stored clip, returns a content ref.
  • __capture: { durationMs?, fps? }, host-side Region Capture; a still, or a WebM clip with durationMs.
  • __getState, __describe: introspect the app.
  • __reload: reload the app iframe to pick up widget_put_files edits — no tab refresh needed. Sub-assets pinned with their own ?v= token need that token bumped too.

Returns { tabId, result }.

workspace_widgets_logs

Reads a deployed app instance's captured browser console logs plus load state (loading / ready / failed), including script errors, CSP blocks, and Permissions-Policy violations. Use it to debug why an app on the canvas is blank or broken. An item that is not a running app (content mounted as a file attachment) is refused outright with an explanation, rather than reporting loading forever. Routes to the live tab; requires the workspace open in a browser.

ArgumentTypeNotes
workspaceIdstringThe workspace id, or a share-surface id for a /w/ view.
itemIdstringThe app item id.
limitnumber1..1000, default 100.
timeoutMsnumber1000..60000, default 30000.

Returns { tabId, result }.

On this page