Skip to content

Latest commit

 

History

History
158 lines (119 loc) · 9.44 KB

File metadata and controls

158 lines (119 loc) · 9.44 KB

Devup Bridge

devup-mcp 가 Figma 를 읽을 때 공식 MCP 의 요금 한도를 쓰지 않게 해 주는 플러그인입니다.

왜 필요한가

devup-mcp 의 수집은 읽기 스크립트를 공식 MCP 의 use_figma 로 보내는 방식이고, 한도가 걸리는 곳이 바로 그 도구입니다. 화면 하나를 받는 데 snapshot 만 십수 회가 들어가므로 한도는 금방 바닥납니다.

그 스크립트들이 건드리는 것은 문서화된 Plugin API 뿐입니다.

getNodeByIdAsync   getStyleByIdAsync   variables   root   fileKey
getLocalPaintStylesAsync / TextStylesAsync / EffectStylesAsync / GridStylesAsync

전부 평범한 플러그인이 쓸 수 있는 것들이라, 우리가 돌리는 플러그인이 같은 일을 대신할 수 있습니다. 그 경로에는 한도가 없습니다.

설치

빌드할 필요 없습니다. dist/ 가 저장소에 들어 있습니다.

Figma 데스크톱 앱에서 Plugins → Development → Import plugin from manifest 를 고르고 plugin/manifest.json 을 선택하면 끝입니다.

브라우저판에서는 개발 플러그인을 불러올 수 없으므로 데스크톱 앱이 필요합니다.

플러그인 소스를 고쳤다면

cd plugin
npm install
npm run build   # dist/ 를 다시 만든다 — 함께 커밋해야 한다
node --test tests/withdraw.test.mjs   # 커밋할 dist/code.js 가 취소를 지키는지

dist/ 는 의도적으로 커밋합니다. 받는 사람이 Node 없이 곧장 import 할 수 있게 하려는 것이고, 그 대가로 원본과 어긋날 위험이 생기므로 CI 가 매번 다시 빌드해 git diff --exit-code -- dist 로 대조합니다. 빌드는 재현 가능합니다 — 같은 입력에서 같은 바이트가 나옵니다. 어긋난 채로는 병합되지 않습니다.

쓰는 법

읽으려는 파일을 열고 플러그인을 실행한 뒤, 창을 열어 둔 채로 devup-mcp 를 쓰면 됩니다. 창을 닫으면 연결이 끊기고 그 파일의 읽기는 다시 공식 MCP 로 갑니다.

창에 표시되는 점이 상태입니다.

표시 뜻
초록 devup-mcp 에 연결됨. 이 파일의 읽기는 한도를 쓰지 않습니다
빨강 devup-mcp 를 찾지 못함. 2초마다 다시 시도합니다

devup-mcp 쪽은 아무 설정도 필요 없습니다. 플러그인이 붙어 있으면 그 파일의 스크립트 읽기를 브리지로 보내고, 안 붙어 있으면 호출마다 곧장 공식 MCP 로 넘어갑니다. 켜 두어서 잃는 것은 없습니다.

링크 없이 — 지금 선택한 것

플러그인은 붙을 때와 그 뒤 페이지·선택이 바뀔 때마다 보고 있는 페이지와 선택한 노드(앞 20개와 전체 수)를 devup-mcp 에 알립니다. 그래서 플러그인이 하나만 붙어 있으면 devup_figma_export·devup_figma_search·devup_figma_explore 에 url 을 주지 않아도 됩니다 — 이 파일의, Figma 에서 선택한 노드가 대상입니다. 링크 자리가 꼭 필요하면 figma-bridge://current(?node-id=1-2 로 노드 지정)를 씁니다. 지금 무엇이 붙어 있고 무엇을 선택했는지는 devup_figma_auth { "action": "status" } 의 paths.bridge.attachedFiles 에 나옵니다.

이 보고가 없는 예전 빌드는 selection 이 null 로 보이며, 이때는 frameIds 로 노드를 직접 지정해야 합니다. 저장소를 받은 뒤 플러그인을 다시 실행하면 새 빌드가 쓰입니다.

알아 둘 것

포트를 바꾸려면 세 곳을 함께 고쳐야 합니다. Figma 는 플러그인이 접속할 수 있는 주소를 manifest 에 미리 적어 두게 하며, 이 목록은 실행 중에 바뀌지 않습니다. 그래서 DEVUP_FIGMA_BRIDGE_PORT 만 바꾸면 devup-mcp 는 새 포트에서 기다리는데 플러그인은 여전히 1993 을 두드리게 되고, 아무 오류 없이 공식 MCP 로 폴백합니다. 아끼려던 한도가 그대로 나가므로 눈치채기 어렵습니다.

바꿔야 한다면 manifest.json 의 allowedDomains, src/code.ts 의 PORT, 그리고 환경 변수를 모두 같은 값으로 맞춘 뒤 플러그인을 다시 빌드·설치하십시오.

끄려면 DEVUP_FIGMA_BRIDGE_PORT=off 를 주면 됩니다.

읽기 전용입니다. 실행되는 스크립트는 devup-mcp 의 읽기 스크립트에서 생성되며 문서를 바꾸는 호출을 포함하지 않습니다. 데이터는 같은 기기의 devup-mcp 로만 나갑니다(127.0.0.1).

