/seed-verify-figma-mcp-transports
Figma MCP 도구 변경 뒤 REST와 WebSocket 결과를 실제로 비교해 transport parity를 검증할 때 사용한다.
$ npx -y skills add daangn/seed-design --skill seed-verify-figma-mcp-transports --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/seed-verify-figma-mcp-transports
Context preview
The summary Claude sees to decide when to auto-load this skill.
Figma MCP 도구 변경 뒤 REST와 WebSocket 결과를 실제로 비교해 transport parity를 검증할 때 사용한다.
SKILL.md
seed-verify-figma-mcp-transports.SKILL.mdname: seed-verify-figma-mcp-transports
description: Figma MCP 도구 변경 뒤 REST와 WebSocket 결과를 실제로 비교해 transport parity를 검증할 때 사용한다.
Verify Figma MCP Transports
A Figma MCP tool answers the same question over two paths: **REST** (personal access token) and **WebSocket** (the Figma plugin). Fixing one and not the other still typechecks, so the drift is silent. Run both and compare mechanically.
두 경로의 구현 차이가 판단에 필요할 때만 `packages/mcp/AGENTS.md`를 읽는다.
> [!IMPORTANT] > Run this skill **on the main thread**. Phase 3 is a hard stop that waits on a person, and a subagent has nobody to ask — it will pass itself.
Prerequisites
- `FIGMA_PERSONAL_ACCESS_TOKEN` is set. If not, stop at Phase 0 and ask for it.
- The Figma desktop app is installed.
- The tool under test is registered in `PROBES` in the probe script. If it isn't, register it first — see the header comment in that file.
Phase 0: Decide what to inspect
Both transports need a target, so this comes before any probing — REST in Phase 1 already needs it.
**검증 기준은 변경 diff에서 스스로 도출한다.** 사용자가 이미 조건을 만족하는 layer URL을 제공했으면 그대로 사용한다. 그렇지 않으면 특정 node가 아니라 필요한 layer 형태를 설명해 URL을 요청한다. "A frame containing a layer with two or more annotations, and a text layer with none"은 답할 수 있지만, "Give me a layer URL"은 검증 설계를 사용자에게 넘긴다.
Start from this checklist and cut what your change doesn't touch:
| Cover | Why | |---|---| | The queried node itself carrying a value | Catches a traversal that skips its own root | | A descendant carrying a value | The recursive collection path | | A leaf (no `children`) | Whether a non-container node throws | | A page (`CANVAS` / `PAGE`) | The plugin-only `loadAsync` path, plus the type-vocabulary difference | | A node inside a component instance | IDs composed as `I<a>;<b>;<c>` |
The last two apply to every tool. The rest apply only when the tool walks a tree.
Ask with **AskUserQuestion**, and ask for a **layer URL** — `parseFigmaUrl` takes the file key and node id straight out of it, so nobody has to read ids off a canvas.
If the same file gets reused across runs, put its key in `SEED_MCP_PROBE_FILE_KEY` and pass only `--node-id` afterwards.
Phase 1: REST alone (no person needed)
REST needs nothing but the token, so **finish it without asking anyone.**
bun packages/mcp/scripts/probe-transports.ts \
--probe <tool> \
--transport rest \
--file-key <key> \
--node-id <id>
- The script calls the same helper the tool handler calls. Never reach past it to the REST API directly — that tests Figma, not the tool.
- If this fails, do not move on to WebSocket prep. Calling a person in to help debug a broken REST path spends their time on your bug.
Phase 2: Prepare WebSocket (up to the human boundary)
Build everything that does not need a person, so the person is interrupted exactly once.
1. Build the plugin. Editing the source without rebuilding leaves Figma reading the old `dist`.
bun --filter figma-mcp build
2. Start the relay in the background (`Bash` with `run_in_background: true`).
bun packages/mcp/bin/index.mjs socket
Wait for `WebSocket server running on port 3055`. If the port is already held, ask whether to reuse that process — never kill something you did not start.
Phase 3: Hand off (hard stop)
Only a person can drive the Figma desktop app. There is no way around this step.
**Before asking, confirm all of these.** If any is false, go back to Phase 2 — the person gets called once.
- [ ] `tools/figma-mcp/dist` was just rebuilt
- [ ] The relay is listening on 3055
- [ ] Phase 1 passed
Then ask with **AskUserQuestion**. Do not write the question into chat and continue — that is not a stop.
Spell out what to do and why each step matters; without the reason people skip the reload. Refer to the file by the key Phase 1 actually used. If they open a different file the two transports answer about different documents, and that difference gets reported as a code bug.
WebSocket side is ready. Two things in Figma:
1. Quit the plugin and run it again — dist was just rebuilt, and a running
instance keeps answering with the old code.
2. Open the file from Phase 1 (<key>) and hit Connect in the plugin.
Port 3055, channel is fixed to local-default, so there is nothing to type.
Offer three options:
| Option | Next | |---|---| | `Ready` | Phase 4 | | `Show me how to reload the plugin` | Explain, then ask again | | `Stop` | Clean up the relay, report Phase 1 only |
Phase 4: Probe and compare
1. **Do not take "ready" at face value.** Check the relay log for `New client connected` first. If it is missing, ask again rather than probing into a void — an unconnected run yields a 30-second timeout that reads like a plugin bug.
2. Run both and diff:
bun packages/mcp/scripts/probe-transports.ts \
--probe <tool> \
--transport both \
--file-key <key> \
--node-id <id>3. **The exit code decides whether anything differs — not whether it is a bug.** Do not read the output and conclude it "looks the same"; 0 means the transports agree on every compared field. A 1 prints the disagreement, which you then classify with the table below before calling it a bug.
4. Run every node you chose in Phase 0. One passing node is not a pass.
Phase 5: Report and clean up
- Report pass/fail per node, and for any failure which field differed and how.
- Record which file and nodes you used. Without that nobody can reproduce the result.
- **Terminate only a relay you started in Phase 2.** If you reused one that was already running, leave it.
Four ways the transports diverge
Comparing is not "the whole payload matches". Sort each field into one of four classes.
| Class | Handling | |---|---| | **Must match** | The default. A difference is a bug. | | **Transport-only** | Only one side can produce it. Add it to the probe's `ignore`. | | **Different vocabulary** | Both name the same thing differe
Read more
name: seed-verify-figma-mcp-transports description: Figma MCP 도구 변경 뒤 REST와 WebSocket 결과를 실제로 비교해 transport parity를 검증할 때 사용한다.
Verify Figma MCP Transports
A Figma MCP tool answers the same question over two paths: **REST** (personal access token) and **WebSocket** (the Figma plugin). Fixing one and not the other still typechecks, so the drift is silent. Run both and compare mechanically.
두 경로의 구현 차이가 판단에 필요할 때만 `packages/mcp/AGENTS.md`를 읽는다.
> [!IMPORTANT] > Run this skill **on the main thread**. Phase 3 is a hard stop that waits on a person, and a subagent has nobody to ask — it will pass itself.
Prerequisites
- `FIGMA_PERSONAL_ACCESS_TOKEN` is set. If not, stop at Phase 0 and ask for it.
- The Figma desktop app is installed.
- The tool under test is registered in `PROBES` in the probe script. If it isn't, register it first — see the header comment in that file.
Phase 0: Decide what to inspect
Both transports need a target, so this comes before any probing — REST in Phase 1 already needs it.
**검증 기준은 변경 diff에서 스스로 도출한다.** 사용자가 이미 조건을 만족하는 layer URL을 제공했으면 그대로 사용한다. 그렇지 않으면 특정 node가 아니라 필요한 layer 형태를 설명해 URL을 요청한다. "A frame containing a layer with two or more annotations, and a text layer with none"은 답할 수 있지만, "Give me a layer URL"은 검증 설계를 사용자에게 넘긴다.
Start from this checklist and cut what your change doesn't touch:
| Cover | Why | |---|---| | The queried node itself carrying a value | Catches a traversal that skips its own root | | A descendant carrying a value | The recursive collection path | | A leaf (no `children`) | Whether a non-container node throws | | A page (`CANVAS` / `PAGE`) | The plugin-only `loadAsync` path, plus the type-vocabulary difference | | A node inside a component instance | IDs composed as `I<a>;<b>;<c>` |
The last two apply to every tool. The rest apply only when the tool walks a tree.
Ask with **AskUserQuestion**, and ask for a **layer URL** — `parseFigmaUrl` takes the file key and node id straight out of it, so nobody has to read ids off a canvas.
If the same file gets reused across runs, put its key in `SEED_MCP_PROBE_FILE_KEY` and pass only `--node-id` afterwards.
Phase 1: REST alone (no person needed)
REST needs nothing but the token, so **finish it without asking anyone.**
bun packages/mcp/scripts/probe-transports.ts \ --probe <tool> \ --transport rest \ --file-key <key> \ --node-id <id>
- The script calls the same helper the tool handler calls. Never reach past it to the REST API directly — that tests Figma, not the tool.
- If this fails, do not move on to WebSocket prep. Calling a person in to help debug a broken REST path spends their time on your bug.
Phase 2: Prepare WebSocket (up to the human boundary)
Build everything that does not need a person, so the person is interrupted exactly once.
1. Build the plugin. Editing the source without rebuilding leaves Figma reading the old `dist`.
bun --filter figma-mcp build
2. Start the relay in the background (`Bash` with `run_in_background: true`).
bun packages/mcp/bin/index.mjs socket
Wait for `WebSocket server running on port 3055`. If the port is already held, ask whether to reuse that process — never kill something you did not start.
Phase 3: Hand off (hard stop)
Only a person can drive the Figma desktop app. There is no way around this step.
**Before asking, confirm all of these.** If any is false, go back to Phase 2 — the person gets called once.
- [ ] `tools/figma-mcp/dist` was just rebuilt
- [ ] The relay is listening on 3055
- [ ] Phase 1 passed
Then ask with **AskUserQuestion**. Do not write the question into chat and continue — that is not a stop.
Spell out what to do and why each step matters; without the reason people skip the reload. Refer to the file by the key Phase 1 actually used. If they open a different file the two transports answer about different documents, and that difference gets reported as a code bug.
WebSocket side is ready. Two things in Figma: 1. Quit the plugin and run it again — dist was just rebuilt, and a running instance keeps answering with the old code. 2. Open the file from Phase 1 (<key>) and hit Connect in the plugin. Port 3055, channel is fixed to local-default, so there is nothing to type.
Offer three options:
| Option | Next | |---|---| | `Ready` | Phase 4 | | `Show me how to reload the plugin` | Explain, then ask again | | `Stop` | Clean up the relay, report Phase 1 only |
Phase 4: Probe and compare
1. **Do not take "ready" at face value.** Check the relay log for `New client connected` first. If it is missing, ask again rather than probing into a void — an unconnected run yields a 30-second timeout that reads like a plugin bug.
2. Run both and diff:
bun packages/mcp/scripts/probe-transports.ts \
--probe <tool> \
--transport both \
--file-key <key> \
--node-id <id>3. **The exit code decides whether anything differs — not whether it is a bug.** Do not read the output and conclude it "looks the same"; 0 means the transports agree on every compared field. A 1 prints the disagreement, which you then classify with the table below before calling it a bug.
4. Run every node you chose in Phase 0. One passing node is not a pass.
Phase 5: Report and clean up
- Report pass/fail per node, and for any failure which field differed and how.
- Record which file and nodes you used. Without that nobody can reproduce the result.
- **Terminate only a relay you started in Phase 2.** If you reused one that was already running, leave it.
Four ways the transports diverge
Comparing is not "the whole payload matches". Sort each field into one of four classes.
| Class | Handling | |---|---| | **Must match** | The default. A difference is a bug. | | **Transport-only** | Only one side can produce it. Add it to the probe's `ignore`. | | **Different vocabulary** | Both name the same thing differe
SEED는 당근 제품을 위한 통합된 디자인 언어입니다. 하나의 토큰 소스에서 React, iOS, Android, Lynx까지 여러 플랫폼에 일관된 디자인을 전달하고, Figma와 연동됩니다.
Repo: daangn/seed-design
Other skills on seed-design.
seed-change
SEED 변경의 영향·검증·기준 브랜치를 판단하거나, 공개 패키지 changeset을 작성하거나, 명시적으로 요청받은 rebase·commit·push·PR 제출을 할…
seed-component
SEED 컴포넌트의 경로 조회·React·Lynx API 비교, 신규·포팅·기존 구현 변경, React·Lynx 문서·예제 작성, 또는 컴포넌트와 무관한 색상 토큰의…

