In multi-user mode, disable file system access in tools #20

This commit is contained in:
Dominik Jain 2025-12-16 22:50:10 +01:00
parent 02da2b4b19
commit 445cf728b8
2 changed files with 33 additions and 7 deletions

View File

@ -67,10 +67,23 @@ export class PenpotMcpServer {
this.registerTools(); this.registerTools();
} }
/**
* Indicates whether the server is running in multi-user mode,
* where user tokens are required for authentication.
*/
public isMultiUserMode(): boolean { public isMultiUserMode(): boolean {
return this.isMultiUser; return this.isMultiUser;
} }
/**
* Indicates whether file system access is enabled for MCP tools.
* Access is enabled only in single-user mode, where the file system is assumed
* to belong to the user running the server locally.
*/
public isFileSystemAccessEnabled(): boolean {
return !this.isMultiUserMode();
}
public getInitialInstructions(): string { public getInitialInstructions(): string {
let instructions = this.configLoader.getInitialInstructions(); let instructions = this.configLoader.getInitialInstructions();
instructions = instructions.replace("$api_types", this.apiDocs.getTypeNames().join(", ")); instructions = instructions.replace("$api_types", this.apiDocs.getTypeNames().join(", "));
@ -87,13 +100,16 @@ export class PenpotMcpServer {
} }
private registerTools(): void { private registerTools(): void {
// Create relevant tool instances (depending on file system access)
const toolInstances: Tool<any>[] = [ const toolInstances: Tool<any>[] = [
new ExecuteCodeTool(this), new ExecuteCodeTool(this),
new HighLevelOverviewTool(this), new HighLevelOverviewTool(this),
new PenpotApiInfoTool(this, this.apiDocs), new PenpotApiInfoTool(this, this.apiDocs),
new ExportShapeTool(this), new ExportShapeTool(this), // tool adapts to file system access internally
new ImportImageTool(this),
]; ];
if (this.isFileSystemAccessEnabled()) {
toolInstances.push(new ImportImageTool(this));
}
for (const tool of toolInstances) { for (const tool of toolInstances) {
const toolName = tool.getToolName(); const toolName = tool.getToolName();

View File

@ -45,7 +45,13 @@ export class ExportShapeTool extends Tool<ExportShapeArgs> {
* @param mcpServer - The MCP server instance * @param mcpServer - The MCP server instance
*/ */
constructor(mcpServer: PenpotMcpServer) { constructor(mcpServer: PenpotMcpServer) {
super(mcpServer, ExportShapeArgs.schema); let schema: any = ExportShapeArgs.schema;
if (!mcpServer.isFileSystemAccessEnabled()) {
// remove filePath key from schema
schema = { ...schema };
delete schema.filePath;
}
super(mcpServer, schema);
} }
public getToolName(): string { public getToolName(): string {
@ -53,11 +59,11 @@ export class ExportShapeTool extends Tool<ExportShapeArgs> {
} }
public getToolDescription(): string { public getToolDescription(): string {
return ( let description =
"Exports a shape from the Penpot design to a PNG or SVG image, " + "Exports a shape from the Penpot design to a PNG or SVG image, " +
"such that you can get an impression of what the shape looks like.\n" + "such that you can get an impression of what the shape looks like.";
"Alternatively, you can save it to a file." if (this.mcpServer.isFileSystemAccessEnabled()) description += "\nAlternatively, you can save it to a file.";
); return description;
} }
protected async executeCore(args: ExportShapeArgs): Promise<ToolResponse> { protected async executeCore(args: ExportShapeArgs): Promise<ToolResponse> {
@ -89,6 +95,10 @@ export class ExportShapeTool extends Tool<ExportShapeArgs> {
return TextResponse.fromData(imageData); return TextResponse.fromData(imageData);
} }
} else { } else {
// make sure file system access is enabled
if (!this.mcpServer.isFileSystemAccessEnabled()) {
throw new Error("File system access is not enabled on the MCP server!");
}
// save image to file // save image to file
if (args.format === "png") { if (args.format === "png") {
FileUtils.writeBinaryFile(args.filePath, PNGImageContent.byteData(imageData)); FileUtils.writeBinaryFile(args.filePath, PNGImageContent.byteData(imageData));