@liner-fe/figma-mcp 1.0.2 → 1.0.3
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.
- package/dist/server/server.cjs +1 -117
- package/package.json +1 -1
package/dist/server/server.cjs
CHANGED
|
@@ -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: "@
|
|
138
|
+
name: "@liner-fe/figma-mcp",
|
|
188
139
|
version: "1.0.0"
|
|
189
140
|
},
|
|
190
141
|
{
|
|
@@ -256,73 +207,6 @@ server.registerPrompt(
|
|
|
256
207
|
};
|
|
257
208
|
}
|
|
258
209
|
);
|
|
259
|
-
server.registerTool(
|
|
260
|
-
"get_rule_of_components",
|
|
261
|
-
{
|
|
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
|
-
})
|
|
274
|
-
},
|
|
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 () => {
|
|
293
|
-
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
|
|
302
|
-
}
|
|
303
|
-
}))
|
|
304
|
-
};
|
|
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
210
|
server.registerPrompt(
|
|
327
211
|
"data_analysis_strategy",
|
|
328
212
|
{
|