한 기기에서 devup-mcp 를 여러 개 띄우면 모두가 같은 플러그인을 씁니다. MCP 클라이언트나 세션마다 devup-mcp 가 하나씩 뜨는 것은 정상입니다. 플러그인이 붙을 수 있는 포트는 manifest 에 적힌 하나뿐이라 먼저 뜬 쪽(호스트)이 포트를 잡고 플러그인을 받으며, 나머지는 호스트를 통해 읽습니다(중계). 플러그인 창은 하나면 됩니다. devup_figma_auth { "action": "status" } 의 paths.bridge.role 이 이 프로세스가 host 인지 relay 인지, host 가 포트를 쥔 프로세스(pid·버전·빌드)를 알려 주며, attachedFiles 는 어느 프로세스에서 보든 같습니다.

호스트를 띄운 세션이 끝나면 남은 devup-mcp 가운데 하나가 곧바로 포트를 이어받고, 플러그인은 2초마다 다시 붙기를 시도하므로 그 새 호스트에 저절로 붙습니다. 사람이 프로세스를 죽이거나 세션을 다시 띄울 필요가 없습니다. 이어받는 동안 status 는 role: "connecting" 으로 그 상태를 그대로 보고합니다.

그때 진행 중이던 수집도 끊기지 않습니다. 플러그인이 돌리고 있던 읽기는 새 호스트에 다시 붙는 대로 다시 보내집니다(읽기는 문서를 바꾸지 않으므로 두 번 돌아도 해가 없습니다). 파일 키를 보고하지 못하는 창(Dev Mode)도 이어서 찾을 수 있도록, 플러그인은 창을 열 때 한 번 정한 sessionId 를 hello 에 싣습니다 — 소켓이 바뀌어도 같은 창이면 같은 이름입니다.

devup-mcp 가 더는 기다리지 않는 읽기 — 요청한 프로세스가 떠났거나 시간이 다 됐다 — 에는 devup-cancel 이 옵니다. 차례를 기다리던 작업이면 돌리지 않고, 이미 돌고 있던 작업이면 스크립트는 멈출 수 없으니 답만 보내지 않습니다. 이 메시지와 sessionId 를 모르는 예전 빌드도 그대로 붙어 동작합니다.

중계는 같은 사용자의 devup-mcp 끼리만 이어집니다. 두 프로세스는 그 사용자만 읽을 수 있는 비밀값(Windows %USERPROFILE%\AppData\Local\devup-mcp\bridge-relay.key, macOS·Linux /tmp/devup-mcp-<uid>/bridge-relay.key)으로 서로를 증명합니다. Unix 는 MCP 클라이언트마다 넘기는 HOME 이 달라도 같은 자리를 보도록 사용자 번호로 자리를 정합니다. 브라우저 페이지는 붙을 수 없습니다 — 중계 문은 Origin 이 붙은 요청을 모두, 플러그인 문은 Figma 플러그인 창(Origin: null)과 figma.com 이 아닌 요청을 거절합니다.

이 기능 이전의 devup-mcp 가 포트를 잡고 있으면 그 프로세스만 플러그인을 씁니다. 나중에 뜬 새 devup-mcp 는 그 사실을 알아보고 status 의 paths.bridge 에 issue: "legacy-host" 와 할 일 — 그 devup-mcp 를 띄운 클라이언트를 재시작하거나 갱신하기 — 을 적으며, 그 프로세스가 끝나면 스스로 포트를 이어받습니다. 예전 devup-mcp 는 자신을 밝히지 않으므로 운영체제에 물어 그 pid 와 실행 파일 경로를 host 에 적습니다. devup-mcp 가 아닌 프로그램이 포트를 잡은 경우는 issue: "foreign-program" 으로 따로 알리고, 그 프로그램을 holder 에 적습니다.

ws://127.0.0.1 은 쓸 수 없습니다. Figma 는 allowedDomains 에 그 주소를 적으면 "유효한 URL 이 아니다"라며 매니페스트 자체를 거부해 플러그인이 실행되지 않습니다. localhost 로만 적어야 하고, UI 도 같은 이름으로 접속합니다. 실제 설치에서 확인한 동작입니다.

파일을 하나만 열어 두십시오. 플러그인은 붙을 때 figma.fileKey 로 자기 파일을 알리는데, 이 값이 비어 오는 경우가 있습니다(Dev Mode 에서 확인). 그때도 연결은 등록되지만, 어느 파일인지 모르므로 혼자 붙어 있을 때만 읽기를 맡습니다. 키 없는 플러그인이 둘 이상이면 어느 쪽이 대상 파일인지 가릴 수 없어 공식 MCP 로 넘어갑니다 — 엉뚱한 파일을 읽어 주는 것보다 낫기 때문입니다.

스크립트는 복사본이 아닙니다

src/generated/ 는 npm run build 가 devup-mcp 의 원본에서 만들어 냅니다.

crates/devup-mcp-figma/src/scripts/*.js   ← 원본 (공식 MCP 경로도 이것을 씀)
        ↓ plugin/scripts/gen-scripts.mjs
plugin/src/generated/scripts.js           ← 중간 산출물 (커밋하지 않음)
        ↓ rspack + scripts/inline-ui.mjs
plugin/dist/{code.js,ui.html}             ← 최종 번들 (커밋함, CI 가 대조)

두 경로가 같은 소스를 쓰므로 봉투가 갈라질 수 없습니다. 원본의 플레이스홀더는 함수 인자로 바뀌고, 치환되지 않은 것이 남으면 빌드가 실패합니다.

__DEVUP_SNAPSHOT_CURSOR__ 만 예외로 그대로 남습니다. 값이 아니라 Rust 디코더와 공유하는 마커 노드 id 라서, 치환하면 페이지네이션이 조용히 깨집니다.