mirror of
https://github.com/penpot/penpot-mcp.git
synced 2026-04-25 11:18:37 +00:00
Add PenpotApiInfoTool
This commit is contained in:
parent
d972e1ed71
commit
74ff6a12df
@ -39,8 +39,9 @@ penpot-mcp/
|
||||
|
||||
### Adding a new Tool
|
||||
|
||||
* Implement the tool class in `mcp-server/src/tools/` following the `Tool` interface.
|
||||
* IMPORTANT: Do not catch any exceptions in the `executeCore` method. Let them propagate to be handled centrally.
|
||||
1. Implement the tool class in `mcp-server/src/tools/` following the `Tool` interface.
|
||||
IMPORTANT: Do not catch any exceptions in the `executeCore` method. Let them propagate to be handled centrally.
|
||||
2. Register the tool in `PenpotMcpServer`.
|
||||
|
||||
Look at `PrintTextTool` as an example.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ initial_instructions: |
|
||||
One of the key tools is the execute_code tool, which allows you to run JavaScript code using the Penpot Plugin API
|
||||
directly in the connected project.
|
||||
|
||||
When writing code, a key object is the `penpot` object which provides key functionality:
|
||||
When writing code, a key object is the `penpot` object (which is of type `Penpot`). It provides useful functionality:
|
||||
* `penpot.selection` provides the list of elements the user has selected in the Penpot UI.
|
||||
If it is unclear which elements to work on, you can ask the user to select them for you.
|
||||
* Generation of CSS content for elements:
|
||||
@ -24,7 +24,7 @@ initial_instructions: |
|
||||
type?: "html" | "svg";
|
||||
}): string;
|
||||
|
||||
For example, to generate CSS for the selected elements, you can execute this:
|
||||
For example, to generate CSS for the currently selected elements, you can execute this:
|
||||
return penpot.generateStyle(penpot.selection, { type: "css", withChildren: true });
|
||||
|
||||
You have hereby read the 'Penpot High-Level Overview' and need not use a tool to read it again.
|
||||
|
||||
@ -3,7 +3,7 @@ import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
/**
|
||||
* Represents a single API type with its documentation.
|
||||
* Represents a single type/interface defined in the Penpot API
|
||||
*/
|
||||
export class ApiType {
|
||||
private readonly name: string;
|
||||
@ -24,6 +24,13 @@ export class ApiType {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overview text of this API type (which all signature/type declarations)
|
||||
*/
|
||||
getOverviewText() {
|
||||
return this.overview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single markdown text document from all parts of this API type.
|
||||
*
|
||||
|
||||
@ -10,6 +10,7 @@ import { ConfigurationLoader } from "./ConfigurationLoader";
|
||||
import { createLogger } from "./logger";
|
||||
import { Tool } from "./Tool";
|
||||
import { HighLevelOverviewTool } from "./tools/HighLevelOverviewTool";
|
||||
import { PenpotApiInfoTool } from "./tools/PenpotApiInfoTool";
|
||||
|
||||
export class PenpotMcpServer {
|
||||
private readonly logger = createLogger("PenpotMcpServer");
|
||||
@ -56,6 +57,7 @@ export class PenpotMcpServer {
|
||||
new PrintTextTool(this),
|
||||
new ExecuteCodeTool(this),
|
||||
new HighLevelOverviewTool(this),
|
||||
new PenpotApiInfoTool(this),
|
||||
];
|
||||
|
||||
for (const tool of toolInstances) {
|
||||
|
||||
@ -40,16 +40,19 @@ export class ExecuteCodeTool extends Tool<ExecuteCodeArgs> {
|
||||
|
||||
public getToolDescription(): string {
|
||||
return (
|
||||
"Executes JavaScript code in the Penpot plugin context. " +
|
||||
"Two objects are available: `penpot` (the Penpot API) and `storage` (an object in which arbitrary " +
|
||||
"Executes JavaScript code in the Penpot plugin context.\n" +
|
||||
"IMPORTANT: Before using this tool, make sure you have read the 'Penpot High-Level Overview' and know " +
|
||||
"which Penpot API functionality is necessary and how to use it.\n" +
|
||||
"You have access two main objects: `penpot` (the Penpot API, of type `Penpot`) and `storage` (an object in which arbitrary " +
|
||||
"data can be stored, simply by adding a new attribute; stored attributes can be referenced in future calls " +
|
||||
"to this tool, so any intermediate results that could come in handy later should be stored in `storage` " +
|
||||
"instead of just a fleeting variable).\n" +
|
||||
"The tool call returns the value of the concluding `return` statement, if any.\n" +
|
||||
"Any output that you generate via the `console` object will be returned to you; so you may use this" +
|
||||
"to track what your code is doing, but you should only do so only if there is an actual need!.\n" +
|
||||
"In general, try a simple approach first, and only if it fails, try more complex code that involves " +
|
||||
"handling different cases (in particular error cases)."
|
||||
"to track what your code is doing, but you should only do so only if there is an actual need for this! " +
|
||||
"IMPORTANT: Don't use logging prematurely!\n" +
|
||||
"VERY IMPORTANT: In general, try a simple approach first, and only if it fails, try more complex code that involves " +
|
||||
"handling different cases (in particular error cases) and that applies logging."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
85
mcp-server/src/tools/PenpotApiInfoTool.ts
Normal file
85
mcp-server/src/tools/PenpotApiInfoTool.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { z } from "zod";
|
||||
import { Tool } from "../Tool";
|
||||
import "reflect-metadata";
|
||||
import type { ToolResponse } from "../ToolResponse";
|
||||
import { TextResponse } from "../ToolResponse";
|
||||
import { PenpotMcpServer } from "../PenpotMcpServer";
|
||||
import { ApiDocs } from "../ApiDocs";
|
||||
|
||||
/**
|
||||
* Arguments class for the PenpotApiInfo tool with validation decorators.
|
||||
*/
|
||||
export class PenpotApiInfoArgs {
|
||||
static schema = {
|
||||
type: z.string().min(1, "Type name cannot be empty"),
|
||||
member: z.string().optional(),
|
||||
};
|
||||
|
||||
/**
|
||||
* The API type name to retrieve information for.
|
||||
*/
|
||||
type!: string;
|
||||
|
||||
/**
|
||||
* The specific member name to retrieve (optional).
|
||||
*/
|
||||
member?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool for retrieving Penpot API documentation information.
|
||||
*
|
||||
* This tool provides access to API type documentation loaded from YAML files,
|
||||
* allowing retrieval of either full type documentation or specific member details.
|
||||
*/
|
||||
export class PenpotApiInfoTool extends Tool<PenpotApiInfoArgs> {
|
||||
private static readonly MAX_FULL_TEXT_CHARS = 2000;
|
||||
private readonly apiDocs: ApiDocs;
|
||||
|
||||
/**
|
||||
* Creates a new PenpotApiInfo tool instance.
|
||||
*
|
||||
* @param mcpServer - The MCP server instance
|
||||
*/
|
||||
constructor(mcpServer: PenpotMcpServer) {
|
||||
super(mcpServer, PenpotApiInfoArgs.schema);
|
||||
this.apiDocs = new ApiDocs();
|
||||
}
|
||||
|
||||
public getToolName(): string {
|
||||
return "penpot_api_info";
|
||||
}
|
||||
|
||||
public getToolDescription(): string {
|
||||
return "Retrieves Penpot API documentation for types and their members";
|
||||
}
|
||||
|
||||
protected async executeCore(args: PenpotApiInfoArgs): Promise<ToolResponse> {
|
||||
const apiType = this.apiDocs.getType(args.type);
|
||||
|
||||
if (!apiType) {
|
||||
throw new Error(`API type "${args.type}" not found`);
|
||||
}
|
||||
|
||||
if (args.member) {
|
||||
// return specific member documentation
|
||||
const memberDoc = apiType.getMember(args.member);
|
||||
if (!memberDoc) {
|
||||
throw new Error(`Member "${args.member}" not found in type "${args.type}"`);
|
||||
}
|
||||
return new TextResponse(memberDoc);
|
||||
} else {
|
||||
// return full text or overview based on length
|
||||
const fullText = apiType.getFullText();
|
||||
if (fullText.length <= PenpotApiInfoTool.MAX_FULL_TEXT_CHARS) {
|
||||
return new TextResponse(fullText);
|
||||
} else {
|
||||
return new TextResponse(
|
||||
apiType.getOverviewText() +
|
||||
"\n\nMember details not provided (too long). " +
|
||||
"Call this tool with a member name for more information."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user