import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { sendCommandToFigma } from "../communication";
import { logger } from "../logger";
/**
* Register auto-layout related MCP tools
*/
export function registerLayoutTools(server: McpServer): void {
// Set Layout Mode
server.tool(
"set_layout_mode",
"Set the auto-layout mode of a frame in Figma",
{
nodeId: z.string().describe("The ID of the frame to modify"),
layoutMode: z
.enum(["NONE", "HORIZONTAL", "VERTICAL"])
.describe("The layout mode to set"),
layoutWrap: z
.enum(["NO_WRAP", "WRAP"])
.optional()
.describe("Whether the frame should wrap its children"),
},
async ({ nodeId, layoutMode, layoutWrap }) => {
try {
const result = await sendCommandToFigma<{ name: string }>(
"set_layout_mode",
{ nodeId, layoutMode, layoutWrap },
);
return {
content: [
{
type: "text",
text: `Set layout mode of "${result.name}" to ${layoutMode}${
layoutWrap ? ` with wrap: ${layoutWrap}` : ""
}`,
},
],
};
} catch (error) {
logger.error("Error setting layout mode", error);
return {
content: [
{
type: "text",
text: `Error setting layout mode: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
// Set Padding
server.tool(
"set_padding",
"Set the padding of an auto-layout frame in Figma",
{
nodeId: z.string().describe("The ID of the frame to modify"),
paddingTop: z.number().optional().describe("Top padding"),
paddingRight: z.number().optional().describe("Right padding"),
paddingBottom: z.number().optional().describe("Bottom padding"),
paddingLeft: z.number().optional().describe("Left padding"),
},
async ({
nodeId,
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
}) => {
try {
const result = await sendCommandToFigma<{ name: string }>(
"set_padding",
{ nodeId, paddingTop, paddingRight, paddingBottom, paddingLeft },
);
return {
content: [
{
type: "text",
text: `Set padding of "${result.name}" to top:${paddingTop ?? 0}, right:${paddingRight ?? 0}, bottom:${paddingBottom ?? 0}, left:${paddingLeft ?? 0}`,
},
],
};
} catch (error) {
logger.error("Error setting padding", error);
return {
content: [
{
type: "text",
text: `Error setting padding: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
// Set Axis Alignment
server.tool(
"set_axis_align",
"Set the axis alignment of an auto-layout frame in Figma",
{
nodeId: z.string().describe("The ID of the frame to modify"),
primaryAxisAlignItems: z
.enum(["MIN", "MAX", "CENTER", "SPACE_BETWEEN"])
.optional()
.describe("Primary axis alignment"),
counterAxisAlignItems: z
.enum(["MIN", "MAX", "CENTER", "BASELINE"])
.optional()
.describe("Counter axis alignment"),
},
async ({ nodeId, primaryAxisAlignItems, counterAxisAlignItems }) => {
try {
const result = await sendCommandToFigma<{ name: string }>(
"set_axis_align",
{ nodeId, primaryAxisAlignItems, counterAxisAlignItems },
);
return {
content: [
{
type: "text",
text: `Set axis alignment of "${result.name}"`,
},
],
};
} catch (error) {
logger.error("Error setting axis alignment", error);
return {
content: [
{
type: "text",
text: `Error setting axis alignment: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
// Set Layout Sizing
server.tool(
"set_layout_sizing",
"Set the sizing mode of an auto-layout frame in Figma",
{
nodeId: z.string().describe("The ID of the frame to modify"),
layoutSizingHorizontal: z
.enum(["FIXED", "HUG", "FILL"])
.optional()
.describe("Horizontal sizing mode"),
layoutSizingVertical: z
.enum(["FIXED", "HUG", "FILL"])
.optional()
.describe("Vertical sizing mode"),
},
async ({ nodeId, layoutSizingHorizontal, layoutSizingVertical }) => {
try {
const result = await sendCommandToFigma<{ name: string }>(
"set_layout_sizing",
{ nodeId, layoutSizingHorizontal, layoutSizingVertical },
);
return {
content: [
{
type: "text",
text: `Set layout sizing of "${result.name}"`,
},
],
};
} catch (error) {
logger.error("Error setting layout sizing", error);
return {
content: [
{
type: "text",
text: `Error setting layout sizing: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
// Set Item Spacing
server.tool(
"set_item_spacing",
"Set the spacing between items in an auto-layout frame in Figma",
{
nodeId: z.string().describe("The ID of the frame to modify"),
itemSpacing: z
.number()
.optional()
.describe("Spacing between items on primary axis"),
counterAxisSpacing: z
.number()
.optional()
.describe("Spacing between items on counter axis (for wrapped frames)"),
},
async ({ nodeId, itemSpacing, counterAxisSpacing }) => {
try {
const result = await sendCommandToFigma<{ name: string }>(
"set_item_spacing",
{ nodeId, itemSpacing, counterAxisSpacing },
);
return {
content: [
{
type: "text",
text: `Set item spacing of "${result.name}" to ${itemSpacing ?? 0}`,
},
],
};
} catch (error) {
logger.error("Error setting item spacing", error);
return {
content: [
{
type: "text",
text: `Error setting item spacing: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
}