Skip to main content
Glama
extract-archive.ts5.57 kB
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import fs from 'fs-extra'; import * as path from 'path'; import extractZip from 'extract-zip'; import * as tar from 'tar'; /** * Tool: Extract Archive * Registers the tool with the MCP server * @param server MCP server instance */ const registerTool = (server: McpServer) => { server.registerTool( 'extract-archive', { title: 'Extract Archive', description: 'Extracts a ZIP, TAR, or TAR.GZ file to a specified directory. Parameters: archivePath - Path to the archive file (required); extractTo - Target directory for extraction (required); overwrite - Whether to overwrite existing files (optional, default is false)', inputSchema: { archivePath: z.string(), extractTo: z.string(), overwrite: z.boolean().optional() } }, async ({ archivePath, extractTo, overwrite = false }) => { try { // Check if the archive file exists if (!(await fs.pathExists(archivePath))) { return { content: [ { type: 'text', text: `Error: Archive file ${archivePath} does not exist` } ], isError: true }; } // Check the file format const fileExtension = path.extname(archivePath).toLowerCase(); const supportedFormats = ['.zip', '.tar', '.gz', '.tgz']; // Special handling for .tar.gz const fileName = path.basename(archivePath).toLowerCase(); const isTarGz = fileName.endsWith('.tar.gz') || fileName.endsWith('.tgz'); if ( !supportedFormats.some((ext) => archivePath.toLowerCase().endsWith(ext) ) && !isTarGz ) { return { content: [ { type: 'text', text: `Error: Unsupported archive format. Supported formats: ZIP, TAR, TAR.GZ, TGZ` } ], isError: true }; } // Ensure the extraction directory exists await fs.ensureDir(extractTo); // Check if the target directory is empty (if not overwriting) if (!overwrite) { const existingFiles = await fs.readdir(extractTo); if (existingFiles.length > 0) { return { content: [ { type: 'text', text: `Error: Target directory ${extractTo} is not empty. Set overwrite=true to overwrite existing files.` } ], isError: true }; } } let extractedFiles: string[] = []; let format = ''; // Choose extraction method based on file format if (fileExtension === '.zip') { format = 'ZIP'; extractedFiles = await extractZipFile(archivePath, extractTo); } else if ( isTarGz || fileExtension === '.gz' || fileExtension === '.tgz' ) { format = 'TAR.GZ'; extractedFiles = await extractTarFile(archivePath, extractTo, true); } else if (fileExtension === '.tar') { format = 'TAR'; extractedFiles = await extractTarFile(archivePath, extractTo, false); } // Calculate the total size of the extracted files let totalSize = 0; for (const file of extractedFiles) { try { const stats = await fs.stat(file); if (stats.isFile()) { totalSize += stats.size; } } catch { // Ignore stat errors } } return { content: [ { type: 'text', text: `Extraction complete!\nArchive file: ${archivePath}\nFormat: ${format}\nExtracted to: ${extractTo}\nNumber of files extracted: ${extractedFiles.length}\nTotal size: ${Math.round(totalSize / 1024)}KB` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error extracting archive: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } } ); }; /** * Extracts a ZIP file. */ async function extractZipFile( archivePath: string, extractTo: string ): Promise<string[]> { await extractZip(archivePath, { dir: path.resolve(extractTo) }); // Recursively get all extracted files const getAllFiles = async (dirPath: string): Promise<string[]> => { const files: string[] = []; const items = await fs.readdir(dirPath); for (const item of items) { const itemPath = path.join(dirPath, item); const stats = await fs.stat(itemPath); if (stats.isDirectory()) { files.push(...(await getAllFiles(itemPath))); } else { files.push(itemPath); } } return files; }; return await getAllFiles(extractTo); } /** * Extracts a TAR file. */ async function extractTarFile( archivePath: string, extractTo: string, gzip: boolean ): Promise<string[]> { const extractedFiles: string[] = []; await tar.extract({ file: archivePath, cwd: extractTo, gzip: gzip, onentry: (entry: any) => { if (entry.type === 'File') { extractedFiles.push(path.join(extractTo, entry.path)); } } } as any); return extractedFiles; } export default registerTool;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Yussefgafer/MyMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server