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.
Authoring tools (widget_*)
widget_scaffold
Returns a starter bundle to write locally: widget.json, index.html, and an example tool (tools/hello.js). It does not write anything server-side.
| Argument | Type | Notes |
|---|---|---|
name | string | App name. Non-kebab characters are normalized to -. |
Returns { name, 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 a later widget_publish / widget_snapshot sees the change. Creates parent subfolders as needed.
| Argument | Type | Notes |
|---|---|---|
folderId | string | The bundle folder id (from widget_download or a remix). |
files[] | array | Each entry: { path, text }. |
files[].path | string | Folder-relative, for example widget.json or tools/hello.js. |
files[].text | string | Full UTF-8 contents (replaces the file). |
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, 2 MB per file. The underlying writer also supports in-place edits (find / replace) for patching a large file without resending it.
Returns { folderId, results: [{ path, action: 'created' | 'updated', id }], hint }.
widget_publish
Publishes a folder bundle as an 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.
| Argument | Type | Notes |
|---|---|---|
folderId | string | The 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
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.
| Argument | Type | Notes |
|---|---|---|
workingWidgetId | string | The working app's content row id. |
listed | boolean | List in the marketplace. Omit on an update to reuse the prior choice. |
title | string | Optional title. |
message | string | Optional commit-style version note. |
Returns { versionId, widgetContentId, treeFolderId, treeHash, postId, deduped }. See Publishing and remix.
widget_remix
Forks a published app into your own copy: clones the bundle subtree onto your account, replays publish (minting a fresh dedicated agent), and stamps the remix lineage. Bumps the source post's remix count.
| Argument | Type | Notes |
|---|---|---|
sourcePostId | string | The source app's post id. |
Returns { newPostId, newAgentId, newWidgetContentId, ordinal }. Some kinds are not remixable (passive / native / system widgets, and live canvas items) and return an error.
widget_instantiate
Mounts an app on a workspace canvas and returns where to open it.
| Argument | Type | Notes |
|---|---|---|
refId | string | The app's content row id (widgetContentId). |
workspaceId | string | Existing workspace. A new one is created if omitted. |
name | string | Name for the new workspace. |
Returns { workspaceId, itemId, canvasUrl }.
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).
| Argument | Type | Notes |
|---|---|---|
folderId | string | The bundle folder id. |
maxFiles | number | 1..1000, default 200. |
Returns { folderId, count, files: [{ id, path, mime, binary, text }] }.
widget_fn_logs
Server-side debug: reads an agent's recent custom-function invocations with status, error code, and duration. Useful for diagnosing why a published tool is failing.
| Argument | Type | Notes |
|---|---|---|
agentId | string | The agent whose invocations to read. |
functionName | string | Optional filter to one function. |
limit | number | 1..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.
| Argument | Type | Notes |
|---|---|---|
agentId | string | Optionally bind the token to one agent you own. |
ttlMinutes | number | 5..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). Richer orchestration (durable queues, multi-tab) is on the way; see What's ready.
workspace_list_open
Lists the workspaces you currently have open in a live tab, with the apps open in each. These are the only places a command can be dispatched right now. No arguments.
Returns { open: [{ workspaceId, title, tabIds, openWidgetItemIds }] }.
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.
| Argument | Type | Notes |
|---|---|---|
workspaceId | string | The workspace id. |
Returns { workspaceId, hasLiveTab, widgets: [{ itemId, ..., live }] }. See Agent command interface.
workspace_widgets_invoke
Runs a command on an app open in your live tab. Requires the app to be open in a browser tab.
| Argument | Type | Notes |
|---|---|---|
workspaceId | string | The workspace id. |
itemId | string | The app item id (from workspace_widgets_list). |
name | string | A declared command, or a builtin (below). |
args | object | Command arguments. |
timeoutMs | number | 1000..300000, default 30000. Exports can be slow. |
Builtin command names:
__screenshot: PNG data URL of the app.__record:{ durationMs, fps?, selector? }, records a canvas / video app to a stored clip, returns a content ref.__capture:{ durationMs?, fps? }, host-side Region Capture of the app iframe (taint-free real footage). Needs the user to have started a capture session on the tab. Returns a PNG, or a WebM clip withdurationMs.__getState,__describe: introspect the app.
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. Routes to the live tab; requires the workspace open in a browser.
| Argument | Type | Notes |
|---|---|---|
workspaceId | string | The workspace id. |
itemId | string | The app item id. |
limit | number | 1..1000, default 100. |
timeoutMs | number | 1000..60000, default 30000. |
Returns { tabId, result }.
Related
- Quickstart: the tools in order, end to end.
- App authoring: bundle layout and
widget.json. - Publishing and remix: publish, snapshot, remix in depth.