5. The MCP server

ud mcp runs a Model Context Protocol server (protocol 2025-06-18) over stdio, named ui-designer (CMD-7).

5.1 Registration#

ud mcp runs a Model Context Protocol server (protocol 2025-06-18) over stdio, named ui-designer (CMD-7). ud mcp install adds it to the workspace’s .mcp.json, creating the file if needed and keeping other servers:

json
{
  "mcpServers": {
    "ui-designer": {
      "command": "ud",
      "args": ["mcp"]
    }
  }
}

When ud is not on the PATH outside VS Code terminals, install writes the absolute path of the stable ud launcher that the extension keeps up to date (CLI-001) instead of "ud". Options:

Option Meaning
ud mcp --file <path> default fileKey for calls that leave it out
ud mcp --read-only lists only read tools; mutating calls are refused (for review-only agents)
ud mcp --proposal <id> route every write to a proposal of the live editor (§6.5); used by the AI panel. Under --proposal the server refuses every registry command flagged writesFiles or network (CMD-17) and every URL input (upload_assets, generate_figma_design), whatever --allow says; create_new_file is refused too. Refused calls return unsupported with the hint “not allowed on a proposal”.
ud mcp --allow <ids> allowlist: the tools and registry command ids the server will run in this process (comma-separated, read for every read tool, globs such as node.*). Everything not listed is refused with unsupported. The panel passes it on every run (§6.3); without it the server runs whatever the plan allows.
ud mcp --as <name> signing actor (else UD_ACTOR, Claude inside Claude Code, git user; CMD-29)
ud mcp install [--user] write the entry to .mcp.json (or to the user’s Claude Code settings)
ud mcp install --proposal auto opt in to reviewable writes for external agents: the entry gets --proposal auto, and each MCP session’s writes go to one proposal that the editor opens on the first write and the user accepts or discards in the AI panel (§6.5). Headless (no editor), auto falls back to live writes under the file lock and says so in whoami.

Claude Code shows the tools as mcp__ui-designer__<tool>. Other clients (Claude Desktop, Cursor, VS Code’s own MCP support) use the same command.

5.2 Tools#

tools/list returns the supported Figma tools with their input schemas, property for property (CMD-1, CMD-8), followed by the native tools. Two deliberate relaxations of Figma’s schemas: fileKey has no ^[0-9a-zA-Z]{22,128}$ pattern and is optional (CMD-2), and nodeId accepts the forms of CMD-3. Extra optional parameters are allowed by CMD-8 and are marked "x-ud": true in the schema.

Tool Mutates Plan M Notes
whoami no any 0.1 actor, plan (ud::local), seat, proposal mode
get_metadata no any 0.1 sparse XML; pages when no nodeId; prepends the live selection like Figma
use_figma yes paid 0.1 Plugin API script, atomic (CMD-10 – CMD-12); code ≤ 50 000 chars
create_new_file yes (new file; writesFiles) paid 0.1 fileName, editorType: "design"; returns the path as fileKey; refused under --proposal
get_screenshot no any 0.2 maxDimension, contentsOnly, enableBase64Response; result path + loopback url or url: null (§5.9)
upload_assets yes (network with URLs) paid 0.2 paths (local files) or URLs → <name>.design.assets/; URLs refused under --proposal; headless one-shot needs paths (§5.9)
download_assets no (writesFiles) any 0.2 writes files, returns path and loopback url or url: null (§5.9); refused under --proposal
get_variable_defs no any 0.4 name → value for the current mode
search_design_system no any 0.4 queries: [{entity, query}], includeLibraryKeys
get_libraries no any 0.4 libraries_added_to_file (subscribed), libraries_available_to_add (available)
get_motion_context no any 0.5 keyframe tracks, CSS and motion.dev snippets
get_design_context no any 0.6 code with the code map applied, screenshot, assets; a read, so free like every read tool (LIC-5)
get_code_connect_map, get_code_connect_suggestions, get_context_for_code_connect, list_file_components_for_code_connect no any 0.6 the code map (DEV-4)
add_code_connect_map, send_code_connect_mappings yes paid 0.6 write code-map entries (events in the file)
generate_figma_design yes (network) paid 0.8 capture a running page into frames (EXP-6) with headless Chromium; refused under --proposal (the panel attaches a screenshot instead, §9.1)
ud_run per command per command 0.1 {command, params, fileKey?, dryRun?, ifVersion?}; any registry command (CMD-19), including tree, inspect, system.digest, selection.set, diff, comment.add. Commands flagged writesFiles (exports, codegen, token export, render --out) or network are refused under --proposal, and --allow applies per command id
ud_apply yes paid 0.1 {actions: [{command, params, ref?}], …}; one transaction (CMD-28)
ud_help no any 0.1 {topic}: a command id, a tool name, commands, plugin-api, udx, selectors
ud_render no any 0.2 ud render with all its options (mode, variant, region, format, scale, prototype state)
ud_lint no any 0.6 {nodeId?, rules?}; findings as JSON (CMD-36)

