Skip to main content
Glama
N3uraX

Tafa MCP Server

by N3uraX
directoryOperations.jsโ€ข6.13 kB
import fs from "fs-extra"; import path from "path"; import { createHash } from "crypto"; export class DirectoryOperations { constructor(securityManager) { this.security = securityManager; } async createDirectory(dirPath) { try { const validPath = this.security.validatePath(dirPath); await fs.ensureDir(validPath); return { content: [{ type: "text", text: `โœ… Directory created successfully: ${path.basename(validPath)}` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error creating directory: ${error.message}` }] }; } } async listDirectory(dirPath, recursive = false, showHidden = false) { try { const validPath = this.security.validatePath(dirPath); await this.security.checkPermissions(validPath, 'read'); const items = await this.getDirectoryContents(validPath, recursive, showHidden); const output = this.formatDirectoryListing(items, validPath); return { content: [{ type: "text", text: output }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error listing directory: ${error.message}` }] }; } } async getDirectoryContents(dirPath, recursive = false, showHidden = false) { const items = []; const entries = await fs.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { if (!showHidden && entry.name.startsWith('.')) { continue; } const fullPath = path.join(dirPath, entry.name); const stats = await fs.stat(fullPath); const item = { name: entry.name, path: fullPath, type: entry.isDirectory() ? 'directory' : 'file', size: stats.size, sizeHuman: this.formatFileSize(stats.size), modified: stats.mtime, permissions: stats.mode }; items.push(item); if (recursive && entry.isDirectory()) { try { const subItems = await this.getDirectoryContents(fullPath, recursive, showHidden); items.push(...subItems); } catch (error) { // Skip directories we can't read items.push({ name: `${entry.name}/ (access denied)`, path: fullPath, type: 'directory', size: 0, sizeHuman: 'N/A', modified: stats.mtime, permissions: stats.mode, error: error.message }); } } } return items; } formatDirectoryListing(items, basePath) { const files = items.filter(item => item.type === 'file'); const directories = items.filter(item => item.type === 'directory'); let output = `๐Ÿ“ Directory: ${basePath}\n`; output += `๐Ÿ“Š Summary: ${directories.length} directories, ${files.length} files\n\n`; // Sort items const sortedItems = [...directories, ...files].sort((a, b) => a.name.localeCompare(b.name)); for (const item of sortedItems) { const icon = item.type === 'directory' ? '๐Ÿ“' : '๐Ÿ“„'; const relativePath = path.relative(basePath, item.path); const indent = ' '.repeat((relativePath.split(path.sep).length - 1)); output += `${indent}${icon} ${item.name}`; if (item.type === 'file') { output += ` (${item.sizeHuman})`; } if (item.error) { output += ` โŒ ${item.error}`; } output += '\n'; } return output; } async deleteDirectory(dirPath, backup = true) { try { const validPath = this.security.validatePath(dirPath); await this.security.checkPermissions(validPath, 'delete'); let backupPath = null; if (backup) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const backupName = `${path.basename(validPath)}_${timestamp}`; backupPath = path.join(this.security.backupDir, backupName); await fs.copy(validPath, backupPath); } await fs.remove(validPath); const message = `โœ… Directory deleted successfully: ${path.basename(validPath)}`; return { content: [{ type: "text", text: backupPath ? `${message}\n๐Ÿ’พ Backup created: ${backupPath}` : message }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error deleting directory: ${error.message}` }] }; } } async getDirectoryInfo(dirPath) { try { const validPath = this.security.validatePath(dirPath); await this.security.checkPermissions(validPath, 'read'); const stats = await fs.stat(validPath); const contents = await this.getDirectoryContents(validPath, true, false); const files = contents.filter(item => item.type === 'file'); const directories = contents.filter(item => item.type === 'directory'); const totalSize = files.reduce((sum, file) => sum + file.size, 0); const dirInfo = { path: validPath, name: path.basename(validPath), created: stats.birthtime, modified: stats.mtime, accessed: stats.atime, permissions: stats.mode, totalFiles: files.length, totalDirectories: directories.length, totalSize: totalSize, totalSizeHuman: this.formatFileSize(totalSize) }; return { content: [{ type: "text", text: `๐Ÿ“Š Directory Information:\n${JSON.stringify(dirInfo, null, 2)}` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error getting directory info: ${error.message}` }] }; } } formatFileSize(bytes) { const sizes = ['Bytes', 'KB', 'MB', 'GB']; if (bytes === 0) return '0 Bytes'; const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i]; } }

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/N3uraX/tafa-mcp'

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