Skip to main content
Glama

image-tools-mcp

figma.ts7.72 kB
import fetch from "node-fetch"; /** * 从 Figma URL 中提取 fileKey 和 nodeId * @param figmaUrl - Figma 设计链接 * @returns 包含 fileKey 和 nodeId 的对象 */ export function extractFigmaParams(figmaUrl: string): { fileKey: string; nodeId: string; } { // 支持两种格式的 URL: // 1. https://www.figma.com/file/fileKey/title // 2. https://www.figma.com/design/fileKey/title?node-id=nodeId let fileKey = ""; let nodeId = ""; try { const url = new URL(figmaUrl); // 从路径中提取 fileKey const pathParts = url.pathname.split("/"); if (pathParts.length >= 3) { // 路径格式为 /file/fileKey/title 或 /design/fileKey/title fileKey = pathParts[2]; } // 从查询参数中提取 nodeId const nodeIdParam = url.searchParams.get("node-id"); if (nodeIdParam) { nodeId = nodeIdParam; } if (!fileKey) { throw new Error("无法从 URL 中提取 fileKey"); } return { fileKey, nodeId }; } catch (error) { throw new Error(`解析 Figma URL 失败: ${(error as Error).message}`); } } // 定义 Figma API 的基础 URL const FIGMA_API_BASE_URL = "https://api.figma.com/v1"; // 定义 Figma API 错误响应类型 interface FigmaApiError { err: string; status?: number; // 有时 API 会在 err 平级返回 status } // 定义 Figma API 成功获取图像的响应类型 interface FigmaImageResponse { images: { [nodeId: string]: string | null }; err?: string; // 成功响应也可能带有 err 字段,尽管通常是 null 或 undefined } // 定义 getImage 函数的参数类型接口 interface GetImageParams { fileKey: string; nodeIds: string[]; // 节点 ID 数组 figmaToken: string; // Figma API 访问令牌 scale?: number; // 图像缩放比例 format?: "jpg" | "png" | "svg" | "pdf"; // 图像格式 svg_include_id?: boolean; // SVG 是否包含 ID svg_simplify_stroke?: boolean; // SVG 是否简化描边 use_absolute_bounds?: boolean; // 是否使用绝对边界 version?: string; // 文件版本 } /** * 从 Figma API 获取图像 URL。 * @param params - 包含 fileKey, nodeIds 和 figmaToken 的对象。 * @returns 返回一个包含图像 URL 的 Promise。 * @throws 如果 API 请求失败,则抛出错误。 */ export async function getImage( params: GetImageParams, ): Promise<{ [nodeId: string]: string | null }> { const { fileKey, nodeIds, figmaToken, scale, format, svg_include_id, svg_simplify_stroke, use_absolute_bounds, version, } = params; // 构建 API 请求 URL,包含节点 ID let apiUrl = `${FIGMA_API_BASE_URL}/images/${fileKey}?ids=${nodeIds.join(",")}`; // 添加可选参数到 URL if (scale !== undefined) { apiUrl += `&scale=${scale}`; } if (format !== undefined) { apiUrl += `&format=${format}`; } if (svg_include_id !== undefined && format === "svg") { apiUrl += `&svg_include_id=${svg_include_id}`; } if (svg_simplify_stroke !== undefined && format === "svg") { apiUrl += `&svg_simplify_stroke=${svg_simplify_stroke}`; } if (use_absolute_bounds !== undefined) { apiUrl += `&use_absolute_bounds=${use_absolute_bounds}`; } if (version !== undefined) { apiUrl += `&version=${version}`; } // 发起 API 请求 const response = await fetch(apiUrl, { method: "GET", // HTTP 请求方法 headers: { "X-FIGMA-TOKEN": figmaToken, // Figma API 访问令牌 }, }); // 检查响应状态 if (!response.ok) { // 如果响应状态不为 OK,则抛出错误 const errorData = (await response.json()) as FigmaApiError; throw new Error( `Figma API request failed with status ${response.status}: ${errorData.err}`, ); } // 解析响应数据为 JSON 格式 const data = (await response.json()) as FigmaImageResponse; // 检查返回数据中是否包含错误信息 if (data.err) { // 如果包含错误信息,则抛出错误 throw new Error(`Figma API error: ${data.err}`); } // 返回图像数据 return data.images; } /** * 从 Figma API 获取图片信息 * @param figmaUrl - Figma 设计链接 * @param nodeIds - 可选的节点 ID 数组。 * @param scale - 图像缩放比例 * @param format - 图像格式 * @param svg_include_id - SVG 是否包含 ID * @param svg_simplify_stroke - SVG 是否简化描边 * @param use_absolute_bounds - 是否使用绝对边界 * @param version - 文件版本 * @returns 返回一个包含图片信息或错误信息的对象。 */ export async function getFigmaImages( figmaUrl: string, nodeIds?: string[], scale?: number, format?: "jpg" | "png" | "svg" | "pdf", svg_include_id?: boolean, svg_simplify_stroke?: boolean, use_absolute_bounds?: boolean, version?: string, ): Promise<FigmaImageResponse> { try { // 检查 FIGMA_API_TOKEN 是否已设置 const figmaToken = process.env.FIGMA_API_TOKEN; if (!figmaToken) { // 如果未设置 FIGMA_API_TOKEN,则抛出错误 throw new Error( "FIGMA_API_TOKEN 环境变量未设置。请在配置文件中设置。例:FIGMA_API_TOKEN=your_token", ); } // 从 Figma URL 中提取 fileKey 和 nodeId const { fileKey, nodeId: nodeIdFromUrl } = extractFigmaParams(figmaUrl); // 确定要获取图片的节点 ID 列表 let idsToFetch: string[] = []; if (nodeIds && nodeIds.length > 0) { // 如果提供了 nodeIds 数组,则使用该数组 idsToFetch = nodeIds; } else if (nodeIdFromUrl) { // 否则,如果 URL 中包含 nodeId,则使用该 nodeId idsToFetch = [nodeIdFromUrl]; } else { // 如果两者都未提供,则抛出错误 throw new Error("未提供节点 ID,无法获取图片"); } // 构建 API 请求参数 const params: GetImageParams = { fileKey, nodeIds: idsToFetch, figmaToken, scale, format, svg_include_id, svg_simplify_stroke, use_absolute_bounds, version, }; // 发起请求 const images = await getImage(params); return { images, }; } catch (error: unknown) { // 打印错误信息到控制台 console.error("获取 Figma 图片失败:", error); // 返回包含错误信息的对象 const errorMessage = error instanceof Error ? error.message : "获取 Figma 图片时发生未知错误"; return { images: {}, err: errorMessage, }; } } /** * 下载 Figma 图片到本地 * @param imageUrl - Figma 图片 URL * @param outputPath - 输出文件路径 * @returns 包含下载结果的对象 */ export async function downloadFigmaImage( imageUrl: string, outputPath: string, ): Promise<{ success: boolean; path?: string; error?: string }> { try { const fs = await import("fs"); const { finished } = await import("stream/promises"); // 发起请求获取图片 const response = await fetch(imageUrl); if (!response.ok) { throw new Error(`下载图片失败: HTTP ${response.status}`); } // 创建写入流 const fileStream = fs.createWriteStream(outputPath); // 将响应体作为流传输到文件 // 使用 unknown 作为中间类型,避免类型错误 const buffer = Buffer.from(await response.arrayBuffer()); const readableStream = (await import("stream")).Readable.from(buffer); await finished(readableStream.pipe(fileStream)); return { success: true, path: outputPath, }; } catch (error) { console.error("下载 Figma 图片失败:", error); return { success: false, error: `下载 Figma 图片失败: ${(error as Error).message}`, }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kshern/image-tools-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server