UNPKG

@allpepper/memory-bank-mcp

Version:

MCP server for remote management of project memory banks

136 lines (135 loc) 5.14 kB
import fs from "fs-extra"; import { join } from "path"; export class FileHandler { rootPath; constructor(config) { this.rootPath = config.rootPath; } getProjectPath(projectName) { return join(this.rootPath, projectName); } getFilePath(projectName, fileName) { return join(this.getProjectPath(projectName), fileName); } async validateProjectName(projectName) { // Prevent path traversal and ensure project name is valid if (!projectName || projectName.includes("..") || projectName.includes("/")) { return false; } return true; } async ensureProjectDirectory(projectName) { const projectPath = this.getProjectPath(projectName); await fs.ensureDir(projectPath); } async listDirectoryContents(path) { try { const contents = await fs.readdir(path); return contents; } catch (error) { return []; } } async handleCommand(command) { try { if (command.operation === "list_projects") { const contents = await this.listDirectoryContents(this.rootPath); return { success: true, content: JSON.stringify(contents), }; } if (command.operation === "list_project_files") { if (!(await this.validateProjectName(command.projectName))) { return { success: false, error: "Invalid project name. Must not contain '..' or '/'", }; } const projectPath = this.getProjectPath(command.projectName); if (!(await fs.pathExists(projectPath))) { return { success: false, error: "Project directory does not exist", }; } const contents = await this.listDirectoryContents(projectPath); return { success: true, content: JSON.stringify(contents), }; } // Handle file operations if (!(await this.validateProjectName(command.projectName))) { return { success: false, error: "Invalid project name. Must not contain '..' or '/'", }; } // Ensure project directory exists await this.ensureProjectDirectory(command.projectName); const fileCommand = command; const filePath = this.getFilePath(fileCommand.projectName, fileCommand.fileName); switch (fileCommand.operation) { case "read": { if (await fs.pathExists(filePath)) { const content = await fs.readFile(filePath, "utf-8"); return { success: true, content }; } return { success: false, error: "File does not exist", }; } case "write": { if (!command.content) { return { success: false, error: "Content is required for write operation", }; } if (await fs.pathExists(filePath)) { return { success: false, error: "File already exists. Use update operation to modify existing files.", }; } await fs.writeFile(filePath, command.content, "utf-8"); return { success: true }; } case "update": { if (!command.content) { return { success: false, error: "Content is required for update operation", }; } if (!(await fs.pathExists(filePath))) { return { success: false, error: "File does not exist. Use write operation to create new files.", }; } await fs.writeFile(filePath, command.content, "utf-8"); return { success: true }; } default: { const _exhaustiveCheck = fileCommand.operation; return { success: false, error: "Invalid operation", }; } } } catch (error) { return { success: false, error: `Operation failed: ${error instanceof Error ? error.message : "Unknown error"}`, }; } } }