Skip to main content
Glama

get_figma_styles

Extract style data and CSS from Figma design nodes using file URLs to analyze design elements and retrieve visual properties.

Instructions

根据Figma URL获取节点的样式数据

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesFigma文件URL,可以包含node-id参数指定特定节点
generateCSSNo是否生成CSS代码

Implementation Reference

  • Core handler that parses Figma URL, fetches file and node, extracts relevant styled nodes, and computes style data for the get_figma_styles tool.
    async getStylesFromUrl(figmaUrl: string): Promise<ComponentStyles> {
      try {
        const urlInfo = this.figmaService.parseUrl(figmaUrl);
        const { fileId, nodeId } = urlInfo;
    
        const file = await this.figmaService.getFile(fileId);
        
        let targetNodes: FigmaNode[] = [];
    
        if (nodeId) {
          // 获取特定节点
          const node = await this.figmaService.getNode(fileId, nodeId);
          if (node) {
            targetNodes = [node];
          }
        } else {
          // 获取整个文件的主要组件
          targetNodes = this.extractMainComponents(file.document);
        }
    
        const styles = targetNodes.map(node => this.extractNodeStyle(node));
    
        return {
          fileInfo: {
            fileId,
            fileName: file.name,
            lastModified: file.lastModified,
          },
          styles,
          globalStyles: file.styles,
        };
      } catch (error) {
        throw new Error(`获取样式数据失败: ${error instanceof Error ? error.message : '未知错误'}`);
      }
    }
  • Tool dispatch handler in switch statement that calls the style extractor and formats response, optionally generating CSS.
    private async handleGetStyles(args: any) {
      const { url, generateCSS = false } = args;
    
      const styleData = await this.styleExtractor.getStylesFromUrl(url);
    
      let cssCode = '';
      if (generateCSS && styleData.styles.length > 0) {
        const cssRules = styleData.styles.map(style => {
          const selector = `.${style.nodeName.toLowerCase().replace(/\\s+/g, '-')}`;
          const css = this.styleExtractor.generateCSS(style);
          return css ? `${selector} {\\n  ${css}\\n}` : '';
        }).filter(rule => rule);
    
        cssCode = cssRules.join('\\n\\n');
      }
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              success: true,
              data: {
                fileInfo: styleData.fileInfo,
                styles: styleData.styles,
                globalStyles: styleData.globalStyles,
                ...(cssCode && { generatedCSS: cssCode }),
              },
            }, null, 2),
          },
        ],
      };
    }
  • src/index.ts:75-93 (registration)
    Tool registration including name, description, and input schema in the ListTools response.
    {
      name: 'get_figma_styles',
      description: '根据Figma URL获取节点的样式数据',
      inputSchema: {
        type: 'object',
        properties: {
          url: {
            type: 'string',
            description: 'Figma文件URL,可以包含node-id参数指定特定节点',
          },
          generateCSS: {
            type: 'boolean',
            description: '是否生成CSS代码',
            default: false,
          },
        },
        required: ['url'],
      },
    },
  • Type definitions for style data structures used as output schema for the tool.
    export interface StyleData {
      nodeId: string;
      nodeName: string;
      nodeType: string;
      position?: {
        x: number;
        y: number;
        width: number;
        height: number;
      };
      fills?: Array<{
        type: string;
        color?: {
          r: number;
          g: number;
          b: number;
          a: number;
        };
        gradientStops?: Array<{
          color: { r: number; g: number; b: number; a: number };
          position: number;
        }>;
      }>;
      strokes?: Array<{
        type: string;
        color?: {
          r: number;
          g: number;
          b: number;
          a: number;
        };
      }>;
      strokeWeight?: number;
      cornerRadius?: number;
      effects?: Array<{
        type: string;
        visible: boolean;
        radius?: number;
        color?: {
          r: number;
          g: number;
          b: number;
          a: number;
        };
        offset?: {
          x: number;
          y: number;
        };
      }>;
      textStyle?: {
        fontFamily?: string;
        fontSize?: number;
        fontWeight?: number;
        letterSpacing?: number;
        lineHeight?: number;
        textAlign?: string;
        textColor?: {
          r: number;
          g: number;
          b: number;
          a: number;
        };
      };
      constraints?: {
        vertical: string;
        horizontal: string;
      };
    }
    
    export interface ComponentStyles {
      fileInfo: {
        fileId: string;
        fileName: string;
        lastModified: string;
      };
      styles: StyleData[];
      globalStyles?: Record<string, any>;
    }
  • Helper function to generate CSS from extracted style data, used when generateCSS=true.
    generateCSS(styleData: StyleData): string {
      const cssRules: string[] = [];
    
      // 位置和尺寸
      if (styleData.position) {
        cssRules.push(`width: ${styleData.position.width}px`);
        cssRules.push(`height: ${styleData.position.height}px`);
      }
    
      // 背景色
      if (styleData.fills && styleData.fills.length > 0) {
        const fill = styleData.fills[0];
        if (fill.color) {
          const { r, g, b, a } = fill.color;
          if (a === 1) {
            cssRules.push(`background-color: rgb(${r}, ${g}, ${b})`);
          } else {
            cssRules.push(`background-color: rgba(${r}, ${g}, ${b}, ${a})`);
          }
        }
      }
    
      // 边框
      if (styleData.strokes && styleData.strokes.length > 0) {
        const stroke = styleData.strokes[0];
        const weight = styleData.strokeWeight || 1;
        if (stroke.color) {
          const { r, g, b, a } = stroke.color;
          if (a === 1) {
            cssRules.push(`border: ${weight}px solid rgb(${r}, ${g}, ${b})`);
          } else {
            cssRules.push(`border: ${weight}px solid rgba(${r}, ${g}, ${b}, ${a})`);
          }
        }
      }
    
      // 圆角
      if (styleData.cornerRadius !== undefined) {
        cssRules.push(`border-radius: ${styleData.cornerRadius}px`);
      }
    
      // 文本样式
      if (styleData.textStyle) {
        const textStyle = styleData.textStyle;
        if (textStyle.fontFamily) {
          cssRules.push(`font-family: "${textStyle.fontFamily}"`);
        }
        if (textStyle.fontSize) {
          cssRules.push(`font-size: ${textStyle.fontSize}px`);
        }
        if (textStyle.fontWeight) {
          cssRules.push(`font-weight: ${textStyle.fontWeight}`);
        }
        if (textStyle.letterSpacing) {
          cssRules.push(`letter-spacing: ${textStyle.letterSpacing}px`);
        }
        if (textStyle.lineHeight) {
          cssRules.push(`line-height: ${textStyle.lineHeight}px`);
        }
        if (textStyle.textAlign) {
          cssRules.push(`text-align: ${textStyle.textAlign.toLowerCase()}`);
        }
        if (textStyle.textColor) {
          const { r, g, b, a } = textStyle.textColor;
          if (a === 1) {
            cssRules.push(`color: rgb(${r}, ${g}, ${b})`);
          } else {
            cssRules.push(`color: rgba(${r}, ${g}, ${b}, ${a})`);
          }
        }
      }
    
      // 阴影效果
      if (styleData.effects && styleData.effects.length > 0) {
        const shadows = styleData.effects
          .filter(effect => effect.type === 'DROP_SHADOW' && effect.visible)
          .map(effect => {
            const x = effect.offset?.x || 0;
            const y = effect.offset?.y || 0;
            const blur = effect.radius || 0;
            if (effect.color) {
              const { r, g, b, a } = effect.color;
              return `${x}px ${y}px ${blur}px rgba(${r}, ${g}, ${b}, ${a})`;
            }
            return '';
          })
          .filter(shadow => shadow);
    
        if (shadows.length > 0) {
          cssRules.push(`box-shadow: ${shadows.join(', ')}`);
        }
      }
    
      return cssRules.length > 0 ? cssRules.join(';\n  ') + ';' : '';
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool retrieves style data but doesn't cover important aspects like authentication needs, rate limits, error handling, or what specific style data is returned (e.g., colors, typography). This leaves significant gaps for an agent to understand the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence in Chinese that directly states the tool's purpose without any wasted words. It's appropriately sized and front-loaded with the core functionality.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of retrieving style data from Figma, no annotations, and no output schema, the description is incomplete. It doesn't explain what '样式数据' (style data) includes, how results are structured, or any behavioral traits like permissions or limitations, making it inadequate for full agent understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters ('url' and 'generateCSS') thoroughly. The description adds no additional parameter semantics beyond what's in the schema, such as URL format examples or CSS generation details, meeting the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as '获取节点的样式数据' (get node style data) from a Figma URL, which is a specific verb+resource combination. However, it doesn't explicitly differentiate this from sibling tools like 'get_node_svg' or 'extract_node_elements', which might also retrieve node-related data but in different formats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention sibling tools like 'get_node_svg' for SVG data or 'get_figma_image' for images, nor does it specify prerequisites or exclusions for usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/Echoxiawan/figma-mcp-full-server'

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