@sxl-studio/bridge
v1.6.0
Published
MCP/HTTP bridge server for SXL Studio Figma plugin — enables remote control from IDE
Readme
SXL Studio Bridge
Node.js process that connects Cursor (or any MCP client) and HTTP clients to the SXL Studio Figma plugin while a Remote Connect session is active in the plugin UI.
What it does
- WebSocket — plugin UI iframe connects here and forwards
remote-command/ results. - MCP (Streamable HTTP + stdio) — Cursor / Claude Desktop / any MCP client calls typed tools (
export_variables,export_composition_json,get_codegen,compose_from_url, …); each tool maps to one plugin command or an orchestration that chains several. - HTTP — same command queue for scripts, CI, curl, idempotency-safe retries, audit log.
Official Figma MCP does not run your plugin code. Use both: Figma MCP for file/design context; this bridge for SXL-specific operations (compositions, token export, mappings, Git, Dev Mode codegen).
Figma MCP vs SXL Bridge (product split)
| Need | Use |
|------|-----|
| Native file operations where Figma’s MCP tools are enough (context, many canvas writes, variables in supported flows) | Official Figma MCP (often remote https://mcp.figma.com/mcp) |
| Plugin-only workflows: compositions, plugin token/Git APIs, whitelisted node helpers, Dev Mode codegen parity | SXL Studio Bridge + plugin Remote Connect |
Bridge forwards commandType + payload over WebSocket; execution is always in the plugin (whitelist + handlers). Adding an MCP tool in Bridge without the matching plugin handler will return not_whitelisted.
Version compatibility (npm Bridge ⟷ plugin)
| @sxl-studio/bridge (npm) | SXL Studio plugin | Highlights |
|---------------------------|-------------------|------------|
| 1.0.x | same-era | Base remote node tools (create_frame, set_node_fill, …) |
| 1.1.x | same-era | set_node_fill_variable, extended create_frame / create_text (parentId, Auto Layout fields) |
| 1.2.x | same-era | Remote module split (dispatch/, canvas/, sxl/), MCP instructions, base canvas tools, validated POST /api/command, aligned COMMAND_TIMEOUTS |
| 1.3.x | 2.1.0+ | Dev Mode codegen bridge (get_codegen, export_composition_json), full token workspace CRUD (create_token_file, delete_token_file, move_token_file, save_tokens_config, upsert save_token_file), Variables CRUD (modes, scopes, codeSyntax), Styles CRUD, orchestration (compose_from_url, generate_code_from_url, document_component), MCP Resources (sxl://…), typed errors (EDITOR_MODE_READONLY + structured envelope), BRIDGE_AUTH_TOKEN, Idempotency-Key on /api/command, /api/log audit trail, /api/tools + list_tools meta-tool, editor-mode write-guard with typed propagation. |
| 1.4.x | 2.1.0+ (plugin with apply_token_doc_spec) | Doc Spec v1 + build_token_documentation / apply_token_doc_spec, MCP resources sxl://agent/recipes/doc-tokens (+ doc-component, doc-composition, doc-flow), expanded MCP instructions for documentation recipes. |
| 1.5.x | 2.2.0+ | Doc Builder v2: apply_doc_spec (generic sections), bind_variable_palette, build_component_doc, build_doc_flow. Intent-router resource sxl://agent/recipes/index plus template-discovery, doc-spec-v2. Reinforced anti-patterns in sxl-mcp-instructions.ts (/tmp payloads, base64 loaders, use_figma scripts). |
| 1.6.x | 2.3.0+ | Audit & Usage (Phase A) + Variables orchestration (Phase B) + Styles orchestration (Phase C) + Mockup-from-DesignSystem (Phase D) + Compositions orchestration (Phase E). Phase A: audit category — analyze_variable_usage, find_variable_usages, render_variable_usage_page, audit_variable_coverage, find_variable_coverage_misses, audit_style_coverage, find_style_coverage_misses, find_unused_variables, find_unused_styles. Chunked traversal with transitive-alias resolution. Token-economy: summary by default, paginated find_* for details. Phase B: new variables-orchestration category — import_variable_spec (idempotent bulk create / update with aliases), analyze_variable_order (read-only ordering diff), dedupe_variables (merge duplicates, dry-run by default), rebind_variable_aliases (bulk alias rewrite), apply_coverage_suggestions (audit suggestions → real bindings, dry-run by default). Phase C: new styles-orchestration category — import_style_spec (idempotent bulk create / update of Paint / Text / Effect styles), dedupe_styles (merge duplicates byName | bySignature), rebind_style_consumers (bulk styleId rewrite on consumer nodes), audit_style_drift (read-only drift between local Paint styles and Variables / expectations[]), apply_style_coverage_suggestions (Phase A find_style_coverage_misses → real setStyleId* writes). Phase D: new mockup category — find_components (read-only paginated catalogue of local + library-instantiated components with componentPropertyDefinitions, Dev-Mode compatible), build_mockup (declarative auto-layout assembly from an instance | section | spacer | text item tree with property / text / fill-binding overrides; dryRun-aware), apply_mockup_dataset (clone a template per dataset row with row-specific overrides; dryRun-aware). Phase E: new compositions-orchestration category — bulk_generate_compositions (bulk generate / apply of composition files with fileIds | names | prefix filters, operation: auto | generate | apply, per-item error isolation, dryRun-aware), audit_composition_drift (read-only drift detection between workspace composition files and tracked Figma components: linked | unlinked | drift | missing, Dev-Mode safe). All write commands accept dryRun / apply so Dev Mode can be used as a preview surface. Recipes: sxl://agent/recipes/{variable-usage,audit-coverage,find-unused,bulk-variables,auto-bind-from-audit,bulk-styles,style-drift,mockup-builder,bulk-compositions,composition-drift}. |
Treat feature alignment by changelog or release tag, not npm name alone.
Ports
One TCP port (BRIDGE_PORT, default 37830): plugin WebSocket, HTTP REST (/api/*), and MCP Streamable HTTP (/mcp) share it. Override with BRIDGE_PORT=3100 npm start if needed (update plugin build + mcp.json to match).
| On port BRIDGE_PORT | URL (default) |
|----------------------|---------------|
| Plugin UI | ws://127.0.0.1:37830 |
| REST | http://127.0.0.1:37830/api/{status,session,tools,log,command,disconnect} |
| Cursor MCP | http://127.0.0.1:37830/mcp |
Optional: shared-secret auth
Set BRIDGE_AUTH_TOKEN in the environment and every /api/* and /mcp request must send Authorization: Bearer <token>. Requests without the header return 401 BRIDGE_UNAUTHORIZED. Useful when running Bridge on a shared machine, or behind a local proxy.
BRIDGE_AUTH_TOKEN=s3cret npm startCursor MCP (recommended)
Add http://127.0.0.1:37830/mcp to .cursor/mcp.json. Start Bridge first (cd Utils/bridge && npm run build && npm start). Then enable Remote Connect in the SXL Studio plugin.
Official Figma MCP (http://127.0.0.1:3845/mcp) reads design context from the file; it does not run SXL Studio plugin commands.
Run locally
cd Utils/bridge
npm install
npm run build
node dist/index.jsIf you see EADDRINUSE, pick a free port: BRIDGE_PORT=39999 npm start, then use http://127.0.0.1:39999/mcp in Cursor and rebuild the plugin so remoteBridge.ts default matches.
The repo .cursor/mcp.json points Cursor at http://127.0.0.1:37830/mcp. Bridge must run before opening Agent chat.
MCP + stdout: the Model Context Protocol uses stdout for JSON-RPC. Do not use console.log in this process (it corrupts the stream). Use console.error for diagnostics.
MCP configuration (Cursor)
Example .cursor/mcp.json:
{
"mcpServers": {
"sxl-studio": {
"url": "http://127.0.0.1:37830/mcp"
}
}
}stdio variant (if preferred):
{
"mcpServers": {
"sxl-studio": {
"command": "node",
"args": ["/absolute/path/to/repo/Utils/bridge/dist/index.js"],
"env": { "BRIDGE_PORT": "37830" }
}
}
}HTTP API examples
Requires the plugin open in Figma, Remote Connect enabled, and Bridge running.
Status
curl -s http://127.0.0.1:37830/api/statusReturns ports, mcpStreamableHttp, session, queueLength, currentCommand, authEnabled.
Tool catalogue
curl -s 'http://127.0.0.1:37830/api/tools?category=tokens'
curl -s 'http://127.0.0.1:37830/api/tools?devModeReadableOnly=true'Returns entries { name, category, description, requiresDesignMode, requiresComposition }. MCP clients can call the equivalent list_tools meta-tool.
Audit trail
curl -s 'http://127.0.0.1:37830/api/log?limit=50'Ring buffer of executed commands: commandType, status, durationMs, payloadKeys, idempotencyKey, timestamp.
Read token file (after list_token_files)
curl -s -X POST http://127.0.0.1:37830/api/command \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BRIDGE_AUTH_TOKEN" \
-H "Idempotency-Key: 01HXYZ1234" \
-d '{"commandType":"get_token_file_content","payload":{"fileId":"tf_..."}}'Repeat requests with the same Idempotency-Key (within 10 minutes) return the cached response without touching the plugin — safe for retries.
Save token file (upsert)
curl -s -X POST http://127.0.0.1:37830/api/command \
-H "Content-Type: application/json" \
-d '{
"commandType": "save_token_file",
"payload": { "name": "buttons", "folder": "components", "content": "{\"$type\":\"composition\"}" }
}'If a file with that name+folder exists, it is updated. Otherwise it is created.
Export composition JSON from current selection
curl -s -X POST http://127.0.0.1:37830/api/command \
-H "Content-Type: application/json" \
-d '{"commandType":"export_composition_json","payload":{}}'Optional payload.nodeId selects a specific node instead of the first selected node.
Typed errors
Failures return a structured envelope:
{
"status": "failed",
"error": "{\"code\":\"EDITOR_MODE_READONLY\",\"message\":\"Command \\\"create_frame\\\" requires Figma Design mode.\",\"retryable\":false,\"details\":{\"editorType\":\"dev\",\"mode\":\"default\",\"isDevMode\":true}}"
}Known codes: EDITOR_MODE_READONLY, BRIDGE_TIMEOUT, BRIDGE_CANCELLED, BRIDGE_UNAUTHORIZED, BRIDGE_ERROR. MCP tools decode the envelope before returning to the agent.
MCP tools (summary)
Registered in src/mcp-factory.ts via tools/*.ts:
- Diagnostics / meta:
get_plugin_status,is_dev_mode,get_selection_summary,get_drift_status,list_tools. - Tokens / workspace:
list_token_files,get_token_file_content,save_token_file(upsert),create_token_file,delete_token_file,move_token_file,rename_token_file,get_tokens_config,save_tokens_config,export_variables,reset_diff*,reapply_token_bindings,cross_file_sync_*,get_applied_tokens. - Composition:
export_composition_json,get_codegen,list_compositions,generate_composition,apply_composition,preview_composition,check_composition_linked,inspect_selection. - Variables:
get_variables,create_variable_collection,create_variable,bind_variable,rename_variable,delete_variable,rename_variable_collection,delete_variable_collection,add_variable_mode,remove_variable_mode,rename_variable_mode,set_variable_mode_value,set_variable_scopes,set_variable_code_syntax, plus batch opsbatch_create_variables/batch_set_variable_values/batch_delete_variables/batch_bind_variables. - Variables orchestration (Phase B, Bridge
1.6.0+):import_variable_spec(idempotent bulk create / update with aliases,dryRun),analyze_variable_order(read-only ordering diff),dedupe_variables(merge duplicates, dry-run by default; canvas write only withapply: true),rebind_variable_aliases(bulk alias rewrite,dryRun),apply_coverage_suggestions(audit suggestions → real bindings, dry-run by default). - Styles:
get_local_styles,create_paint_style,create_text_style,create_effect_style,set_text_style,set_effect_style,set_stroke_style,set_fill_style,import_style_by_key. - Styles orchestration (Phase C, Bridge
1.6.0+):import_style_spec(idempotent bulk create / update of Paint / Text / Effect styles,dryRun),dedupe_styles(merge duplicatesbyName | bySignature, dry-run by default; canvas write only withapply: true),rebind_style_consumers(bulk styleId rewrite on consumer nodes,dryRun),audit_style_drift(READ-ONLY drift between local Paint styles and Variables /expectations[]),apply_style_coverage_suggestions(Phase Afind_style_coverage_misses→ realsetStyleId*writes, dry-run by default). - Mockup-from-DesignSystem (Phase D, Bridge
1.6.0+):find_components(READ-ONLY paginated catalogue of local + library-instantiated components withcomponentPropertyDefinitions; Dev-Mode compatible),build_mockup(assemble one auto-layout mockup from a declarativeinstance | section | spacer | textitem tree with property / text / fill-binding overrides;dryRun-aware),apply_mockup_dataset(clone a template per dataset row with row-specific overrides;dryRun-aware). Replaces hand-rolleduse_figma { figma.createInstance(...).setProperties(...) }loops. - Compositions orchestration (Phase E, Bridge
1.6.0+):bulk_generate_compositions(bulkgenerate/applyof composition files in one MCP call; filtersfileIds | names | prefix;operation: auto | generate | apply; per-item error isolation;dryRun-aware),audit_composition_drift(READ-ONLY drift detector between workspace composition files and tracked Figma components; statuseslinked | unlinked | drift | missing; Dev-Mode safe). Replaces hand-rolledfor-ofloops overgenerate_composition/apply_compositionand per-filecheck_composition_linkedpolling. - Data / nodes:
apply_mapping,apply_all_mappings,count_apply_targets,generate_instances,apply_image, plus direct node helpers indata.ts/figma-nodes.ts(set_node_fill_variable,create_rectangle,set_auto_layout,duplicate_subtree,create_component_instance,apply_documentation_payload, extendedcreate_frame/create_text). - Git:
git_pull,git_hard_pull,git_push. - Orchestration:
generate_code_from_url,compose_from_url,document_component.
MCP Resources
| URI | Contents |
|-----|----------|
| sxl://figma/status | Plugin status snapshot |
| sxl://figma/selection | Current Figma selection |
| sxl://tokens/config | Raw config.json |
| sxl://tokens/files | Token file index |
| sxl://tokens/files/{fileId} | Raw token file body |
| sxl://compositions/index | Composition JSON index |
| sxl://agent/recipes/index | Intent router (start here) |
| sxl://agent/recipes/{doc-tokens,doc-component,doc-composition,doc-flow,doc-spec-v2,template-discovery,variable-palette,compose-with-variables,scenario-from-markdown,variable-usage,audit-coverage,find-unused,bulk-variables,auto-bind-from-audit,bulk-styles,style-drift,mockup-builder,bulk-compositions,composition-drift} | Doc Builder + audit + Phase B + Phase C + Phase D + Phase E orchestration recipes |
Cursor / Claude can attach these as context without calling tools.
Dev Mode support
| Context | Reads | Canvas writes | Token/config/git writes |
|---------|-------|---------------|--------------------------|
| Figma Design | ✔︎ | ✔︎ | ✔︎ |
| Figma Dev Mode (UI, mode: "default") | ✔︎ | ✘ (plugin returns EDITOR_MODE_READONLY) | ✔︎ |
| Figma Dev Mode (Inspect → Code sandbox) | read-only codegen callback; Remote Connect unavailable | ✘ | ✘ |
get_codegen (Bridge) and the Dev Mode Inspect → Code panel (plugin) share the exact same routeCodegenGenerate pipeline. Output is byte-identical.
Development
npm run test # Vitest
npm run build # tsc → dist/
npm run lint # tsc --noEmitPublishing to npm
See docs/npm-publish.md. The package ships only dist/ and README.md (files in package.json). Example and monorepo-only scripts live under examples/.
Examples (monorepo only)
See examples/README.md for how to write consumer scripts against POST /api/command without coupling the npm package to your design-system paths.
