import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { sendCommandToFigma } from "../communication";
import { logger } from "../logger";
/**
* Register scanning-related MCP tools
*/
export function registerScanningTools(server: McpServer): void {
// Scan Text Nodes
server.tool(
"scan_text_nodes",
"Scan and return all text nodes within a given node tree (useful for bulk text updates)",
{
nodeId: z.string().describe("The root node ID to scan for text nodes"),
useChunking: z
.boolean()
.optional()
.describe("Whether to return results in chunks (for large trees)"),
chunkSize: z
.number()
.optional()
.describe("Number of nodes per chunk (default: 50)"),
},
async ({ nodeId, useChunking, chunkSize }) => {
try {
const result = await sendCommandToFigma("scan_text_nodes", {
nodeId,
useChunking,
chunkSize,
});
return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
} catch (error) {
logger.error("Error scanning text nodes", error);
return {
content: [
{
type: "text",
text: `Error scanning text nodes: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
// Scan Nodes by Types
server.tool(
"scan_nodes_by_types",
"Scan and return all nodes of specified types within a node tree",
{
nodeId: z.string().describe("The root node ID to scan"),
types: z
.array(z.string())
.describe(
"Array of node types to find (e.g., ['FRAME', 'TEXT', 'RECTANGLE'])",
),
},
async ({ nodeId, types }) => {
try {
const result = await sendCommandToFigma("scan_nodes_by_types", {
nodeId,
types,
});
return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
} catch (error) {
logger.error("Error scanning nodes by types", error);
return {
content: [
{
type: "text",
text: `Error scanning nodes by types: ${
error instanceof Error ? error.message : String(error)
}`,
},
],
};
}
},
);
}