getZipInfo
Extract metadata from local ZIP files, including details on contents and structure, with optional password support for secure archives.
Instructions
Get metadata information of a local ZIP file
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input | Yes | ||
| options | No |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"input": {
"type": "string"
},
"options": {
"additionalProperties": false,
"properties": {
"password": {
"type": "string"
}
},
"type": "object"
}
},
"required": [
"input"
],
"type": "object"
}
Implementation Reference
- src/index.ts:270-342 (handler)The execute handler for the getZipInfo tool. It reads the local ZIP file, calls the getZipInfo utility, computes compression ratio, formats the metadata into a readable text response, and returns it as MCP content.execute: async (args) => { try { const inputPath = args.input; const options: DecompressionOptions = args.options || {}; // Check if input file exists if (!(await exists(inputPath))) { throw new Error(`Input file not found: ${inputPath}`); } // Read ZIP file const zipData = await fs.readFile(inputPath); // Get ZIP information const metadata = await getZipInfo(new Uint8Array(zipData), options); const compressionRatio = metadata.totalSize > 0 ? ( (1 - metadata.totalCompressedSize / metadata.totalSize) * 100 ).toFixed(2) + "%" : "0%"; // File size formatting const formatSize = (size: number): string => { if (size < 1024) return `${size} B`; if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`; if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`; return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`; }; // Build file information text const filesInfo = metadata.files .map( (file: ZipInfo) => `- ${file.filename}: Original size=${formatSize( file.size )}, Compressed=${formatSize(file.compressedSize)}, Modified date=${new Date( file.lastModDate ).toLocaleString()}, Encrypted=${file.encrypted ? "Yes" : "No"}` ) .join("\n"); return { content: [ { type: "text", text: `ZIP file "${path.basename(inputPath)}" information overview:`, }, { type: "text", text: `Total files: ${metadata.files.length}` }, { type: "text", text: `Total size: ${formatSize(metadata.totalSize)}` }, { type: "text", text: `Compressed size: ${formatSize(metadata.totalCompressedSize)}`, }, { type: "text", text: `Compression ratio: ${compressionRatio}` }, { type: "text", text: metadata.comment ? `Comment: ${metadata.comment}` : "", }, { type: "text", text: `\nFile details:\n${filesInfo}` }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get ZIP information: ${formatError(error)}` }, ], }; } },
- src/index.ts:259-343 (registration)Registers the getZipInfo tool with the FastMCP server, specifying name, description, input schema, and the execute handler.server.addTool({ name: "getZipInfo", description: "Get metadata information of a local ZIP file", parameters: z.object({ input: z.string(), // ZIP file path options: z .object({ password: z.string().optional(), }) .optional(), }), execute: async (args) => { try { const inputPath = args.input; const options: DecompressionOptions = args.options || {}; // Check if input file exists if (!(await exists(inputPath))) { throw new Error(`Input file not found: ${inputPath}`); } // Read ZIP file const zipData = await fs.readFile(inputPath); // Get ZIP information const metadata = await getZipInfo(new Uint8Array(zipData), options); const compressionRatio = metadata.totalSize > 0 ? ( (1 - metadata.totalCompressedSize / metadata.totalSize) * 100 ).toFixed(2) + "%" : "0%"; // File size formatting const formatSize = (size: number): string => { if (size < 1024) return `${size} B`; if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`; if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`; return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`; }; // Build file information text const filesInfo = metadata.files .map( (file: ZipInfo) => `- ${file.filename}: Original size=${formatSize( file.size )}, Compressed=${formatSize(file.compressedSize)}, Modified date=${new Date( file.lastModDate ).toLocaleString()}, Encrypted=${file.encrypted ? "Yes" : "No"}` ) .join("\n"); return { content: [ { type: "text", text: `ZIP file "${path.basename(inputPath)}" information overview:`, }, { type: "text", text: `Total files: ${metadata.files.length}` }, { type: "text", text: `Total size: ${formatSize(metadata.totalSize)}` }, { type: "text", text: `Compressed size: ${formatSize(metadata.totalCompressedSize)}`, }, { type: "text", text: `Compression ratio: ${compressionRatio}` }, { type: "text", text: metadata.comment ? `Comment: ${metadata.comment}` : "", }, { type: "text", text: `\nFile details:\n${filesInfo}` }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get ZIP information: ${formatError(error)}` }, ], }; } }, });
- src/index.ts:262-269 (schema)Zod schema defining the input parameters for the getZipInfo tool: input (ZIP file path) and optional options (password).parameters: z.object({ input: z.string(), // ZIP file path options: z .object({ password: z.string().optional(), }) .optional(), }),
- src/utils/compression.ts:122-163 (helper)Core utility function that parses ZIP data using @zip.js/zip.js, extracts file metadata (size, compressed size, dates, encryption status), aggregates totals, and returns structured ZipMetadata.export async function getZipInfo( data: Uint8Array | Blob, options: DecompressionOptions = {} ): Promise<ZipMetadata> { try { const reader = data instanceof Blob ? new zip.BlobReader(data) : new zip.Uint8ArrayReader(data); const zipReader = new zip.ZipReader(reader, { password: options.password }); const entries = await zipReader.getEntries(); const files: ZipInfo[] = []; let totalSize = 0; let totalCompressedSize = 0; for (const entry of entries) { if (!entry.directory) { files.push({ filename: entry.filename, size: entry.uncompressedSize, compressedSize: entry.compressedSize, lastModDate: new Date(entry.lastModDate), encrypted: entry.encrypted, comment: entry.comment }); totalSize += entry.uncompressedSize; totalCompressedSize += entry.compressedSize; } } const metadata: ZipMetadata = { files, totalSize, totalCompressedSize, comment: zipReader.comment ? new TextDecoder().decode(zipReader.comment) : undefined }; await zipReader.close(); return metadata; } catch (error: any) { throw new Error(`Failed to get zip file information: ${error.message}`); } }
- src/utils/compression.ts:22-27 (schema)TypeScript interface defining the structure of ZIP metadata returned by getZipInfo, including file list, totals, and optional comment.export interface ZipMetadata { files: ZipInfo[]; totalSize: number; totalCompressedSize: number; comment?: string; }