UNPKG

local-file-operation-mcp

Version:

本地文件操作 MCP 服务器:安全的读写、编辑、搜索、比较、哈希、权限、压缩、监控、命令与任务管理工具集。

144 lines (120 loc) 4.1 kB
/** * 文件压缩/解压工具模块 * 支持ZIP、TAR、GZ格式的压缩和解压 */ const fs = require('fs').promises; const path = require('path'); const { exec } = require('child_process'); const { promisify } = require('util'); const execAsync = promisify(exec); class FileArchiveTool { constructor(securityValidator) { this.securityValidator = securityValidator; } async handle(args) { const { operation, source, destination, format = 'zip' } = args; // 检查路径是否被允许 if (!this.securityValidator.isPathAllowed(source) || (destination && !this.securityValidator.isPathAllowed(destination))) { throw new Error('不允许操作指定路径的文件'); } // 验证格式 const supportedFormats = ['zip', 'tar', 'gz', 'tar.gz']; if (!supportedFormats.includes(format.toLowerCase())) { throw new Error(`不支持的压缩格式: ${format}。支持的格式: ${supportedFormats.join(', ')}`); } try { switch (operation) { case 'compress': return await this.compress(source, destination, format); case 'extract': return await this.extract(source, destination); default: throw new Error(`不支持的操作类型: ${operation}`); } } catch (error) { throw new Error(`压缩/解压操作失败: ${error.message}`); } } async compress(source, destination, format) { const sourcePath = path.resolve(source); const destPath = destination ? path.resolve(destination) : this.generateArchiveName(source, format); let command; switch (format.toLowerCase()) { case 'zip': command = `zip -r "${destPath}" "${sourcePath}"`; break; case 'tar': command = `tar -cf "${destPath}" "${sourcePath}"`; break; case 'gz': command = `gzip -c "${sourcePath}" > "${destPath}"`; break; case 'tar.gz': command = `tar -czf "${destPath}" "${sourcePath}"`; break; default: throw new Error(`不支持的压缩格式: ${format}`); } await execAsync(command); const stats = await fs.stat(destPath); return { content: [ { type: 'text', text: `压缩成功:\n源文件: ${sourcePath}\n压缩文件: ${destPath}\n格式: ${format.toUpperCase()}\n大小: ${stats.size} 字节` } ] }; } async extract(source, destination) { const sourcePath = path.resolve(source); const destPath = destination ? path.resolve(destination) : path.dirname(sourcePath); // 确保目标目录存在 await fs.mkdir(destPath, { recursive: true }); const ext = path.extname(sourcePath).toLowerCase(); let command; if (ext === '.zip') { command = `unzip "${sourcePath}" -d "${destPath}"`; } else if (ext === '.tar') { command = `tar -xf "${sourcePath}" -C "${destPath}"`; } else if (ext === '.gz') { command = `gunzip -c "${sourcePath}" > "${path.join(destPath, path.basename(sourcePath, '.gz'))}"`; } else if (sourcePath.endsWith('.tar.gz')) { command = `tar -xzf "${sourcePath}" -C "${destPath}"`; } else { throw new Error(`无法识别的压缩文件格式: ${ext}`); } await execAsync(command); return { content: [ { type: 'text', text: `解压成功:\n压缩文件: ${sourcePath}\n解压到: ${destPath}` } ] }; } generateArchiveName(source, format) { const sourcePath = path.resolve(source); const baseName = path.basename(sourcePath); const dirName = path.dirname(sourcePath); let extension; switch (format.toLowerCase()) { case 'zip': extension = '.zip'; break; case 'tar': extension = '.tar'; break; case 'gz': extension = '.gz'; break; case 'tar.gz': extension = '.tar.gz'; break; } return path.join(dirName, `${baseName}${extension}`); } } module.exports = FileArchiveTool;