2026-05-22 12:00:44 +00:00
---
title: MCP Server
description: Connect Claude Code, Cursor, Windsurf, and other MCP clients to OpenPencil for AI-assisted design inspection and editing.
---
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
# MCP Server
2026-04-13 07:11:23 +00:00
OpenPencil includes an MCP (Model Context Protocol) server that lets AI coding tools — Claude Code, Cursor, Windsurf, etc. — read and modify designs through the running app.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-07-25 18:29:03 +00:00
Two transports: **stdio** for MCP clients, and **Streamable HTTP** for browser extensions and scripts. On macOS and Linux, local clients prefer a private Unix domain socket; Windows and unavailable sockets fall back to localhost TCP.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-09-15 14:12:31 +00:00
Tool definitions own native Valibot input schemas, execution/mutation metadata, capabilities, and optional interface exposure exclusions. Tools are included by default; `exposure: { mcp: false, ai: false, webmcp: false }` can exclude them independently from each adapter. Exposure does not bypass execution support or user permissions: WebMCP still requires supported execution and explicit Off, Inspect, or Edit access. AI and MCP consume the same schema through Standard Schema; WebMCP derives its JSON Schema from that input. Numeric strings are accepted consistently across adapters, while non-finite values are rejected. Programmatic integrations use MCP SDK v2; custom tools replace the former `params` /`ParamDef` contract with `input` and execution metadata.
2026-09-15 07:55:27 +00:00
feat(settings): configure tool access, MCP failures, and step limits
* feat(settings): configure tool access and agent step limits
Built-in AI exposed only a hardcoded subset of the tool registry, and the
maximum agent steps was a constant, so users could neither enable
extended tools such as create_component nor adjust long-running tasks.
Built-in AI and the local MCP server now keep independent, locally saved
tool permissions over one shared catalog, with searchable read-only and
side-effect groups and per-target defaults. Chat settings gain a validated
maximum-steps field whose captured value drives the stop condition,
remaining-step warnings, and limit detection for each message.
Tool access, the local server, browser access, and MCP connections are
grouped under a single Automation settings page.
Closes #573
Closes #584
* refactor(settings): split automation into MCP and Tool access pages
The Automation page mixed a permission matrix with server endpoints behind
a Tools/Connections switch, and the view switch was indistinguishable from
the provider switch. The nested scroll region showed three of 110 tools.
Rename the MCP-facing page to MCP and give tool permissions their own Tool
access page. The page owns a fixed toolbar for the target, count, defaults,
and search, so the list uses the full dialog body and no row is clipped.
* fix(automation): explain MCP startup failures with localized guidance
Every startup failure collapsed into "MCP server did not become healthy":
the spawn layer recorded the real error but the runtime discarded it, and
health probes could not distinguish a rejected token from a missing server.
The message also surfaced raw English text as the alert heading.
Classify failures by reason (not installed, denied command, early exit,
startup timeout, rejected token, unexpected response, unreachable) and
render translated heading and guidance from the catalog, keeping captured
stderr or HTTP status as labeled diagnostic detail.
* refactor(ui): share one collapsible disclosure primitive
Six features each wired Reka's collapsible with their own motion classes and
one settings-only theme token, so the same interaction drifted in spacing,
icon size, and reduced-motion handling.
Add AppCollapsible with a family theme and move the settings disclosure and
the model editor's advanced settings onto it. Chat and frame-preset call
sites keep their distinct visuals for a follow-up.
* fix(automation): explain MCP failures with localized details
The failure alert carried raw English error text as its heading, and the
diagnostic payload sat in a sibling block outside the alert with no
relationship to it.
Classify failures by reason, render translated heading and guidance from
the catalog, and keep the payload in a collapsible inside the alert, which
unmounts while collapsed so the live region announces only the summary.
Add a copy action for issue reports.
Find the executable where a graphical launch can: extend PATH with the
common global bin directories before the lookup and report the searched
directories as diagnostic detail.
* fix(automation): keep MCP failure details out of reasons already explained
An unreachable address and a rejected token already name their cause in the
translated guidance, so repeating it under Details added noise. Details now
carry only output the summary cannot: stderr, HTTP status, or an unknown
error message.
* test(settings): browse every MCP failure reason in Storybook
The failure copy lived inside the settings panel, so reviewing the eight
reasons meant reproducing each failure and the mapping could only be
checked through the panel's dependencies.
Extract MCPFailureAlert, which owns the reason-to-copy mapping, detail
visibility, copy action, and restart action, and add a story covering
every reason plus the collapsed-details behavior.
* fix(ui): order alert details above the recovery actions
The alert rendered its action buttons before the details slot, so the
collapsible explanation of a failure appeared under the controls it
explains. Details now render directly after the description.
* fix(automation): correct MCP failure classification and detail
Review follow-ups on the failure diagnostics.
Only 401 and 403 mean the server refused our token; any other status now
reports an unexpected response instead of telling the user to replace a
token that was never the problem.
The install hint rendered the whole diagnostic detail as its package
argument, so searched directories appeared inside the install command.
The install target is now a domain constant and the searched directories
stay as detail, which not-installed failures surface again since they are
the actionable desktop diagnostic.
Exited failures also record the process exit code and signal so copied
diagnostics stay conclusive when stderr is empty. The bundled PATH test
now covers the append branch instead of only the unchanged path.
* feat(settings): accept custom values for presets and retention
Retention was a closed set of three counts while the AI step limit was a
free number, so two bounded numeric preferences looked and behaved
differently for no product reason.
Add a shared preset-or-custom field: presets stay one click, the escape
hatch reveals a validated numeric field, and the model carries only the
resolved number. Diagnostics retention becomes a bounded number (50 to
20,000) with the presets as shortcuts, and the hardcoded revalidation in
the panel is replaced by one domain resolver.
* fix(settings): label the preset and custom fields
Replacing the labeled provider field with the shared control left the AI
step limit as a bare select with a detached hint paragraph, outside the
settings group, so nothing on screen said what the number meant. The
accessibility name came from aria-label, which is why behavior tests
passed while the panel was unreadable.
Move both controls into labeled settings rows with their descriptions, and
give the revealed field its own accessible name so the two controls in one
row differ. The specs now assert the control lives inside the row that
names it, which is the check that would have caught this.
* fix(mcp): allow the desktop app origin by default
A server started manually bound the port and answered curl but the app
webview could not use it: no CORS origin was configured, so the browser
blocked every fetch and the app reported the server as unhealthy. The
workaround required an undocumented environment variable.
Allow the desktop app origins by default, accept a comma-separated
override, and document the default in the CLI help and the security notes.
Authenticated requests still need the bearer token, and browsers set Origin
themselves, so only the app webview can present these origins.
* fix(settings): address review findings on the new controls
Copy details awaited nothing and confirmed the copy before the write
finished. VueUse never rejects and falls back to a legacy write, so the
await is what makes the confirmation honest rather than an error branch.
The preset field only left custom mode when a preset arrived; a non-preset
value assigned from the owner left the select showing a value absent from
its options with the field still hidden. The watcher now follows the model
in both directions.
The story play functions queried the revealed field by the row label, which
Testing Library matches as a whole string, so those interactions could not
find it. The Storybook smoke assertion also assumed a button or tab, which
skipped every story built from other primitives.
2026-09-17 20:55:58 +00:00
## Tool access settings
Use **Settings → Tool access** (select **Local MCP** ) to search and toggle the local server's tools, individually or by read-only/side-effect group. Group switches affect all group members, even during search. **Restore defaults** enables the configurable MCP tools again. Existing MCP preferences are preserved separately from the **Built-in AI** settings.
Restart the MCP server, then reconnect stdio clients, to apply changes. For an externally managed server, restart its owning process. The list reflects the tools discovered from the server; disabling a dedicated tool does not prevent an enabled script tool from performing the same operation. These switches are not a sandbox and do not configure remote MCP servers or WebMCP.
2026-09-15 13:34:05 +00:00
## Browser-native WebMCP (experimental) {#webmcp}
2026-09-13 21:54:12 +00:00
feat(settings): configure tool access, MCP failures, and step limits
* feat(settings): configure tool access and agent step limits
Built-in AI exposed only a hardcoded subset of the tool registry, and the
maximum agent steps was a constant, so users could neither enable
extended tools such as create_component nor adjust long-running tasks.
Built-in AI and the local MCP server now keep independent, locally saved
tool permissions over one shared catalog, with searchable read-only and
side-effect groups and per-target defaults. Chat settings gain a validated
maximum-steps field whose captured value drives the stop condition,
remaining-step warnings, and limit detection for each message.
Tool access, the local server, browser access, and MCP connections are
grouped under a single Automation settings page.
Closes #573
Closes #584
* refactor(settings): split automation into MCP and Tool access pages
The Automation page mixed a permission matrix with server endpoints behind
a Tools/Connections switch, and the view switch was indistinguishable from
the provider switch. The nested scroll region showed three of 110 tools.
Rename the MCP-facing page to MCP and give tool permissions their own Tool
access page. The page owns a fixed toolbar for the target, count, defaults,
and search, so the list uses the full dialog body and no row is clipped.
* fix(automation): explain MCP startup failures with localized guidance
Every startup failure collapsed into "MCP server did not become healthy":
the spawn layer recorded the real error but the runtime discarded it, and
health probes could not distinguish a rejected token from a missing server.
The message also surfaced raw English text as the alert heading.
Classify failures by reason (not installed, denied command, early exit,
startup timeout, rejected token, unexpected response, unreachable) and
render translated heading and guidance from the catalog, keeping captured
stderr or HTTP status as labeled diagnostic detail.
* refactor(ui): share one collapsible disclosure primitive
Six features each wired Reka's collapsible with their own motion classes and
one settings-only theme token, so the same interaction drifted in spacing,
icon size, and reduced-motion handling.
Add AppCollapsible with a family theme and move the settings disclosure and
the model editor's advanced settings onto it. Chat and frame-preset call
sites keep their distinct visuals for a follow-up.
* fix(automation): explain MCP failures with localized details
The failure alert carried raw English error text as its heading, and the
diagnostic payload sat in a sibling block outside the alert with no
relationship to it.
Classify failures by reason, render translated heading and guidance from
the catalog, and keep the payload in a collapsible inside the alert, which
unmounts while collapsed so the live region announces only the summary.
Add a copy action for issue reports.
Find the executable where a graphical launch can: extend PATH with the
common global bin directories before the lookup and report the searched
directories as diagnostic detail.
* fix(automation): keep MCP failure details out of reasons already explained
An unreachable address and a rejected token already name their cause in the
translated guidance, so repeating it under Details added noise. Details now
carry only output the summary cannot: stderr, HTTP status, or an unknown
error message.
* test(settings): browse every MCP failure reason in Storybook
The failure copy lived inside the settings panel, so reviewing the eight
reasons meant reproducing each failure and the mapping could only be
checked through the panel's dependencies.
Extract MCPFailureAlert, which owns the reason-to-copy mapping, detail
visibility, copy action, and restart action, and add a story covering
every reason plus the collapsed-details behavior.
* fix(ui): order alert details above the recovery actions
The alert rendered its action buttons before the details slot, so the
collapsible explanation of a failure appeared under the controls it
explains. Details now render directly after the description.
* fix(automation): correct MCP failure classification and detail
Review follow-ups on the failure diagnostics.
Only 401 and 403 mean the server refused our token; any other status now
reports an unexpected response instead of telling the user to replace a
token that was never the problem.
The install hint rendered the whole diagnostic detail as its package
argument, so searched directories appeared inside the install command.
The install target is now a domain constant and the searched directories
stay as detail, which not-installed failures surface again since they are
the actionable desktop diagnostic.
Exited failures also record the process exit code and signal so copied
diagnostics stay conclusive when stderr is empty. The bundled PATH test
now covers the append branch instead of only the unchanged path.
* feat(settings): accept custom values for presets and retention
Retention was a closed set of three counts while the AI step limit was a
free number, so two bounded numeric preferences looked and behaved
differently for no product reason.
Add a shared preset-or-custom field: presets stay one click, the escape
hatch reveals a validated numeric field, and the model carries only the
resolved number. Diagnostics retention becomes a bounded number (50 to
20,000) with the presets as shortcuts, and the hardcoded revalidation in
the panel is replaced by one domain resolver.
* fix(settings): label the preset and custom fields
Replacing the labeled provider field with the shared control left the AI
step limit as a bare select with a detached hint paragraph, outside the
settings group, so nothing on screen said what the number meant. The
accessibility name came from aria-label, which is why behavior tests
passed while the panel was unreadable.
Move both controls into labeled settings rows with their descriptions, and
give the revealed field its own accessible name so the two controls in one
row differ. The specs now assert the control lives inside the row that
names it, which is the check that would have caught this.
* fix(mcp): allow the desktop app origin by default
A server started manually bound the port and answered curl but the app
webview could not use it: no CORS origin was configured, so the browser
blocked every fetch and the app reported the server as unhealthy. The
workaround required an undocumented environment variable.
Allow the desktop app origins by default, accept a comma-separated
override, and document the default in the CLI help and the security notes.
Authenticated requests still need the bearer token, and browsers set Origin
themselves, so only the app webview can present these origins.
* fix(settings): address review findings on the new controls
Copy details awaited nothing and confirmed the copy before the write
finished. VueUse never rejects and falls back to a legacy write, so the
await is what makes the confirmation honest rather than an error branch.
The preset field only left custom mode when a preset arrived; a non-preset
value assigned from the owner left the select showing a value absent from
its options with the field still hidden. The watcher now follows the model
in both directions.
The story play functions queried the revealed field by the row label, which
Testing Library matches as a whole string, so those interactions could not
find it. The Storybook smoke assertion also assumed a button or tab, which
skipped every story built from other primitives.
2026-09-17 20:55:58 +00:00
WebMCP is **off by default** . Open **Settings → MCP → WebMCP** and choose **Inspect** for read-only access or **Edit** to also allow scoped, undoable changes. **Off** unregisters all browser tools; changing modes revokes the previous registrations immediately. This preference is independent of local MCP authentication, tool switches, and outbound connections.
2026-09-15 13:34:05 +00:00
For local testing, use a Chrome version exposing `document.modelContext` , enable `chrome://flags/#enable-webmcp-testing` , and relaunch the browser. Open a document, enable access in Settings, and connect a WebMCP-capable browser agent or the [Model Context Tool Inspector ](https://developer.chrome.com/docs/ai/webmcp ). Settings shows browser support and registration status. See the [Chrome WebMCP guide ](https://developer.chrome.com/docs/ai/webmcp ) for current availability.
In supported browsers, OpenPencil registers the selected reviewed set of tools directly in the workspace. Browser agents can inspect nodes, JSX, variables, components, and design patterns, and edit existing layer properties and variable values without installing or connecting an MCP server.
2026-09-13 21:54:12 +00:00
Tools target the document and page active when the call starts. Switching tabs does not redirect an in-flight call. Closing the workspace unregisters the tools. Tool inputs are validated and large inspection results require a narrower query. Oversized editing results are omitted with a committed-edit notice rather than reporting a successful edit as failed.
Edits to geometry, paints, layout, text, and variable bindings/values commit synchronously as individual undoable operations. Failed edits roll back, and undo targets the original document/page even after a page switch. Cancellation prevents an edit from starting; cancellation after commit does not reverse it. Font loading finishes separately without holding a mutation transaction open. Atomic editing currently requires a document with at most 10,000 nodes and variables combined; this shared limit also applies when the same editing tools run through app AI/MCP.
This surface does **not** expose structural creation/deletion, arbitrary JavaScript/JSX execution, image loading, filesystem operations, or credentials. Those tools retain their existing AI/MCP paths. WebMCP is an evolving browser proposal, not universally available; unsupported browsers continue to use OpenPencil normally. The stdio and HTTP integrations below remain independent.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
## Install
```sh
2026-05-19 14:58:08 +00:00
npm install -g @open -pencil/mcp
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
```
## Stdio (Claude Code, Cursor, etc.)
2026-07-25 18:29:03 +00:00
The stdio server discovers the running OpenPencil app automatically. It prefers the app's Unix domain socket on macOS and Linux and falls back to localhost TCP when needed. Make sure the desktop app is open with a document loaded.
2026-05-19 14:58:08 +00:00
### Claude Code
Install the MCP package and register it with Claude Code:
```sh
npm install -g @open -pencil/mcp
claude mcp add --scope user open-pencil -- openpencil-mcp
```
Check the connection:
```sh
claude mcp list
```
Claude Code asks before using each MCP tool unless you allow the server's tools. To auto-approve OpenPencil tools only, add this to `~/.claude/settings.json` :
```json
{
"permissions": {
"allow": ["mcp__open-pencil__*"]
}
}
```
This is narrower than `--permission-mode bypassPermissions` , which skips prompts for every tool. You can also approve tools interactively from Claude's prompt by choosing “Yes, and don't ask again”.
Example prompt:
```text
Use the open-pencil MCP server to inspect the current page and create a small hero section on the canvas.
```
### Other MCP clients
Add to your MCP config (for example `.cursor/mcp.json` ):
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
```json
{
"mcpServers": {
"open-pencil": {
"command": "openpencil-mcp"
}
}
}
```
Or run from source without installing:
::: code-group
```json [Bun]
{
"mcpServers": {
"open-pencil": {
"command": "bun",
2026-04-13 07:11:23 +00:00
"args": ["/path/to/open-pencil/packages/mcp/src/stdio.ts"]
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
}
}
}
```
```json [Node.js]
{
"mcpServers": {
"open-pencil": {
"command": "npx",
2026-04-13 07:11:23 +00:00
"args": ["tsx", "/path/to/open-pencil/packages/mcp/src/stdio.ts"]
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
}
}
}
```
:::
## HTTP
For browser extensions, scripts, CI, or any HTTP client:
```sh
openpencil-mcp-http
```
2026-04-13 07:11:23 +00:00
Or from source: `bun packages/mcp/src/index.ts` / `npx tsx packages/mcp/src/index.ts`
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-07-25 18:29:03 +00:00
Security defaults:
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-07-25 18:29:03 +00:00
- Unix socket and discovery files are created with owner-only permissions on macOS and Linux.
- TCP binds to `127.0.0.1` and uses port 7600 by default.
- Authentication is enabled by default with a generated token stored in the private discovery file.
- `eval` is disabled.
- File operations are limited to `OPENPENCIL_MCP_ROOT` (defaults to the current working directory) and reject symlink escapes.
feat(settings): configure tool access, MCP failures, and step limits
* feat(settings): configure tool access and agent step limits
Built-in AI exposed only a hardcoded subset of the tool registry, and the
maximum agent steps was a constant, so users could neither enable
extended tools such as create_component nor adjust long-running tasks.
Built-in AI and the local MCP server now keep independent, locally saved
tool permissions over one shared catalog, with searchable read-only and
side-effect groups and per-target defaults. Chat settings gain a validated
maximum-steps field whose captured value drives the stop condition,
remaining-step warnings, and limit detection for each message.
Tool access, the local server, browser access, and MCP connections are
grouped under a single Automation settings page.
Closes #573
Closes #584
* refactor(settings): split automation into MCP and Tool access pages
The Automation page mixed a permission matrix with server endpoints behind
a Tools/Connections switch, and the view switch was indistinguishable from
the provider switch. The nested scroll region showed three of 110 tools.
Rename the MCP-facing page to MCP and give tool permissions their own Tool
access page. The page owns a fixed toolbar for the target, count, defaults,
and search, so the list uses the full dialog body and no row is clipped.
* fix(automation): explain MCP startup failures with localized guidance
Every startup failure collapsed into "MCP server did not become healthy":
the spawn layer recorded the real error but the runtime discarded it, and
health probes could not distinguish a rejected token from a missing server.
The message also surfaced raw English text as the alert heading.
Classify failures by reason (not installed, denied command, early exit,
startup timeout, rejected token, unexpected response, unreachable) and
render translated heading and guidance from the catalog, keeping captured
stderr or HTTP status as labeled diagnostic detail.
* refactor(ui): share one collapsible disclosure primitive
Six features each wired Reka's collapsible with their own motion classes and
one settings-only theme token, so the same interaction drifted in spacing,
icon size, and reduced-motion handling.
Add AppCollapsible with a family theme and move the settings disclosure and
the model editor's advanced settings onto it. Chat and frame-preset call
sites keep their distinct visuals for a follow-up.
* fix(automation): explain MCP failures with localized details
The failure alert carried raw English error text as its heading, and the
diagnostic payload sat in a sibling block outside the alert with no
relationship to it.
Classify failures by reason, render translated heading and guidance from
the catalog, and keep the payload in a collapsible inside the alert, which
unmounts while collapsed so the live region announces only the summary.
Add a copy action for issue reports.
Find the executable where a graphical launch can: extend PATH with the
common global bin directories before the lookup and report the searched
directories as diagnostic detail.
* fix(automation): keep MCP failure details out of reasons already explained
An unreachable address and a rejected token already name their cause in the
translated guidance, so repeating it under Details added noise. Details now
carry only output the summary cannot: stderr, HTTP status, or an unknown
error message.
* test(settings): browse every MCP failure reason in Storybook
The failure copy lived inside the settings panel, so reviewing the eight
reasons meant reproducing each failure and the mapping could only be
checked through the panel's dependencies.
Extract MCPFailureAlert, which owns the reason-to-copy mapping, detail
visibility, copy action, and restart action, and add a story covering
every reason plus the collapsed-details behavior.
* fix(ui): order alert details above the recovery actions
The alert rendered its action buttons before the details slot, so the
collapsible explanation of a failure appeared under the controls it
explains. Details now render directly after the description.
* fix(automation): correct MCP failure classification and detail
Review follow-ups on the failure diagnostics.
Only 401 and 403 mean the server refused our token; any other status now
reports an unexpected response instead of telling the user to replace a
token that was never the problem.
The install hint rendered the whole diagnostic detail as its package
argument, so searched directories appeared inside the install command.
The install target is now a domain constant and the searched directories
stay as detail, which not-installed failures surface again since they are
the actionable desktop diagnostic.
Exited failures also record the process exit code and signal so copied
diagnostics stay conclusive when stderr is empty. The bundled PATH test
now covers the append branch instead of only the unchanged path.
* feat(settings): accept custom values for presets and retention
Retention was a closed set of three counts while the AI step limit was a
free number, so two bounded numeric preferences looked and behaved
differently for no product reason.
Add a shared preset-or-custom field: presets stay one click, the escape
hatch reveals a validated numeric field, and the model carries only the
resolved number. Diagnostics retention becomes a bounded number (50 to
20,000) with the presets as shortcuts, and the hardcoded revalidation in
the panel is replaced by one domain resolver.
* fix(settings): label the preset and custom fields
Replacing the labeled provider field with the shared control left the AI
step limit as a bare select with a detached hint paragraph, outside the
settings group, so nothing on screen said what the number meant. The
accessibility name came from aria-label, which is why behavior tests
passed while the panel was unreadable.
Move both controls into labeled settings rows with their descriptions, and
give the revealed field its own accessible name so the two controls in one
row differ. The specs now assert the control lives inside the row that
names it, which is the check that would have caught this.
* fix(mcp): allow the desktop app origin by default
A server started manually bound the port and answered curl but the app
webview could not use it: no CORS origin was configured, so the browser
blocked every fetch and the app reported the server as unhealthy. The
workaround required an undocumented environment variable.
Allow the desktop app origins by default, accept a comma-separated
override, and document the default in the CLI help and the security notes.
Authenticated requests still need the bearer token, and browsers set Origin
themselves, so only the app webview can present these origins.
* fix(settings): address review findings on the new controls
Copy details awaited nothing and confirmed the copy before the write
finished. VueUse never rejects and falls back to a legacy write, so the
await is what makes the confirmation honest rather than an error branch.
The preset field only left custom mode when a preset arrived; a non-preset
value assigned from the owner left the select showing a value absent from
its options with the field still hidden. The watcher now follows the model
in both directions.
The story play functions queried the revealed field by the row label, which
Testing Library matches as a whole string, so those interactions could not
find it. The Storybook smoke assertion also assumed a button or tab, which
skipped every story built from other primitives.
2026-09-17 20:55:58 +00:00
- Only the desktop app's own origin (`tauri://localhost` and its `http(s)://tauri.localhost` variants) is allowed by default, so a server you start yourself works from the app without extra configuration. Set `OPENPENCIL_MCP_CORS_ORIGIN` to a comma-separated list to allow other origins, such as a worktree dev server.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-07-25 18:29:03 +00:00
Set `PORT=0` to disable TCP on macOS and Linux. Windows requires TCP. Set `OPENPENCIL_MCP_SOCKET` to override the Unix socket path, or `OPENPENCIL_MCP_DISCOVERY_PATH` to override the discovery file location. To provide a stable token, set `OPENPENCIL_MCP_AUTH_TOKEN` ; an explicitly empty value disables authentication and should only be used with a trusted local socket.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
2026-07-25 18:29:03 +00:00
Endpoints are available over both active transports:
- `GET /health` — server and app connection status; never returns the auth token.
- `POST /rpc` — authenticated live-app automation.
- `POST /mcp` — MCP Streamable HTTP. Sessions use the `mcp-session-id` header.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
## Workflow
2026-07-03 14:05:04 +00:00
1. **Discover targets** — call `list_documents` first when more than one document or page may be open. It returns stable `document_id` and page IDs.
2. **Open** — `open_file` to load an existing `.fig` , or `new_document` for a blank canvas. These return target metadata for the opened or created document.
3. **Read** — `get_page_tree` , `find_nodes` , `get_node` , `list_pages`
4. **Create** — `create_shape` , `render` (JSX)
5. **Modify** — `set_fill` , `set_stroke` , `set_layout` , `update_node` , `set_effects`
6. **Structure** — `reparent_node` , `group_nodes` , `clone_node` , `delete_node`
7. **Save** — `save_file` to write back to `.fig`
2026-09-18 08:55:06 +00:00
8. **Close** — `close_file` to close an open document tab; it prompts to save unsaved changes.
2026-07-03 14:05:04 +00:00
Most tools accept optional `document_id` and `page_id` fields. Pass them explicitly for agent workflows instead of relying on the visible active tab/page. `create_page` only creates a page; call `switch_page` separately when the workflow should change the active page.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
## AI Agent Skill
Teach your AI coding agent to use OpenPencil tools:
```sh
2026-09-13 14:29:33 +00:00
npx skills add open-pencil/open-pencil
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
```
Works with Claude Code, Cursor, Windsurf, Codex, and any agent that supports [skills ](https://skills.sh ). The skill covers the CLI, MCP tools, JSX rendering, eval, and the running app's automation bridge.
2026-08-13 17:26:25 +00:00
## Tools
OpenPencil currently registers 100+ shared design tools, plus MCP-only document and prompt operations when applicable.
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
### Document
| Tool | Description |
|------|-------------|
| `open_file` | Open a `.fig` file for editing |
2026-09-18 08:55:06 +00:00
| `close_file` | Close an open document tab, prompting to save unsaved changes |
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
| `save_file` | Save the current document to a `.fig` file |
| `new_document` | Create a new empty document |
2026-07-03 14:05:04 +00:00
| `list_documents` | List open app documents/tabs and their pages |
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
### Read
| Tool | Description |
|------|-------------|
| `get_selection` | Get currently selected nodes |
| `get_page_tree` | Get the full node tree of the current page |
| `get_current_page` | Get the current page name and ID |
| `get_node` | Get detailed properties of a node by ID |
| `find_nodes` | Find nodes by name pattern and/or type |
| `get_components` | List all components in the document |
| `list_pages` | List all pages |
| `list_variables` | List design variables |
| `list_collections` | List variable collections |
| `list_fonts` | List fonts used in the current page |
2026-08-13 17:26:25 +00:00
| `list_available_fonts` | List font families the current host can render |
2026-09-26 07:14:30 +00:00
| `get_font_status` | Report requested faces, loaded sources, active substitutions, why an installed face could not be loaded, and affected nodes |
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
| `page_bounds` | Get bounding box of all objects on the current page |
| `node_bounds` | Get bounding box of a node |
| `node_ancestors` | Get ancestor chain of a node |
| `node_children` | Get direct children of a node |
| `node_tree` | Get the subtree rooted at a node |
| `node_bindings` | Get variable bindings on a node |
### Create
| Tool | Description |
|------|-------------|
2026-03-08 10:53:33 +00:00
| `create_shape` | Create a shape (`FRAME`, `RECTANGLE` , `ELLIPSE` , `TEXT` , `LINE` , `STAR` , `POLYGON` , `SECTION` ) |
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
| `create_vector` | Create a vector node from a path string |
| `create_slice` | Create an export slice |
| `create_page` | Create a new page |
| `render` | Render JSX to design nodes — create entire component trees in one call |
| `create_component` | Convert a frame/group into a component |
| `create_instance` | Create an instance of a component |
| `node_to_component` | Convert an existing node into a component in-place |
### Modify
| Tool | Description |
|------|-------------|
| `set_fill` | Set fill color (hex) |
| `set_stroke` | Set stroke color, weight, alignment |
| `set_effects` | Add shadow or blur effects |
| `update_node` | Update position, size, opacity, corner radius, text, font |
| `set_layout` | Set auto-layout (flexbox) — direction, spacing, padding, alignment |
| `set_constraints` | Set resize constraints |
| `set_rotation` | Set rotation angle in degrees |
| `set_opacity` | Set opacity (0– 1) |
| `set_radius` | Set corner radius (uniform or per-corner) |
| `set_minmax` | Set min/max width and height constraints |
2026-03-08 10:53:33 +00:00
| `set_text` | Set text content of a `TEXT` node |
Add Programmable docs section with CLI, JSX, MCP, AI, Collab
New top-level nav section documenting OpenPencil's programmability:
- CLI: inspecting, exporting, analyzing, scripting (eval)
- JSX Renderer: elements, style props, visual diffing
- MCP Server: moved from Reference (setup + tool list)
- AI Chat: setup, 87 tools, example prompts
- Collaboration: room sharing, cursors, follow mode
Restructured sidebar:
- Programmable added to nav bar (7 locales)
- Context Menu moved from User Guide to Reference
- MCP and eval-command removed from Reference
2026-03-08 10:22:36 +00:00
| `set_font` | Set font family and weight |
| `set_font_range` | Set font properties on a character range |
| `set_text_resize` | Set text auto-resize mode (fixed/auto-width/auto-height) |
| `set_visible` | Show or hide a node |
| `set_blend` | Set blend mode |
| `set_locked` | Lock or unlock a node |
| `set_stroke_align` | Set stroke alignment (inside/center/outside) |
| `set_text_properties` | Set text layout: alignment, auto-resize, text case, decoration, truncation |
| `set_layout_child` | Configure auto-layout child: sizing, grow, alignment, absolute positioning |
| `node_move` | Move a node to a new position |
| `node_resize` | Resize a node |
| `node_replace_with` | Replace a node with another node |
| `arrange` | Align or distribute selected nodes |
### Structure
| Tool | Description |
|------|-------------|
| `delete_node` | Delete a node |
| `clone_node` | Duplicate a node |
| `rename_node` | Rename a node |
| `reparent_node` | Move a node into a different parent |
| `select_nodes` | Select nodes by ID |
| `group_nodes` | Group nodes |
| `ungroup_node` | Ungroup a group |
| `flatten_nodes` | Flatten nodes into a single vector |
| `boolean_union` | Boolean union of two or more nodes |
| `boolean_subtract` | Boolean subtraction |
| `boolean_intersect` | Boolean intersection |
| `boolean_exclude` | Boolean exclusion |
### Vector Path
| Tool | Description |
|------|-------------|
| `path_get` | Get the path data of a vector node |
| `path_set` | Set the path data of a vector node |
| `path_scale` | Scale a vector path |
| `path_flip` | Flip a vector path horizontally or vertically |
| `path_move` | Translate a vector path |
### Export
| Tool | Description |
|------|-------------|
| `export_image` | Export nodes as PNG, JPG, or WEBP. Returns base64-encoded image data |
| `export_svg` | Export nodes as SVG markup |
### Viewport
| Tool | Description |
|------|-------------|
| `viewport_get` | Get current viewport position and zoom level |
| `viewport_set` | Set viewport position and zoom |
| `viewport_zoom_to_fit` | Zoom viewport to fit specified nodes |
### Variables
| Tool | Description |
|------|-------------|
| `get_variable` | Get a variable by ID or name |
| `find_variables` | Find variables by name pattern or type |
| `create_variable` | Create a new variable in a collection |
| `set_variable` | Set a variable value in a mode |
| `delete_variable` | Delete a variable |
| `bind_variable` | Bind a variable to a node property |
| `get_collection` | Get a variable collection by ID or name |
| `create_collection` | Create a new variable collection |
| `delete_collection` | Delete a variable collection |
### Analyze
| Tool | Description |
|------|-------------|
| `analyze_colors` | Analyze color palette usage across the document |
| `analyze_typography` | Analyze font/size/weight distribution |
| `analyze_spacing` | Analyze gap and padding values |
| `analyze_clusters` | Detect repeated patterns (potential components) |
### Diff
| Tool | Description |
|------|-------------|
| `diff_create` | Create a snapshot of the current document state |
| `diff_show` | Show differences between the current state and a snapshot |
### Navigation
| Tool | Description |
|------|-------------|
| `switch_page` | Switch to a page by name or ID |
### Escape Hatch
| Tool | Description |
|------|-------------|
| `eval` | Execute JavaScript with full Figma Plugin API access |
Note: `eval` is available over stdio, but disabled in HTTP mode for security.