A tool that the installed milestone does not have yet is not listed. A Figma tool that UI Designer cannot serve is never listed (CMD-6). Under --proposal, tools that are always refused (create_new_file, download_assets, generate_figma_design) are not listed either, and the schema of upload_assets drops its URL form; under --allow, only the listed tools appear.

5.3 Resources#

URI Content MIME
ud://<path>.design?resource=system the design-system digest of that file (ud system, AI-3) text/plain
ud://<path>.design?resource=pages pages and top-level frames application/json
ud://<path>.design?node-id=<id> ud inspect of a node application/yaml
ud://plugin-api/coverage ud plugin-api table (CMD-14) text/markdown
ud://plugin-api/ud-plugin-api.d.ts typings application/typescript
skill://ui-designer/<skill>/SKILL.md, skill://ui-designer/<skill>/references/<file>, …/scripts/<file> the skills of §3 text/markdown, text/javascript
skill://ui-designer/index.json list of skills with name, description, version application/json

resources/list lists one ?resource=system entry per .design file in the workspace (up to 50). Resource subscriptions are supported for ?resource=system: a change to the design system sends notifications/resources/updated.

Clients that cannot read resources reach the same content through tools: ud_run system.digest, ud_help plugin-api, and ud_help skill:ui-designer.

5.4 Prompts#

Prompt Arguments Produces
create_design_system_rules clientFrameworks, clientLanguages (as Figma’s) instructions to write a rules file (CLAUDE.md section or .cursor/rules/…) describing the design system and how code should use its tokens and components, built from ud system and the code map
ud_design_screen description, fileKey?, page? the design loop of §4 as a prompt, for clients without skills
ud_review nodeId, fileKey? the review procedure of §3.7 as a prompt

5.5 Finding the live editor#

