Skip to main content
Glama
file-service.ts3.61 kB
import { promises as fs } from 'fs'; import path from 'path'; export class FileService { private notesDir: string; private allowedExtensions: string[] = ['.md', '.txt', '.json', '.yaml', '.yml']; constructor() { this.notesDir = process.env.NOTES_DIR || './notes'; } async readFile(filePath: string): Promise<string> { try { // Проверяем безопасность пути const safePath = this.sanitizePath(filePath); console.log(`📖 Чтение файла: ${safePath}`); const content = await fs.readFile(safePath, 'utf-8'); console.log(`✅ Файл прочитан: ${safePath} (${content.length} символов)`); return content; } catch (error) { console.error('Ошибка чтения файла:', error); throw new Error(`Ошибка чтения файла: ${error}`); } } async writeFile(filePath: string, content: string): Promise<void> { try { // Проверяем безопасность пути const safePath = this.sanitizePath(filePath); console.log(`✏️ Запись в файл: ${safePath}`); // Создаем директорию если её нет const dir = path.dirname(safePath); await fs.mkdir(dir, { recursive: true }); await fs.writeFile(safePath, content, 'utf-8'); console.log(`✅ Файл записан: ${safePath} (${content.length} символов)`); } catch (error) { console.error('Ошибка записи файла:', error); throw new Error(`Ошибка записи файла: ${error}`); } } async listFiles(dirPath: string = '.'): Promise<string[]> { try { const safePath = this.sanitizePath(dirPath); console.log(`📁 Список файлов в: ${safePath}`); const files = await fs.readdir(safePath, { withFileTypes: true }); const fileNames = files .filter(file => file.isFile() && this.isAllowedExtension(file.name)) .map(file => file.name); console.log(`✅ Найдено файлов: ${fileNames.length}`); return fileNames; } catch (error) { console.error('Ошибка получения списка файлов:', error); throw new Error(`Ошибка получения списка файлов: ${error}`); } } async fileExists(filePath: string): Promise<boolean> { try { const safePath = this.sanitizePath(filePath); await fs.access(safePath); return true; } catch { return false; } } private sanitizePath(filePath: string): string { // Убираем потенциально опасные символы const cleanPath = filePath.replace(/[<>:"|?*]/g, ''); // Разрешаем только относительные пути if (path.isAbsolute(cleanPath)) { throw new Error('Абсолютные пути не разрешены'); } // Разрешаем только файлы в notes директории const resolvedPath = path.resolve(this.notesDir, cleanPath); const notesDirResolved = path.resolve(this.notesDir); if (!resolvedPath.startsWith(notesDirResolved)) { throw new Error('Доступ к файлу вне notes директории запрещен'); } return resolvedPath; } private isAllowedExtension(fileName: string): boolean { const ext = path.extname(fileName).toLowerCase(); return this.allowedExtensions.includes(ext); } }

Implementation Reference

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/Galiusbro/MCP'

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