compress
Compress files or directories into a ZIP archive with customizable options like encryption, password protection, and compression level.
Instructions
Compress local files or directories into a ZIP file
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input | Yes | ||
| options | No | ||
| output | Yes |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"input": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
]
},
"options": {
"additionalProperties": false,
"properties": {
"comment": {
"type": "string"
},
"encryptionStrength": {
"enum": [
1,
2,
3
],
"type": "number"
},
"level": {
"maximum": 9,
"minimum": 0,
"type": "number"
},
"overwrite": {
"type": "boolean"
},
"password": {
"type": "string"
}
},
"type": "object"
},
"output": {
"type": "string"
}
},
"required": [
"input",
"output"
],
"type": "object"
}
Implementation Reference
- src/index.ts:83-166 (handler)The main handler function for the 'compress' tool. It processes input file(s)/directory(ies), reads their contents, prepares data for compression, calls the compressData helper, writes the resulting ZIP to the output path, and returns success/error messages.execute: async (args) => { try { const outputPath = args.output; // Separate CompressionOptions and other options const { overwrite, ...compressionOptions } = args.options || {}; const shouldOverwrite = overwrite ?? false; // Check if output path already exists if ((await exists(outputPath)) && !shouldOverwrite) { throw new Error( `Output file ${outputPath} already exists. Set overwrite: true to overwrite.` ); } // Create output directory (if it doesn't exist) const outputDir = path.dirname(outputPath); if (!(await exists(outputDir))) { await fs.mkdir(outputDir, { recursive: true }); } // Prepare input files const inputPaths = Array.isArray(args.input) ? args.input : [args.input]; const filesToCompress: { name: string; data: Uint8Array }[] = []; // Process each input path for (const inputPath of inputPaths) { if (!(await exists(inputPath))) { throw new Error(`Input path not found: ${inputPath}`); } const stats = await fs.stat(inputPath); if (stats.isDirectory()) { // Process directory const baseDir = path.basename(inputPath); const files = await getAllFiles(inputPath); for (const relPath of files) { const fullPath = path.join(inputPath, relPath); const data = await fs.readFile(fullPath); // Maintain relative path structure filesToCompress.push({ name: path.join(baseDir, relPath), data: new Uint8Array(data), }); } } else { // Process single file const data = await fs.readFile(inputPath); filesToCompress.push({ name: path.basename(inputPath), data: new Uint8Array(data), }); } } if(compressionOptions?.level && compressionOptions.level > 9) { compressionOptions.level = 9; } if(compressionOptions?.level && compressionOptions.level < 0) { compressionOptions.level = 0; } // Execute compression const result = await compressData(filesToCompress, compressionOptions); // Write result to file await fs.writeFile(outputPath, result); return { content: [ { type: "text", text: `Compression completed. Created ${outputPath} file containing ${filesToCompress.length} files.`, }, ], }; } catch (error) { return { content: [{ type: "text", text: `Compression failed: ${formatError(error)}` }], }; } },
- src/index.ts:67-82 (schema)Zod schema defining the parameters for the compress tool: input (file/dir path or array), output ZIP path, and options (compression level, password, etc.).parameters: z.object({ input: z.union([ z.string(), // Single file or directory path z.array(z.string()), // Multiple file or directory paths ]), output: z.string(), // Output ZIP file path options: z .object({ level: z.number().min(0).max(9).optional(), comment: z.string().optional(), password: z.string().optional(), encryptionStrength: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(), overwrite: z.boolean().optional(), }) .optional(), }),
- src/index.ts:64-167 (registration)The server.addTool call that registers the 'compress' tool with name, description, parameters schema, and execute handler.server.addTool({ name: "compress", description: "Compress local files or directories into a ZIP file", parameters: z.object({ input: z.union([ z.string(), // Single file or directory path z.array(z.string()), // Multiple file or directory paths ]), output: z.string(), // Output ZIP file path options: z .object({ level: z.number().min(0).max(9).optional(), comment: z.string().optional(), password: z.string().optional(), encryptionStrength: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(), overwrite: z.boolean().optional(), }) .optional(), }), execute: async (args) => { try { const outputPath = args.output; // Separate CompressionOptions and other options const { overwrite, ...compressionOptions } = args.options || {}; const shouldOverwrite = overwrite ?? false; // Check if output path already exists if ((await exists(outputPath)) && !shouldOverwrite) { throw new Error( `Output file ${outputPath} already exists. Set overwrite: true to overwrite.` ); } // Create output directory (if it doesn't exist) const outputDir = path.dirname(outputPath); if (!(await exists(outputDir))) { await fs.mkdir(outputDir, { recursive: true }); } // Prepare input files const inputPaths = Array.isArray(args.input) ? args.input : [args.input]; const filesToCompress: { name: string; data: Uint8Array }[] = []; // Process each input path for (const inputPath of inputPaths) { if (!(await exists(inputPath))) { throw new Error(`Input path not found: ${inputPath}`); } const stats = await fs.stat(inputPath); if (stats.isDirectory()) { // Process directory const baseDir = path.basename(inputPath); const files = await getAllFiles(inputPath); for (const relPath of files) { const fullPath = path.join(inputPath, relPath); const data = await fs.readFile(fullPath); // Maintain relative path structure filesToCompress.push({ name: path.join(baseDir, relPath), data: new Uint8Array(data), }); } } else { // Process single file const data = await fs.readFile(inputPath); filesToCompress.push({ name: path.basename(inputPath), data: new Uint8Array(data), }); } } if(compressionOptions?.level && compressionOptions.level > 9) { compressionOptions.level = 9; } if(compressionOptions?.level && compressionOptions.level < 0) { compressionOptions.level = 0; } // Execute compression const result = await compressData(filesToCompress, compressionOptions); // Write result to file await fs.writeFile(outputPath, result); return { content: [ { type: "text", text: `Compression completed. Created ${outputPath} file containing ${filesToCompress.length} files.`, }, ], }; } catch (error) { return { content: [{ type: "text", text: `Compression failed: ${formatError(error)}` }], }; } }, });
- src/utils/compression.ts:32-85 (helper)The core compression helper function used by the compress tool handler. Uses @zip.js/zip.js to create ZIP files from file data arrays.export async function compressData( data: Uint8Array | Blob | string | { name: string, data: Uint8Array | Blob | string }[], options: CompressionOptions = {} ): Promise<Uint8Array> { const zipWriter = new zip.ZipWriter(new zip.Uint8ArrayWriter(), { level: options.level || 5, password: options.password, encryptionStrength: options.encryptionStrength }); try { if (Array.isArray(data)) { // Handle multiple file compression for (const item of data) { let fileData: Uint8Array | Blob | string = item.data; // Convert string to Uint8Array if (typeof fileData === 'string') { const encoder = new TextEncoder(); fileData = encoder.encode(fileData); } await zipWriter.add(item.name, typeof fileData === 'string' ? new zip.TextReader(fileData) : fileData instanceof Blob ? new zip.BlobReader(fileData) : new zip.Uint8ArrayReader(fileData) ); } } else { // Handle single file compression let fileData = data; // Convert string to Uint8Array if (typeof fileData === 'string') { const encoder = new TextEncoder(); fileData = encoder.encode(fileData); } await zipWriter.add('file', typeof fileData === 'string' ? new zip.TextReader(fileData) : fileData instanceof Blob ? new zip.BlobReader(fileData) : new zip.Uint8ArrayReader(fileData) ); } return await zipWriter.close(); } catch (error: any) { throw new Error(`Compression failed: ${error.message}`); } }
- src/utils/compression.ts:3-7 (schema)Type definition for CompressionOptions used in compressData and tool options.export interface CompressionOptions { level?: number; // Compression level (0-9) password?: string; // Password protection encryptionStrength?: 1 | 2 | 3; // Encryption strength (1-3) }