ud mcp is a long-lived process; it does not hold the document. For every call it resolves the file and then the bridge, the same way every ud command does (CMD-27):

  1. Resolve fileKey (path, doc-… id searched among the workspace’s .design files, ud:// link, or the --file default, or the only open design).
  2. Look in the bridge folder — $XDG_RUNTIME_DIR/ui-designer, or ui-designer-<uid> in the temporary folder; UD_BRIDGE_DIR overrides — readable only by the user. Each running VS Code window with the extension leaves a file there with the address of its local socket (a Unix socket or a named pipe), a random token, and the paths of the designs it has open. Nothing listens beyond the loopback interface: the only TCP listener is the asset and screenshot server of §5.9, bound to 127.0.0.1 (NFR-4).
  3. If a window has the file open, send the command over that socket with the token. The editor queues it with the user’s own edits, applies it, flashes the changed nodes (UI-7) and answers. Reads see unsaved state.
  4. Otherwise run headless: load the file with the same document core, take the file lock, apply, write, and release the lock.

The bridge is re-resolved per call, so opening or closing the editor during an agent session just switches mode. ud_run where reports which mode the last call used. ARC-001 specifies the bridge protocol.

5.6 Authentication and licence#

  • No login for the MCP server. It is a local process of the user, reached over stdio by the user’s client. The bridge token protects the editor’s socket from other local users.
  • Licence. The plan is the one of the extension on this machine (LIC-2). ud mcp is gated exactly like ud, command for command: every read tool — get_metadata, get_screenshot, get_design_context, get_variable_defs, search_design_system, get_libraries, get_motion_context, the get_*/list_* code-map tools, ud_render, ud_lint, ud_help, download_assets, whoami and every read command through ud_run — is free (LIC-5). Mutating calls need the trial or a paid plan; on the Free plan they return isError with code licence (exit 4 from ud) and a hint (“UI Designer Pro unlocks editing; run ‘UI Designer: Sign In’”). whoami reports seat: "view" on Free, so a skill can tell before it starts. Neither ud mcp nor the language model tools of §10 are “AI features” in the sense of LIC-2: that term means the AI panel and the quick actions only, and those need the paid plan or the trial as a whole (§6.7). Agents the user runs through ud mcp or VS Code chat pay nothing beyond what ud itself charges for the same mutation.
  • Live editor decides. When the change goes through the bridge, the editor checks the licence; headless, ud checks the same cached licence signature (offline grace, LIC-4).

5.7 Limits#

Limit Default Configurable
use_figma time / memory / nodes created 30 s / 256 MB / 100 000 (CMD-11) timeout via ud use_figma --timeout; not over MCP
use_figma code length 50 000 characters (as Figma) no
Text in one tool result 100 000 characters; longer get_metadata is cut at a node boundary with a hint to pass a nodeId or depth UD_MCP_MAX_TEXT
Screenshot size maxDimension default 1024, clamped to 8192 (the clamp is reported in the result) no
Concurrency reads in parallel; mutating calls on one document are queued and run one at a time —
Queue depth 32 pending mutating calls per document; more returns busy —
Rate none beyond the queue —
Speed CMD-31: reads < 150 ms via the bridge, mutations < 250 ms, use_figma start-up < 50 ms —

5.8 Errors#

Errors are tool results with isError: true (CMD-30). The text starts with a code, then a message and a hint; structuredContent carries the same as JSON:

json
{
  "code": "command",
  "exit": 1,
  "message": "layoutSizingHorizontal: FILL can only be set on children of auto-layout frames",
  "hint": "Append the node to an auto-layout frame first, then set FILL.",
  "script": { "line": 14, "column": 3, "name": "Error" },
  "safeToRetryWithoutCanvasRead": true,
  "documentVersion": 4182
}
Code Exit When Agent’s next step
usage 2 bad parameters, schema violation fix the call
command 1 the command or script failed (incl. UnsupportedApiError) fix and retry; nothing was applied
conflict 3 ifVersion older than the document; a proposal was discarded under the agent re-read, then retry
licence 4 mutation without a paid plan or trial stop and tell the user
not_found 5 file, node, command or tool not found check ids with get_metadata
unsupported 6 a Figma tool or editor type UI Designer does not serve; a tool, command or input form outside --allow or refused under --proposal (§5.1) use the alternative named in the message; on a proposal, leave the file-writing step to the user
busy 1 mutating queue full wait for earlier calls
stopped 1 the user pressed Stop on the agent status item or ran “UI Designer: Stop Agent” (UI-7) stop; do not retry

5.9 Asset and screenshot results#

get_screenshot, ud_render, download_assets and upload_assets deal in files. Their results name the file and, when something can serve it, a URL; there is no file:// URL anywhere in the interface.

Situation get_screenshot / ud_render / download_assets result upload_assets
The call went through the bridge (editor open) { path, url }: path is the PNG on disk; url is a single-use loopback URL served by the extension host (http://127.0.0.1:<port>/…) returns loopback POST URLs, one per asset, served by the extension host; paths are accepted too
ud mcp headless (no editor), server still running { path, url }: the URL is served by the ud mcp process for as long as it runs as above, served by ud mcp
One-shot headless ud get_screenshot / ud render / ud download_assets { path, url: null }: the process exits before anyone could fetch, so nothing is served ud upload_assets needs --paths; a URL-only call exits 2 (usage) with the hint to pass paths

Rules that hold for every URL: loopback only (127.0.0.1, never 0.0.0.0), a 128-bit single-use token in the path, a 10-minute lifetime, a Host header that must match, requests with an Origin header rejected, 10 MB per asset. The server is specified in ARC-001 §9.6 and the hardening in SRS NFR-4. Figma’s skills, which curl the screenshot URL or POST to the upload URL, therefore work unchanged while a server runs; our skills tell the agent to prefer path (or the inline image) and to treat url: null as “read the file”. In the AI panel enableBase64Response is forced on, so the agent never needs the URL at all.