@liner-fe/figma-mcp 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,7 +24,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  // src/server.ts
25
25
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
26
26
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
27
- var import_zod = require("zod");
28
27
 
29
28
  // src/figmaClient.ts
30
29
  var import_crypto = require("crypto");
@@ -134,57 +133,9 @@ var logger = {
134
133
  log: (message) => process.stderr.write(`[LOG] ${message}
135
134
  `)
136
135
  };
137
- var RULES_FILES = Object.keys(__RULES__);
138
- function levenshtein(a, b) {
139
- const m = a.length;
140
- const n = b.length;
141
- if (m === 0) return n;
142
- if (n === 0) return m;
143
- const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
144
- for (let i = 0; i <= m; i++) dp[i][0] = i;
145
- for (let j = 0; j <= n; j++) dp[0][j] = j;
146
- for (let i = 1; i <= m; i++) {
147
- for (let j = 1; j <= n; j++) {
148
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
149
- dp[i][j] = Math.min(
150
- dp[i - 1][j] + 1,
151
- // 삭제
152
- dp[i][j - 1] + 1,
153
- // 삽입
154
- dp[i - 1][j - 1] + cost
155
- // 교체
156
- );
157
- }
158
- }
159
- return dp[m][n];
160
- }
161
- function getSimilarityScore(target, candidate) {
162
- if (target === candidate) return 100;
163
- if (candidate.startsWith(target) || target.startsWith(candidate)) return 95;
164
- if (candidate.includes(target) || target.includes(candidate)) return 85;
165
- const distance = levenshtein(target, candidate);
166
- const maxLen = Math.max(target.length, candidate.length);
167
- const normalized = 1 - distance / maxLen;
168
- const score = Math.floor(normalized * 80);
169
- return score > 0 ? score : 0;
170
- }
171
- var STORIES_EXT = ".stories.mdx";
172
- function findSimilarStoriesFiles(componentName) {
173
- const compName = componentName.toLowerCase();
174
- const files = RULES_FILES.filter((file) => file.toLowerCase().endsWith(STORIES_EXT));
175
- const scored = files.map((file) => {
176
- const baseName = file.toLowerCase().replace(new RegExp(`${STORIES_EXT.replace(".", "\\.")}$`), "");
177
- return {
178
- file,
179
- baseName,
180
- score: getSimilarityScore(compName, baseName)
181
- };
182
- }).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score);
183
- return scored;
184
- }
185
136
  var server = new import_mcp.McpServer(
186
137
  {
187
- name: "@jongh/figma-plugin",
138
+ name: "@liner-fe/figma-mcp",
188
139
  version: "1.0.0"
189
140
  },
190
141
  {
@@ -206,20 +157,18 @@ var { connectToFigma, sendCommandToFigma } = createFigmaClient({
206
157
  serverUrl,
207
158
  wsUrlBase: WS_URL
208
159
  });
209
- server.registerTool(
210
- "get_selection",
211
- {
212
- description: "Get information about the current selection in Figma",
213
- inputSchema: {}
214
- },
160
+ server.tool(
161
+ "get_document_info",
162
+ "Get detailed information about the current Figma document",
163
+ {},
215
164
  async () => {
216
165
  try {
217
- const result = await sendCommandToFigma("get_selection");
166
+ const result = await sendCommandToFigma("get_document_info");
218
167
  return {
219
168
  content: [
220
169
  {
221
170
  type: "text",
222
- text: JSON.stringify(result, null, 2)
171
+ text: JSON.stringify(result)
223
172
  }
224
173
  ]
225
174
  };
@@ -228,140 +177,40 @@ server.registerTool(
228
177
  content: [
229
178
  {
230
179
  type: "text",
231
- text: `Error getting selection: ${error instanceof Error ? error.message : String(error)}`
180
+ text: `Error getting document info: ${error instanceof Error ? error.message : String(error)}`
232
181
  }
233
182
  ]
234
183
  };
235
184
  }
236
185
  }
237
186
  );
238
- server.registerPrompt(
239
- "design system components",
240
- {
241
- description: "help analyze design system common components"
242
- },
243
- () => {
244
- return {
245
- messages: [
246
- {
247
- role: "assistant",
248
- content: {
249
- type: "text",
250
- text: `\uACF5\uD1B5 \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAD6C\uD604 \uC815\uBCF4\uB97C \uD30C\uC545\uD558\uC5EC \uCF54\uB4DC \uC81C\uC791\uC5D0 \uD65C\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4. \uCF54\uB4DC \uC0AC\uC6A9 \uC608\uC2DC, \uC124\uBA85 \uB4F1\uC744 \uC815\uD655\uD558\uAC8C \uD30C\uC545\uD558\uC5EC \uC2E4\uC81C \uCF54\uB4DC \uC81C\uC791\uC5D0 \uC815\uD655\uD558\uAC8C \uD65C\uC6A9\uD560 \uC218 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4.
251
- \uD2B9\uD788 Figma \uC778\uD130\uD398\uC774\uC2A4\uC640 \uCF54\uB4DC \uAC04\uC758 \uAD6C\uD604 \uCC28\uC774\uB97C \uC815\uD655\uD558\uAC8C \uD30C\uC545\uD558\uACE0 \uCF54\uB4DC\uC5D0 \uB9DE\uAC8C \uD65C\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4.`
252
- }
253
- }
254
- ],
255
- description: "Troubleshooting guide for connection issues between Figma plugin and MCP server"
256
- };
257
- }
258
- );
259
187
  server.registerTool(
260
- "get_rule_of_components",
188
+ "get_selection",
261
189
  {
262
- title: "Rule of design system component",
263
- description: [
264
- "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB294 \uACF5\uD1B5 \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAD6C\uD604 \uADDC\uCE59(\uAD6C\uC870, props, \uC2A4\uD0C0\uC77C \uB4F1)\uC744 \uC870\uD68C\uD558\uB294 MCP \uB3C4\uAD6C\uC785\uB2C8\uB2E4.",
265
- "Figma \uB514\uC790\uC778\uC5D0\uC11C \uC0AC\uC6A9\uB41C \uACF5\uD1B5 \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uC774\uB984\uC744 componentName \uC778\uC790\uB85C \uB118\uACA8 \uD638\uCD9C\uD558\uBA74,",
266
- "\uD574\uB2F9 \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAD6C\uD604 \uC815\uBCF4\uB97C \uBC18\uD658\uD558\uC5EC \u2018MCP\uB97C \uD1B5\uD574 \uC0AC\uC6A9\uB41C \uACF5\uD1B5 \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAD6C\uD604 \uC815\uBCF4\uB97C \uD30C\uC545\uD55C \uB4A4\u2019 \uD398\uC774\uC9C0 \uCF54\uB4DC\uB97C \uC791\uC131\uD560 \uB54C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
267
- "\uC608: Figma\uC5D0\uC11C Button \uCEF4\uD3EC\uB10C\uD2B8\uAC00 \uC4F0\uC600\uB2E4\uBA74 componentName\uC5D0 'button'\uC744 \uB123\uC5B4 \uC774 \uB3C4\uAD6C\uB97C \uD638\uCD9C\uD574 \uAD6C\uD604 \uADDC\uCE59\uC744 \uC870\uD68C\uD558\uC138\uC694."
268
- ].join(" "),
269
- inputSchema: import_zod.z.object({
270
- componentName: import_zod.z.string().describe(
271
- "Figma/\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C\uC5D0\uC11C \uC0AC\uC6A9\uB41C \uACF5\uD1B5 \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984 (\uC608: 'button', 'input', 'modal')"
272
- )
273
- })
190
+ description: "Get information about the current selection in Figma",
191
+ inputSchema: {}
274
192
  },
275
- async ({ componentName }) => {
276
- const similarFiles = findSimilarStoriesFiles(componentName);
277
- const texts = similarFiles.map(({ file }) => __RULES__[file]);
278
- return {
279
- content: [
280
- {
281
- type: "text",
282
- text: `${texts.join("")}`
283
- }
284
- ]
285
- };
286
- }
287
- );
288
- server.registerResource(
289
- "file",
290
- // 리소스 ID
291
- new import_mcp.ResourceTemplate("file://{path}/", {
292
- list: async () => {
193
+ async () => {
194
+ try {
195
+ const result = await sendCommandToFigma("get_selection");
293
196
  return {
294
- resources: RULES_FILES.map((filePath) => ({
295
- uri: `file://${filePath}`,
296
- name: filePath,
297
- title: filePath,
298
- description: "local file from design-rules",
299
- mimeType: "text/plain",
300
- _meta: {
301
- filePath
197
+ content: [
198
+ {
199
+ type: "text",
200
+ text: JSON.stringify(result, null, 2)
302
201
  }
303
- }))
202
+ ]
304
203
  };
305
- }
306
- }),
307
- {
308
- title: "design rule",
309
- description: "important rules and guidelines for resolving design data"
310
- },
311
- // resources/read 핸들러
312
- async (uri, props) => {
313
- const filePath = props.path;
314
- const text = __RULES__[filePath] ?? "";
315
- return {
316
- contents: [
317
- {
318
- uri: uri.href,
319
- mimeType: "text/plain",
320
- text
321
- }
322
- ]
323
- };
324
- }
325
- );
326
- server.registerPrompt(
327
- "data_analysis_strategy",
328
- {
329
- description: "Best practices for analyzing Figma design data"
330
- },
331
- () => {
332
- return {
333
- messages: [
334
- {
335
- role: "assistant",
336
- content: {
204
+ } catch (error) {
205
+ return {
206
+ content: [
207
+ {
337
208
  type: "text",
338
- text: `When analyzing Figma design data, follow these strategies
339
-
340
- 1. Data Extraction Workflow:
341
- - Use get_selection() to focus on specific areas of interest
342
- - Use get_document_info() when connection is enabled
343
-
344
- 2. Component Analysis:
345
- - Identify reusable components vs one-off elements
346
- - Look for design system patterns (colors, typography, spacing)
347
- - Note component variants and their properties
348
- - Extract design tokens (colors, fonts, spacing values)
349
-
350
- 3. Layout Analysis:
351
- - Analyze auto-layout settings and constraints
352
- - Document spacing patterns and grid systems
353
- - Identify responsive design patterns
354
- - Note alignment and positioning strategies
355
-
356
-
357
-
358
-
359
- `
209
+ text: `Error getting selection: ${error instanceof Error ? error.message : String(error)}`
360
210
  }
361
- }
362
- ],
363
- description: "Best practices for working with Figma designs"
364
- };
211
+ ]
212
+ };
213
+ }
365
214
  }
366
215
  );
367
216
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liner-fe/figma-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "bin": "dist/server/server.cjs",
6
6
  "files": [
@@ -65,7 +65,6 @@
65
65
  "start": "concurrently \"pnpm run socket\" \"pnpm run dev\" --names \"SOCKET,MCP\" --prefix-colors \"blue,green\"",
66
66
  "build:server": "pnpm tsup",
67
67
  "build": "pnpm build:server",
68
- "build:package": "pnpm build",
69
- "generate-from-link": "tsx src/generate-from-link.ts"
68
+ "build:package": "pnpm build"
70
69
  }
71
70
  }