mirror of
https://github.com/penpot/penpot-mcp.git
synced 2026-04-25 11:18:37 +00:00
Add ExportShapeTool
This commit is contained in:
parent
223d6d50b0
commit
ad771ee92f
@ -11,6 +11,7 @@ import { createLogger } from "./logger";
|
||||
import { Tool } from "./Tool";
|
||||
import { HighLevelOverviewTool } from "./tools/HighLevelOverviewTool";
|
||||
import { PenpotApiInfoTool } from "./tools/PenpotApiInfoTool";
|
||||
import { ExportShapeTool } from "./tools/ExportShapeTool";
|
||||
|
||||
export class PenpotMcpServer {
|
||||
private readonly logger = createLogger("PenpotMcpServer");
|
||||
@ -58,6 +59,7 @@ export class PenpotMcpServer {
|
||||
new ExecuteCodeTool(this),
|
||||
new HighLevelOverviewTool(this),
|
||||
new PenpotApiInfoTool(this),
|
||||
new ExportShapeTool(this),
|
||||
];
|
||||
|
||||
for (const tool of toolInstances) {
|
||||
|
||||
@ -22,11 +22,27 @@ class ImageContent implements ImageItem {
|
||||
public data: string,
|
||||
public mimeType: string
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param data - PNG image data as Uint8Array or as object (from JSON conversion of Uint8Array)
|
||||
*/
|
||||
protected static byteData(data: Uint8Array | object): Uint8Array {
|
||||
if (typeof data === "object") {
|
||||
// convert object (as obtained from JSON conversion of Uint8Array) back to Uint8Array
|
||||
return new Uint8Array(Object.values(data) as number[]);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PNGImageContent extends ImageContent {
|
||||
constructor(data: Uint8Array) {
|
||||
super(Buffer.from(data).toString("base64"), "image/png");
|
||||
/**
|
||||
* @param data - PNG image data as Uint8Array or as object (from JSON conversion of Uint8Array)
|
||||
*/
|
||||
constructor(data: Uint8Array | object) {
|
||||
let array = ImageContent.byteData(data);
|
||||
super(Buffer.from(array).toString("base64"), "image/png");
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,3 +59,12 @@ export class TextResponse extends ToolResponse {
|
||||
super([new TextContent(text)]);
|
||||
}
|
||||
}
|
||||
|
||||
export class PNGResponse extends ToolResponse {
|
||||
/**
|
||||
* @param data - PNG image data as Uint8Array or as object (from JSON conversion of Uint8Array)
|
||||
*/
|
||||
constructor(data: Uint8Array | object) {
|
||||
super([new PNGImageContent(data)]);
|
||||
}
|
||||
}
|
||||
|
||||
63
mcp-server/src/tools/ExportShapeTool.ts
Normal file
63
mcp-server/src/tools/ExportShapeTool.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { z } from "zod";
|
||||
import { Tool } from "../Tool";
|
||||
import { PNGResponse, ToolResponse } from "../ToolResponse";
|
||||
import "reflect-metadata";
|
||||
import { PenpotMcpServer } from "../PenpotMcpServer";
|
||||
import { ExecuteCodePluginTask } from "../tasks/ExecuteCodePluginTask";
|
||||
import { ExecuteCodeTaskParams } from "@penpot-mcp/common";
|
||||
|
||||
/**
|
||||
* Arguments class for ExecuteCodeTool
|
||||
*/
|
||||
export class ExportShapeArgs {
|
||||
static schema = {
|
||||
shapeId: z.string().min(1, "shapeId cannot be empty"),
|
||||
};
|
||||
|
||||
/**
|
||||
* Identifier of the shape to export.
|
||||
* The special identifier "selection" can be used to refer to the (first) currently selected shape.
|
||||
*/
|
||||
shapeId!: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool for executing JavaScript code in the Penpot plugin context
|
||||
*/
|
||||
export class ExportShapeTool extends Tool<ExportShapeArgs> {
|
||||
/**
|
||||
* Creates a new ExecuteCode tool instance.
|
||||
*
|
||||
* @param mcpServer - The MCP server instance
|
||||
*/
|
||||
constructor(mcpServer: PenpotMcpServer) {
|
||||
super(mcpServer, ExportShapeArgs.schema);
|
||||
}
|
||||
|
||||
public getToolName(): string {
|
||||
return "export_shapes";
|
||||
}
|
||||
|
||||
public getToolDescription(): string {
|
||||
return (
|
||||
"Exports a shape from the Penpot design to a PNG image, such that you can get an impression of what the shape looks like.\n" +
|
||||
"Parameter `shapeId`: identifier of the shapes to export. Use the special identifier 'selection' to " +
|
||||
"export the first shape currently selected by the user."
|
||||
);
|
||||
}
|
||||
|
||||
protected async executeCore(args: ExportShapeArgs): Promise<ToolResponse> {
|
||||
// create code for exporting the shape
|
||||
let taskParams: ExecuteCodeTaskParams;
|
||||
if (args.shapeId === "selection") {
|
||||
taskParams = { code: 'return penpot.selection[0].export({"type": "png"});' };
|
||||
} else {
|
||||
throw new Error("Identifiers other than 'selection' are not yet supported");
|
||||
}
|
||||
|
||||
// execute the code and return the response
|
||||
const task = new ExecuteCodePluginTask(taskParams);
|
||||
const result = await this.mcpServer.pluginBridge.executePluginTask(task);
|
||||
return new PNGResponse(result.data!.result);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user