/**
* MCP tool: get_figma_context
* Extracts design context (layout, styles, text) from a Figma URL.
*/
import {z} from 'zod';
import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
import type {FigmaClient} from '../figma-client.js';
import {parseFigmaUrl} from '../url-parser.js';
import {simplifyNode} from '../transformers/index.js';
const inputSchema = {
figmaUrl: z.string().url().describe('Figma design URL (supports /design/, /file/, /proto/, /board/)'),
depth: z.number().int().min(1).max(10).default(3).describe('Maximum depth to traverse the node tree (default: 3)'),
};
export function registerGetFigmaContext(server: McpServer, client: FigmaClient): void {
server.tool(
'get_figma_context',
'Extract design context (layout, styles, text, dimensions) from a Figma URL as CSS-like properties',
inputSchema,
async ({figmaUrl, depth}) => {
const {fileKey, nodeId} = parseFigmaUrl(figmaUrl);
/* eslint-disable @typescript-eslint/no-explicit-any */
let nodes: Record<string, any>;
if (nodeId) {
const response = await client.getFileNodes(fileKey, [nodeId], depth);
nodes = (response as any).nodes ?? {};
} else {
const response = await client.getFile(fileKey, undefined, depth);
// Wrap the document node so the output is consistent
const doc = (response as any).document;
if (doc) {
nodes = {document: {document: doc}};
} else {
nodes = {};
}
}
const simplified = [];
for (const [id, nodeData] of Object.entries(nodes)) {
const rawNode = (nodeData as any)?.document ?? nodeData;
const result = simplifyNode(rawNode, 0, depth);
if (result) {
result.id = result.id || id;
simplified.push(result);
}
}
if (simplified.length === 0) {
return {
content: [{type: 'text' as const, text: 'No visible nodes found at the specified URL.'}],
};
}
return {
content: [{type: 'text' as const, text: JSON.stringify(simplified, null, 2)}],
};
},
);
}